* Remove most of the old setuid code.
* Much simpler setuid code for the worker in slave mode.
This commit is contained in:
		
							parent
							
								
									9c9cdb06d0
								
							
						
					
					
						commit
						536595b072
					
				
					 3 changed files with 57 additions and 138 deletions
				
			
		|  | @ -15,6 +15,9 @@ | ||||||
| #include <aterm2.h> | #include <aterm2.h> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | extern char * * environ; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -204,6 +207,54 @@ static void initAndRun(int argc, char * * argv) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | static void setuidInit() | ||||||
|  | { | ||||||
|  |     /* Don't do anything if this is not a setuid binary. */ | ||||||
|  |     if (getuid() == geteuid() && getgid() == getegid()) return; | ||||||
|  | 
 | ||||||
|  |     uid_t nixUid = geteuid(); | ||||||
|  |     gid_t nixGid = getegid(); | ||||||
|  |      | ||||||
|  |     fprintf(stderr, "<<< setuid mode >>>\n"); | ||||||
|  | 
 | ||||||
|  |     /* Don't trust the environment. */ | ||||||
|  |     environ = 0; | ||||||
|  | 
 | ||||||
|  |     /* Don't trust the current directory. */ | ||||||
|  |     if (chdir("/") == -1) abort(); | ||||||
|  | 
 | ||||||
|  |     /* Make sure that file descriptors 0, 1, 2 are open. */ | ||||||
|  |     for (int fd = 0; fd <= 2; ++fd) { | ||||||
|  |         struct stat st; | ||||||
|  |         if (fstat(fd, &st) == -1) abort(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* Set the real (and preferably also the save) uid/gid to the
 | ||||||
|  |        effective uid/gid.  This matters mostly when we're not using | ||||||
|  |        build-users (bad!), since some builders (like Perl) complain | ||||||
|  |        when real != effective. | ||||||
|  | 
 | ||||||
|  |        On systems where setresuid is unavailable, we can't drop the | ||||||
|  |        saved uid/gid.  This means that we could go back to the | ||||||
|  |        original real uid (i.e., the uid of the caller).  That's not | ||||||
|  |        really a problem, except maybe when we execute a builder and | ||||||
|  |        we're not using build-users.  In that case, the builder may be | ||||||
|  |        able to switch to the uid of the caller and possibly do bad | ||||||
|  |        stuff.  But note that when not using build-users, the builder | ||||||
|  |        could also modify the Nix executables (say, replace them by a | ||||||
|  |        Trojan horse), so the problem is already there. */ | ||||||
|  | 
 | ||||||
|  | #if HAVE_SETRESUID | ||||||
|  |     setresuid(nixUid, nixUid, nixUid); | ||||||
|  |     setresgid(nixGid, nixGid, nixGid); | ||||||
|  | #else | ||||||
|  |     /* Note: doesn't set saved uid/gid! */ | ||||||
|  |     setuid(nixUid); | ||||||
|  |     setgid(nixGid); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -212,10 +263,11 @@ static char buf[1024]; | ||||||
| int main(int argc, char * * argv) | int main(int argc, char * * argv) | ||||||
| { | { | ||||||
|     using namespace nix; |     using namespace nix; | ||||||
|      | 
 | ||||||
|     /* If we are setuid root, we have to get rid of the excess
 |     /* If we're setuid, then we need to take some security precautions
 | ||||||
|        privileges ASAP. */ |        right away. */ | ||||||
|     switchToNixUser(); |     if (argc == 0) abort(); | ||||||
|  |     setuidInit(); | ||||||
|      |      | ||||||
|     /* ATerm setup. */ |     /* ATerm setup. */ | ||||||
|     ATerm bottomOfStack; |     ATerm bottomOfStack; | ||||||
|  |  | ||||||
|  | @ -11,11 +11,8 @@ | ||||||
| 
 | 
 | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <sys/wait.h> | #include <sys/wait.h> | ||||||
| #include <fcntl.h> |  | ||||||
| 
 |  | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <pwd.h> | #include <fcntl.h> | ||||||
| #include <grp.h> |  | ||||||
| 
 | 
 | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| 
 | 
 | ||||||
|  | @ -891,130 +888,4 @@ bool string2Int(const string & s, int & n) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
| //////////////////////////////////////////////////////////////////////
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static bool haveSwitched; |  | ||||||
| static uid_t savedUid, nixUid; |  | ||||||
| static gid_t savedGid, nixGid; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #if HAVE_SETRESUID |  | ||||||
| #define _setuid(uid) setresuid(uid, uid, savedUid) |  | ||||||
| #define _setgid(gid) setresgid(gid, gid, savedGid) |  | ||||||
| #else |  | ||||||
| /* Only works properly when run by root. */ |  | ||||||
| #define _setuid(uid) setuid(uid) |  | ||||||
| #define _setgid(gid) setgid(gid) |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| void switchToNixUser() |  | ||||||
| { |  | ||||||
| #if 0 |  | ||||||
|     fprintf(stderr, "real = %d/%d, effective = %d/%d\n", |  | ||||||
|         getuid(), getgid(), geteuid(), getegid()); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     /* Note: we require setresuid for now since I don't want to think
 |  | ||||||
|        to deeply about whether this works on systems that don't have |  | ||||||
|        setresuid.  It's already hard enough. */ |  | ||||||
|        |  | ||||||
| #if HAVE_SETRESUID |  | ||||||
| 
 |  | ||||||
|     /* Setuid Nix operation works as follows:
 |  | ||||||
| 
 |  | ||||||
|        - The Nix binaries are owned by a Nix user and group, e.g., |  | ||||||
|          nix.nix, and must setuid and setgid, e.g., |  | ||||||
| 
 |  | ||||||
|          rwsrwsr-x nix.nix |  | ||||||
| 
 |  | ||||||
|        - Users (say alice.users) are only allowed to run (most) Nix |  | ||||||
|          operations if they are in the Nix group.  If they aren't, |  | ||||||
|          some read-only operations (like nix-env -qa) may still work. |  | ||||||
|           |  | ||||||
|        - We run mostly under the Nix user/group, but we switch back to |  | ||||||
|          the calling user/group for some work, like reading Nix |  | ||||||
|          expressions. |  | ||||||
| 
 |  | ||||||
|     */ |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     /* Don't do anything if this is not a setuid binary. */ |  | ||||||
|     if (getuid() == geteuid() && getgid() == getegid()) return; |  | ||||||
| 
 |  | ||||||
|     /* Here we set the uid and gid to the Nix user and group,
 |  | ||||||
|        respectively, IF the current (real) user is a member of the Nix |  | ||||||
|        group.  (The Nix group is the group of the current executable, |  | ||||||
|        i.e., the current effective gid.)  Otherwise we just drop all |  | ||||||
|        privileges. */ |  | ||||||
| 
 |  | ||||||
|     nixGid = geteuid(); |  | ||||||
| 
 |  | ||||||
|     /* Get the supplementary group IDs for the current user. */ |  | ||||||
|     int maxGids = 512, nrGids; |  | ||||||
|     gid_t gids[maxGids]; |  | ||||||
|     if ((nrGids = getgroups(maxGids, gids)) == -1) { |  | ||||||
|         std::cerr << format("unable to query gids\n"); |  | ||||||
|         exit(1); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* !!! Apparently it is unspecified whether getgroups() includes
 |  | ||||||
|        the effective gid.  In that case the following test is always |  | ||||||
|        true *if* the program is installed setgid (which we do when we |  | ||||||
|        have setresuid()).  On Linux this doesn't appear to be the |  | ||||||
|        case, but we should switch to the real gid before doing this |  | ||||||
|        test, and then switch back to the saved gid. */  |  | ||||||
| 
 |  | ||||||
|     /* Check that the current user is a member of the Nix group. */ |  | ||||||
|     bool found = false; |  | ||||||
|     for (int i = 0; i < nrGids; ++i) |  | ||||||
|         if (gids[i] == nixGid) { |  | ||||||
|             found = true; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     if (!found) { |  | ||||||
|         /* Not in the Nix group - drop all root/Nix privileges. */ |  | ||||||
|         _setgid(getgid()); |  | ||||||
|         _setuid(getuid()); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* Save the uid/gid of the caller so the we can switch back to
 |  | ||||||
|        that uid/gid for temporary work, like accessing files, in |  | ||||||
|        SwitchToOriginaluser. */ |  | ||||||
|     savedUid = getuid(); |  | ||||||
|     savedGid = getgid(); |  | ||||||
| 
 |  | ||||||
|     /* Set the real and effective gids to nixGid.  Also make very sure
 |  | ||||||
|        that this succeeded.  We switch the gid first because we cannot |  | ||||||
|        do it after we have dropped root uid. */ |  | ||||||
|     if (_setgid(nixGid) != 0 || getgid() != nixGid || getegid() != nixGid) { |  | ||||||
|         std::cerr << format("unable to set gid to `%1%'\n") % nixGid; |  | ||||||
|         exit(1); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* The Nix uid is the effective uid of the owner of the current
 |  | ||||||
|        executable, i.e., the current effective uid. */ |  | ||||||
|     nixUid = geteuid(); |  | ||||||
| 
 |  | ||||||
|     /* This will drop all root privileges, setting the real, effective
 |  | ||||||
|        and saved uids to pw->pw_uid.  Also make very sure that this |  | ||||||
|        succeeded.*/ |  | ||||||
|     if (_setuid(nixUid) != 0 || getuid() != nixUid || geteuid() != nixUid) { |  | ||||||
|         std::cerr << format("unable to set uid to `%1%'\n") % nixUid; |  | ||||||
|         exit(1); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* !!! for setuid operation, we should: 1) wipe the environment;
 |  | ||||||
|        2) verify file descriptors 0, 1, 2; 3) etc. |  | ||||||
|        See: http://www.daemon-systems.org/man/setuid.7.html
 |  | ||||||
|     */ |  | ||||||
| 
 |  | ||||||
|     haveSwitched = true; |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -249,10 +249,6 @@ string int2String(int n); | ||||||
| bool string2Int(const string & s, int & n); | bool string2Int(const string & s, int & n); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Setuid support. */ |  | ||||||
| void switchToNixUser(); |  | ||||||
| 
 |  | ||||||
|   |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue