SETUID(7)                                               SETUID(7)

       setuid - checklist for security of setuid programs

       Writing  a  secure  setuid  (or setgid) program is tricky.
       There are a number of possible ways of subverting  such  a
       program.  The most conspicuous security holes occur when a
       setuid program is not sufficiently careful to avoid giving
       away  access  to resources it legitimately has the use of.
       Most of the other attacks are basically a matter of alter-
       ing  the program's environment in unexpected ways and hop-
       ing it will fail in some security-breaching manner.  There
       are  generally  three  categories of environment manipula-
       tion: supplying a legal but  unexpected  environment  that
       may  cause  the program to directly do something insecure,
       arranging for error conditions that the  program  may  not
       handle  correctly, and the specialized subcategory of giv-
       ing the program inadequate  resources  in  hopes  that  it
       won't respond properly.

       The  following are general considerations of security when
       writing a setuid program.

       [] The program should run with the weakest  userid  possi-
          ble,  preferably  one  used only by itself.  A security
          hole in a setuid program running with  a  highly-privi-
          leged  userid  can  compromise an entire system.  Secu-
          rity-critical programs  like  passwd(1) should  always
          have  private userids, to minimize possible damage from
          penetrations elsewhere.

       [] The result of getlogin or ttyname may be wrong  if  the
          descriptors  have been meddled with.  There is no fool-
          proof way to determine the controlling terminal or  the
          login name (as opposed to uid) on V7.

       [] On  some  systems (not ours), the setuid bit may not be
          honored if the program is run by root, so  the  program
          may find itself running as root.

       [] Programs that attempt to use creat for locking can foul
          up when run by root; use  of  link  is  preferred  when
          implementing  locking.   Using  chmod for locking is an
          obvious disaster.

       [] Breaking an existing lock is very dangerous; the break-
          down  of  a  locking protocol may be symptomatic of far
          worse problems.  Doing so on  the  basis  of  the  lock
          being  `old'  is  sometimes necessary, but programs can
          run for surprising lengths of  time  on  heavily-loaded

       [] Care  must  be  taken  that  user  requests for i/o are
          checked for permissions using the  user's  permissions,

                              local                             1

SETUID(7)                                               SETUID(7)

          not the program's.  Use of access is recommended.

       [] Programs  executed at user request (e.g. shell escapes)
          must not receive the setuid program's permissions;  use
          of  daughter  processes  and setuid(getuid()) plus set-
          gid(getgid()) after fork but before exec is vital.

       [] Similarly, programs executed at user request  must  not
          receive   other   sensitive   resources,  notably  file
          descriptors.   Use  of  closeall(3) or close-on-exec
          arrangements,  on  systems  which  have them, is recom-

       [] Programs activated by one user but handling traffic  on
          behalf  of  others  (e.g.  daemons)  should avoid doing
          setuid(getuid()) or setgid(getgid()), since the  origi-
          nal  invoker's identity is almost certainly inappropri-
          ate.    On   systems   which   permit   it,   use    of
          setuid(geteuid())  and setgid(getegid()) is recommended
          when performing work on behalf of the system as opposed
          to a specific user.

       [] There  are  inherent  permission problems when a setuid
          program executes another setuid program, since the per-
          missions  are  not additive.  Care should be taken that
          created files are not owned by the wrong  person.   Use
          of  setuid(geteuid()) and its gid counterpart can help,
          if the system allows them.

       [] Care should be taken that newly-created  files  do  not
          have  the  wrong permission or ownership even momentar-
          ily.  Permissions should be arranged by using umask  in
          advance, rather than by creating the file wide-open and
          then using chmod.  Ownership can get sticky due to  the
          limitations  of  the  setuid  concept, although using a
          daughter process connected by a pipe can help.

       [] Setuid programs  should  be  especially  careful  about
          error  checking,  and  the normal response to a strange
          situation should be termination, rather than an attempt
          to carry on.

       [] The  following  are  ways  in  which the program may be
          induced to carelessly give away its special privileges.

       [] The directory the program is started in, or directories
          it may plausibly chdir to, may  contain  programs  with
          the  same  names  as  system  programs, placed there in
          hopes that the program will activate  a  shell  with  a
          permissive  PATH  setting.  PATH should always be stan-
          dardized before invoking a shell  (either  directly  or
          via popen or execvp/execlp).

       [] Similarly,   a   bizarre  IFS  setting  may  alter  the

                              local                             2

SETUID(7)                                               SETUID(7)

          interpretation of a shell  command  in  really  strange
          ways,  possibly  causing  a user-supplied program to be
          invoked.  IFS too should always be standardized  before
          invoking a shell.  (Our shell does this automatically.)

       [] Environment variables in  general  cannot  be  trusted.
          Their contents should never be taken for granted.

       [] Setuid  shell  files  (on systems which implement such)
          simply cannot cope adequately with some of these  prob-
          lems.   They  also have some nasty problems like trying
          to run a .profile when run under a suitable name.  They
          are terminally insecure, and must be avoided.

       [] Relying  on the contents of files placed in publically-
          writeable directories, such as /tmp, is a nearly-incur-
          able  security  problem.   Setuid programs should avoid
          using /tmp entirely, if humanly possible.  The  sticky-
          directories modification (sticky bit on for a directory
          means only owner of a file can remove it) (we have this
          feature) helps, but is not a complete solution.

       [] A  related  problem  is that spool directories, holding
          information that the program  will  trust  later,  must
          never  be publically writeable even if the files in the
          directory are protected.  Among other sinister  manipu-
          lations that can be performed, note that on many Unixes
          (not ours), a core dump of a setuid program is owned by
          the program's owner and not by the user running it.

       [] The following are unusual but possible error conditions
          that the program should cope with  properly  (resource-
          exhaustion  questions  are  considered  separately, see

       [] The value of argc might be 0.

       [] The setting of the umask might not be sensible.  In any
          case, it should be standardized when creating files not
          intended to be owned by the user.

       [] One or  more  of  the  standard  descriptors  might  be
          closed, so that an opened file might get (say) descrip-
          tor 1, causing chaos if  the  program  tries  to  do  a

       [] The  current  directory  (or any of its parents) may be
          unreadable and unsearchable.  On  many  systems pwd(1)
          does  not  run  setuid-root,  so it can fail under such

       [] Descriptors shared by other processes (i.e.,  any  that
          are open on startup) may be manipulated in strange ways
          by said processes.

                              local                             3

SETUID(7)                                               SETUID(7)

       [] The standard descriptors may refer to a terminal  which
          has  a  bizarre mode setting, or which cannot be opened
          again, or which gives end-of-file on any read  attempt,
          or which cannot be read or written successfully.

       [] The  process  may be hit by interrupt, quit, hangup, or
          broken-pipe signals, singly or in fast succession.  The
          user  may  deliberately  exploit  the  race  conditions
          inherent in catching signals; ignoring signals is safe,
          but catching them is not.

       [] Although  non-keyboard  signals cannot be sent by ordi-
          nary users in V7, they may perhaps be sent by the  sys-
          tem  authorities  (e.g.  to indicate that the system is
          about to shut  down),  so  the  possibility  cannot  be

       [] On some systems (not ours) there may be an alarm signal
          pending on startup.

       [] The program may have children it did not create.   This
          is normal when the process is part of a pipeline.

       [] In some non-V7 systems, users can change the ownerships
          of their files.  Setuid programs should avoid  trusting
          the owner identification of a file.

       [] User-supplied  arguments and input data must be checked
          meticulously.  Overly-long input  stored  in  an  array
          without  proper  bound checking can easily breach secu-
          rity.  When software depends on a file being in a  spe-
          cific   format,  user-supplied  data  should  never  be
          inserted into the file  without  being  checked  first.
          Meticulous checking includes allowing for the possibil-
          ity of non-ASCII characters.

       [] Temporary files left in public  directories  like  /tmp
          might vanish at inconvenient times.

       [] The  following  are  resource-exhaustion  possibilities
          that the program should respond properly to.

       [] The user might have used up all  of  his  allowed  pro-
          cesses, so any attempt to create a new one (via fork or
          popen) will fail.

       [] There might be many files open, exhausting  the  supply
          of  descriptors.  Running closeall(3), on systems which
          have it, is recommended.

       [] There might be many arguments.

       [] The arguments and the environment together might occupy
          a great deal of space.

                              local                             4

SETUID(7)                                               SETUID(7)

       [] Systems  which  impose  other  resource limitations can
          open setuid  programs  to  similar  resource-exhaustion

       [] Setuid programs which execute ordinary programs without
          reducing authority pass all the above  problems  on  to
          such  unprepared children.  Standardizing the execution
          environment is only a partial solution.

       closeall(3) standard(3)

       Locally written, although based on outside  contributions.

       The  list  really  is  rather long...  and probably incom-

       [] Neither  the  author  nor  the  University  of  Toronto
          accepts any responsibility whatever for the use or non-
          use of this information.

                              local                             5