Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Jun 2000 19:13:28 +1000 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Kirk McKusick <mckusick@mckusick.com>
Cc:        Gregory Neil Shapiro <sendmail+gshapiro@Sendmail.ORG>, sendmail-questions@Sendmail.ORG, Eric Allman <eric@Sendmail.ORG>, arch@FreeBSD.ORG
Subject:   Re: Broken FreeBSD setuid(2)? 
Message-ID:  <Pine.BSF.4.21.0006191805050.744-100000@besplex.bde.org>
In-Reply-To: <200006171745.KAA08559@beastie.mckusick.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, 17 Jun 2000, Kirk McKusick wrote:

> My answer is at the bottom. I am copying the FreeBSD arch group
> so they can complain if I am misrepresenting how this came to be.
> 
> > Date: Thu, 15 Jun 2000 12:05:27 -0700 (PDT)
> > From: Gregory Neil Shapiro <sendmail+gshapiro@Sendmail.ORG>
> > ...
> > POSIX Part I, section 4.2.2.2 states:
> > 
> >       If {_POSIX_SAVED_IDS} is defined:
> > ...
> >       (2) If the process does not have appropriate privileges, but uid is
> >           equal to the real user ID or the saved set-user-ID, the setuid()
> >           function sets the effective user ID to uid; the real user ID and
> >           saved set-user-ID remain unchanged by this function call.
> > 
> > This is the case demonstrated above.  It does not have appropriate privileges
> > since it is not running as root.  The uid is equal to the real UID.

This doesn't follow.  "appropriate privilege" is implementation-defined.
See POSIX.1-1996 section 2.2.2.4.  In FreeBSD, appropriate privilege for
setuid() is defined as (newuid == geteuid() || geteuid() == 0).  This
"fixes":
1) Programs that depend on pure !_POSIX_SAVED_IDS behaviour.  4.4BSD(Lite)
   saved ids are surprising for such programs.
2) There was no "standard" was of dropping the extra privileges given by
   4.4BSD(Lite) saved ids using 4.4BSD(Lite) syscalls withoud exec'ing,
   except for root.  In FreeBSD, this can be done using either
   setreuid(uid, uid)) or the newer setresuid(uid, uid, uid), but
   depending on setreuid() to do it is dangerous because setreuid()
   is just a wrapper for seteuid() in 4.4BSD(Lite).

> > However, the setuid() function is setting the saved set-user-ID and not
> > leaving it unchanged.  If it were unchanged, then the second setuid()
> > should not fail, again because of this statement and the fact that the uid
> > is equal to the saved set-user-ID.
> > 
> > Looking at other implementations, we have found that the second setuid only
> > fails on FreeBSD.  It succeeds and the program works as expected on
> > Solaris, Linux, and OpenBSD.

I think 4.4BSDLite-[1-2], NetBSD(at east last year's version), and BSD/OS4.1
have the same behaviour as FreeBSD[3-5] here (some versions of FreeBSD-2
implemented _POSIX_SAVED_IDS so they gave the behaviour that you expected).
FreeBSD's definition of "appropriate privilege" is irrelevant in your
example.  The 4.4BSD(Lite) saved id gives "unappropriate" privilege for
setuid() to succeed, and when it succeeds it sets all the ids to the
same values.

> > I checked /usr/src/sys/kern/kern_prot.c and see comments about appendix B
> > but I do not believe they apply to this case.  The setuid() man page
> > states:

Indeed, they don't quite apply.

> > It's arguable whether or not you can follow the rules of !_POSIX_SAVED_IDS
> > while still using saved IDs as it creates a subtle difference between
> > FreeBSD and other operating systems that more than likely goes unnoticed by
> > application writers and has the potential of breaking some of these
> > programs.

This is a 4.4BSD(Lite) feature, not a FreeBSD one.

> I agree that FreeBSD does not implement saved id's according
> to the Posix spec. And indeed they do not claim to do so as
> {_POSIX_SAVED_IDS} is defined as false (see `sysctl kern.saved_ids').
> As released, 4.4BSD defined {_POSIX_SAVED_IDS} as true and had the
> behavior of NetBSD and OpenBSD. Posix argues that a non-priviledged

Is it really different from 4.4BSD(Lite) here?  From <sys/unistd.h>
in Lite1:

---
/*
 * Although we have saved user/group IDs, we do not use them in setuid
 * as described in POSIX 1003.1, because the feature does not work for
 * root.  We use the saved IDs in seteuid/setegid, which are not currently
 * part of the POSIX 1003.1 specification.
 */
#ifdef	_NOT_AVAILABLE
#define	_POSIX_SAVED_IDS	/* saved set-user-ID and set-group-ID */
#endif
---

The Lite2 code in kern/kern_prot.c matches this comment.  FreeBSD
hasn't changed a single byte here in <sys/unistd.h>, but has changed
kern/kern_prot.c so implement _POSIX_SAVED_IDS if the unsupported
option _POSIX_SAVED_IDS is defined at kernel compile time.  BSD/OS4.1
has a better comment without a "dontdef" ifdef.

BTW, note that _POSIX_SAVED_IDS doesn't mean that there are no saved
ids.  It means that there are no POSIX ones, and more importantly, that
setuid() has the POSIX semantics for the !_POSIX_SAVED_IDS case in
setuid(), etc.

> ...
> The FreeBSD folks decided to change the semantics of setuid to
> overwrite the saved user-id so that programs could protect themselves
> from stack overflows, debugger attaches, etc. They argue that
> seteuid is available if you just want to set the effective user-id
> and it is stupid to have a second system call (setuid) which does
> exactly the same thing when you are not root. Since Posix never

setuid() is still good for setting all the ids to the same value.
It goes well with using seteuid() to manipulate the euid.

> bought into adding seteuid, they had to overload setuid to get the
> equivalent functionality. This is a good example of why Posix options
> were a bad idea. By letting each system ship with different option
> settings, you end up with very subtilely different semantics.
> Each vendor is well meaning, but makes for a programming nightmare
> among application developers that have to deal with all the
> combinations.

POSIX options like _POSIX_SAVED_IDS are simple compared with meta-options
like "appropriate privlege".  Correct handling of "appropriate privilege"
seems to require programs to read and understand the system documentation
for it when they start up ;-(.

Bruce



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0006191805050.744-100000>