From: iwj@cam-orl.co.uk ((iwj@cam-orl.co.uk))
Date: 09/02/92


From: Ian Jackson (iwj@cam-orl.co.uk)
Subject: Re: clearing SUID bit on writes
Date: 2 Sep 1992 10:03:40 GMT

In article <1992Sep1.170221.17317@athena.mit.edu>
           tytso@ATHENA.MIT.EDU (Theodore Ts'o) writes:
>When System V does is whenever you write to a setuid file (not just when
>you append to it), it clears the setuid and setgid bits. This prevents
>a security hole if you have a setuid program which is group or world
>writeable. I don't think anything would break if we added this behavior
>to Linux. On the other hand, there's a much simpler way of avoiding the
>security hole, which is to simply don't create group or world writeable
>setuid files.

Careful! I don't know if you want to support mandatory record locking,
but if you do you need to keep the sgid bit set on writes if all the
execute bits are clear. I don't know anybody who's ever used mandatory
locking, so this may be a red herring, but it's worth thinking about.

I'll enclose some manpage extracts for lockf(3), stat(2) & write(2)
(SunOS 4.1.2). They are a little unclear, but I tried it (small
transcript also enclosed) and it only clears the sgid bit if one of
the execute bits is set.

==========

LOCKF(3) C LIBRARY FUNCTIONS LOCKF(3)

NAME
     lockf - record locking on files

SYNOPSIS
     #include <unistd.h>

     int lockf(fd, cmd, size)
     int fd, cmd;
     long size;

DESCRIPTION
     lockf() places, removes, and tests for exclusive locks on
     sections of files. These locks are either advisory or man-
     datory depending on the mode bits of the file. The lock is
     mandatory if the set-GID bit (S_ISGID) is set and the group
     execute bit (S_IXGRP) is clear (see stat(2V) for information
     about mode bits). Otherwise, the lock is advisory.

     If a process holds a mandatory exclusive lock on a segment
     of a file, both read and write operations block until the
     lock is removed (see WARNINGS).

     An advisory lock does not affect read and write access to
     the locked segment. Advisory locks may be used by cooperat-
     ing processes checking for locks using F_GETLCK and volun-
     tarily observing the indicated read and write restrictions.

     [ ... ]

WARNINGS
     Mandatory record locks are dangerous. If a runaway or oth-
     erwise out-of-control process should hold a mandatory lock
     on a file critical to the system and fail to release that
     lock, the entire system could hang or crash. For this rea-
     son, mandatory record locks may be removed in a future SunOS
     release.n Use advisory record locking whenever possible.

     [ ... ]

BUGS
     lockf() locks do not interact in any way with locks granted
     by flock(), but are compatible with locks granted by
     fcntl().

Sun Release 4.1 Last change: 21 January 1990

==========

WRITE(2V) SYSTEM CALLS WRITE(2V)

NAME
     write, writev - write output

SYNOPSIS
     [ ... ]

DESCRIPTION
     [ ... ]
     If the real user is not the super-user, then write() clears
     the set-user-id bit on a file. This prevents penetration of
     system security by a user who "captures" a writable set-
     user-id file owned by the super-user.

[ ... - there is no mention of the set-group-id bit - iwj ]
Sun Release 4.1 Last change: 21 January 1990

==========

STAT(2V) SYSTEM CALLS STAT(2V)

NAME
     stat, lstat, fstat - get file status

SYNOPSIS
     [ ... ]

DESCRIPTION
     [ ... - including stat structure layout - ... ]

     The status information word st_mode is bit-encoded using the
     following masks and bits:

     S_ISUID Set user ID on execution. The process's
                    effective user ID is set to that of the owner
                    of the file when the file is run as a program
                    (see execve(2V)). On a regular file, this
                    bit should be cleared on any write.

     S_ISGID Set group ID on execution. The process's
                    effective group ID is set to that of the file
                    when the file is run as a program (see
                    execve(2V)). On a regular file, this bit
                    should be cleared on any write.

Sun Release 4.1 Last change: 21 January 1990

==========

Script started on Wed Sep 2 10:55:32 1992
$ rm -f foo; touch foo
$ chmod 2666 foo; ls -lg foo
-rw-rwSrw- 1 iwj other 0 Sep 2 10:55 foo
$ echo >>foo; ls -lg foo
-rw-rwSrw- 1 iwj other 1 Sep 2 10:55 foo
$ chmod 2766 foo; ls -lg foo
-rwxrwSrw- 1 iwj other 1 Sep 2 10:55 foo
$ echo >>foo; ls -lg foo
-rwxrw-rw- 1 iwj other 2 Sep 2 10:55 foo
$ chmod 2676 foo; ls -lg foo
-rw-rwsrw- 1 iwj other 2 Sep 2 10:55 foo
You have mail in /usr/spool/mail/iwj
$ echo >>foo; ls -lg foo
-rw-rwxrw- 1 iwj other 3 Sep 2 10:56 foo
$ rm foo
$ exit
Script done on Wed Sep 2 10:56:48 1992

-- 
Ian Jackson                             The opinions expressed here are my own.
              iwj@cam-orl.co.uk / ...!mcsun!uknet!cam-orl!iwj