Bug 114 - Under FreeBSD 4.x (and possibly 5.x), sudo can incorrectly provide elevated privileges to users when %group directives are used and NIS is used.
Under FreeBSD 4.x (and possibly 5.x), sudo can incorrectly provide elevated p...
Status: RESOLVED FIXED
Product: Sudo
Classification: Unclassified
Component: Sudo
1.6.7
PC FreeBSD
: high security
Assigned To: Todd C. Miller
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2003-05-21 18:18 MDT by Kirk Webb
Modified: 2003-05-21 23:46 MDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Kirk Webb 2003-05-21 18:18:23 MDT
Sudo makes an unsafe assumption about the integrity of static library memory in
the getgrnam() and getpwnam() libc calls.  It turns out that the inclusion of
users via the +@netgroup directive under FreeBSD 4.x (and possibly other
variants) can cause getpwnam() to call getgrnam().  Note that FreeBSD's
implementation of both functions uses static memory.  With that in mind, I'll
highlight the problem in the usergr_matches() function from parse.c (called when
sudo wants to see if a user is a member of some group listed via the '%'
directive in the sudoers file):

1  int
2  usergr_matches(group, user)
3      char *group;
4      char *user;
5  {
6      struct group *grp;
7      struct passwd *pw;
8      char **cur;
9
10     /* make sure we have a valid usergroup, sudo style */
11     if (*group++ != '%')
12 	return(FALSE);
13
14     if ((grp = getgrnam(group)) == NULL) 
15 	return(FALSE);
16
17     /*
18      * Check against user's real gid as well as group's user list
19      */
20     if ((pw = getpwnam(user)) == NULL)
21 	return(FALSE);
22
23     if (grp->gr_gid == pw->pw_gid)
24 	return(TRUE);
25
26     for (cur=grp->gr_mem; *cur; cur++) {
27 	if (strcmp(*cur, user) == 0)
28 	    return(TRUE);
29     }
30
31     return(FALSE);
32 }

First, a note:  In FreeBSD's getpwnam implementation, if 1) NIS is enabled, 2) a
user's entry isn't explicity listed in master.passwd, 3) there are +@netgroup
import directives in master.passwd, and 4) the user isn't found in the current
netgroup being searched, then the function searches for a group with the same
name, and if found, searches within it (using getgrnam()) for the user.  Whew,
that's a mouthful.  This is the situation where sudo gets into trouble.  I'll
refer to this as +@group inclusion.

Notice how getgrnam() is called on line 14, followed by getpwnam() on line 20. 
When a user is found via +@group inclusion, the call to getpwnam() will call
getgrnam() internally, and so _WILL_ overwrite/modify the static group
functions' memory.  So, if the subsequent check on line 23 doesn't succeed (it
won't if the user's default gid != gid of group s/he is included from), the one
on 27 will.

I think the FreeBSD libc maintainers are partly (mostly?) to blame here; they
should have either 1) made this side effect explicit in the getpwnam() manpage,
or 2) used separate internal memory for the group search.

Anyhow, here is a patch that will fix the problem:

--- parse.c	Tue Apr 15 18:39:14 2003
+++ parse.c.new	Fri May 16 13:46:36 2003
@@ -443,6 +443,7 @@
 {
     struct group *grp;
     struct passwd *pw;
+    int gid;
     char **cur;
 
     /* make sure we have a valid usergroup, sudo style */
@@ -451,20 +452,21 @@
 
     if ((grp = getgrnam(group)) == NULL) 
 	return(FALSE);
+    gid = grp->gr_gid;
 
     /*
-     * Check against user's real gid as well as group's user list
+     * Check against group's user list as well as user's real gid
      */
-    if ((pw = getpwnam(user)) == NULL)
-	return(FALSE);
-
-    if (grp->gr_gid == pw->pw_gid)
-	return(TRUE);
-
     for (cur=grp->gr_mem; *cur; cur++) {
 	if (strcmp(*cur, user) == 0)
 	    return(TRUE);
     }
+
+    if ((pw = getpwnam(user)) == NULL)
+	return(FALSE);
+
+    if (pw->pw_gid == gid)
+	return(TRUE);
 
     return(FALSE);
 }
Comment 1 Todd C. Miller 2003-05-21 19:46:58 MDT
It does seem kind of bogus that getpw*() and getgr*() use can clobber each other in the netgroup case but this may also affect systems other than FreeBSD.  A similar patch will be included in the next sudo release.