From owner-freebsd-arch Sat Jun 17 10:45:55 2000 Delivered-To: freebsd-arch@freebsd.org Received: from beastie.mckusick.com (beastie.mckusick.com [209.31.233.184]) by hub.freebsd.org (Postfix) with ESMTP id AB27A37B5D4 for ; Sat, 17 Jun 2000 10:45:50 -0700 (PDT) (envelope-from mckusick@mckusick.com) Received: from beastie.mckusick.com (localhost [127.0.0.1]) by beastie.mckusick.com (8.9.3/8.9.3) with ESMTP id KAA08559; Sat, 17 Jun 2000 10:45:40 -0700 (PDT) (envelope-from mckusick@beastie.mckusick.com) Message-Id: <200006171745.KAA08559@beastie.mckusick.com> To: Gregory Neil Shapiro Subject: Re: Broken FreeBSD setuid(2)? Cc: sendmail-questions@Sendmail.ORG, eric@Sendmail.ORG (Eric Allman), arch@freebsd.org In-Reply-To: Your message of "Thu, 15 Jun 2000 12:05:27 PDT." <14665.10487.273074.915885@horsey.gshapiro.net> Date: Sat, 17 Jun 2000 10:45:40 -0700 From: Kirk McKusick Sender: owner-freebsd-arch@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG 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 > To: sendmail-questions@Sendmail.ORG > Cc: eric@sendmail.com, mckusick@mckusick.com > Subject: Broken FreeBSD setuid(2)? > In-Reply-To: <26017.961092745@ux.cs.niu.edu> > References: <14665.5036.94759.10387@horsey.gshapiro.net> > <25862.961091528@ux.cs.niu.edu> > <14665.6387.591517.166768@horsey.gshapiro.net> > <26017.961092745@ux.cs.niu.edu> > X-Mailer: VM 6.75 under 21.2 (beta34) "Molpe" XEmacs Lucid > > I'm considering sending this off to someone at FreeBSD. Opinions before I > do? > > > I believe we (sendmail-bugs) have found a _possible_ bug in the setuid(2) > implementation on FreeBSD 3.4 (and possibly 4.0). setuid(2) appears to set > the saved uid even if the process is not running as root and not > set-user-id root. For example: > > #include > #include > #include > > int > main(int argc, char **argv) > { > uid_t euid = geteuid(); > uid_t ruid = getuid(); > > printf("Before: ruid=%d euid=%d\n", getuid(), geteuid()); > if (setuid(ruid) < 0) > perror("setuid"); > printf("Middle: ruid=%d euid=%d\n", getuid(), geteuid()); > if (setuid(euid) < 0) > perror("setuid"); > printf("After: ruid=%d euid=%d\n", getuid(), geteuid()); > } > > And an example run: > > > uname -a > FreeBSD horsey.gshapiro.net 3.4-STABLE FreeBSD 3.4-STABLE #51: Sun May 21 22:36:42 PDT 2000 root@horsey.gshapiro.net:/usr/src/sys/compile/HORSEY i386 > > ls -lag try > -rwsr-xr-x 1 generic gshapiro 3731 Jun 15 10:27 try > > id > uid=103(gshapiro) > > id generic > uid=101(generic) > > ./try > Before: ruid=103 euid=101 > Middle: ruid=103 euid=103 > setuid: Operation not permitted > After: ruid=103 euid=103 > > > 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. > 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 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: > > STANDARDS > The setuid() and setgid() functions are compliant with the IEEE > Std1003.1-1990 (``POSIX'') specification with _POSIX_SAVED_IDS not de- > fined with the permitted extensions from Appendix B.4.2.2. The seteuid() > and setegid() functions are extensions based on the POSIX concept of > _POSIX_SAVED_IDS, and have been proposed for a future revision of the > standard. > > 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. 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 user should not have the ability to set the saved-id. They further argue that they should never need the ability to set the saved-id since they are only running their own trusted code. They can lose the special priviledge in any sub-processes that they exec simply by setting the real user-id to the effective user-id before doing the exec (since the effective user-id is copied to the saved user-id on exec). What Posix fails to account for is a program that gets corrupted by a stack overflow and wants to guard against it by losing their saved-id before starting to accept outside input. Posix would say that a program with a stack overflow is not compliant with the standard, and hence is outside the scope of the document. 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 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. Kirk McKusick To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-arch" in the body of the message