From: Ian Jackson (iwj@cam-orl.co.uk)
Newsgroups: comp.os.linux
Subject: Re: clearing SUID bit on writes
Summary: Mandatory record locking needs the sgid bit to stay
Keywords: sgid, locking
Date: 2 Sep 92 10:03:40 GMT
Organization: Olivetti Research Ltd

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
Newsgroups: comp.os.linux