develooper Front page | perl.perl5.porters | Postings from February 2011

Re: setuid and serious trouble (Re: Time to update POSIX.pm?)

Thread Previous | Thread Next
From:
Tom Christiansen
Date:
February 3, 2011 05:57
Subject:
Re: setuid and serious trouble (Re: Time to update POSIX.pm?)
Message ID:
18507.1296741400@chthon
> I hope you will comment on the bigger story as well.

Very well.

I haven't looked into the matter in detail.  I do know that there
may now be something of a mismatch between traditional setxid
semantics of two different id sets wherein setting the real id
was a one-way trip, and current prevailing semantics where you
have three different id sets and can get back the saved id even
having set both real and effective ids.  That doesn't map so well 
to Perl's two-id system unless you clump them.

I'm concerned that platform variations may preclude ever managing
these things in a uniform manner.  Consider that all these hints
files mention /set[re]*[ug]id/:

 aix.sh        darwin.sh     freebsd.sh    openbsd.sh    svr5.sh
 aix_3.sh      dcosx.sh      linux.sh      qnx.sh        unicos.sh
 aix_4.sh      dgux.sh       mpeix.sh      solaris_2.sh  unicosmk.sh
 bsdos.sh      epix.sh       netbsd.sh     svr4.sh       vmesa.sh

For example, from the very top of openbsd.sh:

    # In OpenBSD < 3.3, the setre?[ug]id() are emulated using the
    # _POSIX_SAVED_IDS functionality which does not have the same
    # semantics as 4.3BSD.  Starting with OpenBSD 3.3, the original
    # semantics have been restored.
    case "$osvers" in
    [0-2].*|3.[0-2])
	    d_setregid=$undef
	    d_setreuid=$undef
	    d_setrgid=$undef
	    d_setruid=$undef
    esac

Looking at manpages on a couple of BSD systems (OpenBsd and Darwin),
Solaris, and Linux, it begins to look like there may be some convergence 
at least amongst those three/four.  I include the three relevant manpage
sections from those respective systems below by signature.

So it may be that we can do something reasonable.  I'd very much
like to keep as uniform an interface into the id sets as we can,
because setxid is too important a matter to be left up to
platform variation if there's any possible way to avoid that.

I suspect it may be unrelated, but I have old memories of
insecurity creep involved in setxid scripts that set spider
senses tingling.  I notice there's at least one lesson to be
learnt in looking at which hints files mention the associated
flag for secure suid scripts:

    dcosx.sh:d_suidsafe=define
    dgux.sh:d_suidsafe='define'
    epix.sh:d_suidsafe='define'     # "./Configure -d" can't figure this out easilly
    esix4.sh:d_suidsafe=define
    linux.sh:d_suidsafe='undef'
    mirbsd.sh:d_suidsafe=$define
    openbsd.sh:d_suidsafe=$define
    powerux.sh:d_suidsafe='define'
    qnx.sh:  d_suidsafe='define'
    solaris_2.sh:d_suidsafe=${d_suidsafe:-define}
    svr4.sh:d_suidsafe='define'     # "./Configure -d" can't figure this out easilly
    svr5.sh:d_suidsafe='define'     # "./Configure -d" can't figure this out easily
    uts.sh:d_suidsafe='define'
    vmesa.sh:d_suidsafe='undef'

The lesson?  That we cut and paste a lot, and that 
we don't most of us spell check our hints files. :)

--tom

====== OpenBSD and also Darwin setuid(2) ======

     The setuid() function sets the real and effective user IDs and the saved
     set-user-ID of the current process to the specified value.  The setuid()
     function is permitted if the effective user ID is that of the superuser,
     or if the specified user ID is the same as the effective user ID.  If
     not, but the specified user ID is the same as the real user ID, setuid()
     will set the effective user ID to the real user ID.

     The setgid() function sets the real and effective group IDs and the
     saved set-group-ID of the current process to the specified value.  The
     setgid() function is permitted if the effective user ID is that of the
     superuser, or if the specified group ID is the same as the effective
     group ID.  If not, but the specified group ID is the same as the real
     group ID, setgid() will set the effective group ID to the real group
     ID.  Supplementary group IDs remain unchanged.

     The seteuid() function (setegid()) sets the effective user ID (group ID)
     of the current process.  The effective user ID may be set to the value of
     the real user ID or the saved set-user-ID (see intro(2) and execve(2));
     in this way, the effective user ID of a set-user-ID executable may be
     toggled by switching to the real user ID, then re-enabled by reverting to
     the set-user-ID value.  Similarly, the effective group ID may be set to
     the value of the real group ID or the saved set-group-ID.

====== Solaris setuid(2) ======

     The setuid() function sets the real user ID, effective  user
     ID,  and  saved user ID of the calling process. The setgid()
     function sets the real group ID,  effective  group  ID,  and
     saved  group  ID  of  the calling process. The setegid() and
     seteuid() functions set the effective  group  and  user  IDs
     respectively  for the calling process. See intro(2) for more
     information on real, effective, and  saved  user  and  group
     IDs.

     At login time, the real user  ID,  effective  user  ID,  and
     saved  user  ID of the login process are set to the login ID
     of the user responsible for the creation of the process. The
     same  is  true for the real, effective, and saved group IDs;
     they are set to the group ID of the user responsible for the
     creation of the process.

     When a process calls one of the exec(2) family of  functions
     to  execute a file (program), the user and/or group identif-
     iers associated with the process can  change.  If  the  file
     executed is a set-user-ID file, the effective and saved user
     IDs of the process are set to the owner  of  the  file  exe-
     cuted.  If  the  file  executed  is a set-group-ID file, the
     effective and saved group IDs of the process are set to  the
     group  of  the  file executed. If the file executed is not a
     set-user-ID or set-group-ID file,  the  effective  user  ID,
     saved  user  ID,  effective group ID, and saved group ID are
     not changed.

     If the {PRIV_PROC_SETID} privilege is asserted in the effec-
     tive  set  of the process calling setuid(), the real, effec-
     tive, and saved user IDs are set to the  uid  argument.   If
     the  uid  argument  is 0 and none of the saved, effective or
     real  UID  is  0,   additional   restrictions   apply.   See
     privileges(5).

     If the {PRIV_PROC_SETID} privilege is not  asserted  in  the
     effective  set,  but  uid  is either the real user ID or the
     saved user ID of the calling process, the effective user  ID
     is set to uid.

     If the {PRIV_PROC_SETID} privilege is asserted in the effec-
     tive  set  of the process calling setgid(), the real, effec-
     tive, and saved group IDs are set to the gid argument.

     If the {PRIV_PROC_SETID} privilege is not  asserted  in  the
     effective  set,  but  gid is either the real group ID or the
     saved group ID of the calling process, the  effective  group
     ID is set to gid.

====== Linus setuid(2) ====== 

    setuid() sets the effective user ID of the calling process. If the
    effective UID of the caller is root, the real UID and saved set-user-
    ID are also set.

    Under Linux, setuid() is implemented like the POSIX version with
    the _POSIX_SAVED_IDS feature.  This allows a set-user-ID (other
    than root) program to drop all of its user privileges, do some un-
    privileged work, and then re-engage the original effective user ID in
    a secure manner.

    If the user is root or the program is set-user-ID-root, special care
    must be taken. The setuid() function checks the effective user ID of
    the caller and if it is the superuser, all process-related user ID's
    are set to uid. After this has occurred, it is impossible for the
    program to regain root privileges.

    Thus, a set-user-ID-root program wishing to temporarily drop root
    privileges, assume the identity of a non-root user, and then regain
    root privileges afterwards cannot use setuid(). You can accomplish this
    with the (non-POSIX, BSD) call seteuid(2).

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About