* Removed `build-allow-root'.
* Added `build-users-group', the group under which builds are to be performed. * Check that /nix/store has 1775 permission and is owner by the build-users-group.
This commit is contained in:
		
							parent
							
								
									84d6459bd5
								
							
						
					
					
						commit
						35247c4c9f
					
				
					 5 changed files with 61 additions and 39 deletions
				
			
		| 
						 | 
					@ -78,37 +78,46 @@
 | 
				
			||||||
#build-max-jobs = 1
 | 
					#build-max-jobs = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Option `build-allow-root'
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This option controls Nix's behaviour when it is invoked under the
 | 
					 | 
				
			||||||
# `root' user (or setuid-root).  If `true' (default), builds are
 | 
					 | 
				
			||||||
# performed under the `root' user.  If `false', builds are performed
 | 
					 | 
				
			||||||
# under one of the users listed in the `build-users' option (see
 | 
					 | 
				
			||||||
# below).
 | 
					 | 
				
			||||||
#build-allow-root = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Option `build-users'
 | 
					### Option `build-users'
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This option is only applicable if `build-allow-root' is `false' and
 | 
					# This option contains a list of user names under which Nix can
 | 
				
			||||||
# Nix is invoked under the `root' user (or setuid-root).  It contains
 | 
					# execute builds.  In multi-user Nix installations, builds should not
 | 
				
			||||||
# a list of user names under which Nix can execute builds.  Builds
 | 
					# be performed by the Nix account since that would allow users to
 | 
				
			||||||
# cannot be performed by root since that would allow users to take
 | 
					# arbitrarily modify the Nix store and database by supplying specially
 | 
				
			||||||
# over the system by supplying specially crafted builders; and they
 | 
					# crafted builders; and they cannot be performed by the calling user
 | 
				
			||||||
# cannot be performed by the calling user since that would allow
 | 
					# since that would allow him/her to influence the build result.
 | 
				
			||||||
# him/her to influence the build result.
 | 
					 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Thus this list should contain a number of `special' user accounts
 | 
					# Thus this list should contain a number of `special' user accounts
 | 
				
			||||||
# created specifically for Nix, e.g., `nix-builder-1',
 | 
					# created specifically for Nix, e.g., `nix-builder-1',
 | 
				
			||||||
# `nix-builder-2', and so on.  The more users the better, since at
 | 
					# `nix-builder-2', and so on.  The more users the better, since at
 | 
				
			||||||
# most a number of builds equal to the number of build users can be
 | 
					# most a number of builds equal to the number of build users can be
 | 
				
			||||||
# started.
 | 
					# running simultaneously.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# If this list is empty, builds will be performed under the Nix
 | 
				
			||||||
 | 
					# account (that is, the uid under which the Nix daemon runs, or that
 | 
				
			||||||
 | 
					# owns the setuid nix-worker program).
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Example:
 | 
					# Example:
 | 
				
			||||||
#   build-users = nix-builder-1 nix-builder-2 nix-builder-3
 | 
					#   build-users = nix-builder-1 nix-builder-2 nix-builder-3
 | 
				
			||||||
#build-users =
 | 
					#build-users =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Option `build-users-group'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# If `build-users' is used, then this option specifies the group ID
 | 
				
			||||||
 | 
					# (gid) under which each build is to be performed.  This group should
 | 
				
			||||||
 | 
					# have permission to create files in the Nix store, but not delete
 | 
				
			||||||
 | 
					# them.  I.e., /nix/store should be owned by the Nix account, its
 | 
				
			||||||
 | 
					# group should be the group specified here, and its mode should be
 | 
				
			||||||
 | 
					# 1775.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The default is `nix'.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Example:
 | 
				
			||||||
 | 
					#   build-users-group = nix
 | 
				
			||||||
 | 
					#build-users-group =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Option `system'
 | 
					### Option `system'
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This option specifies the canonical Nix system name of the current
 | 
					# This option specifies the canonical Nix system name of the current
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -258,6 +258,8 @@ static void setuidInit()
 | 
				
			||||||
    if (setuid(nixUid)) abort();
 | 
					    if (setuid(nixUid)) abort();
 | 
				
			||||||
    if (setgid(nixGid)) abort();
 | 
					    if (setgid(nixGid)) abort();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setuidMode = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,9 @@ namespace nix {
 | 
				
			||||||
Path makeRootName(const Path & gcRoot, int & counter);
 | 
					Path makeRootName(const Path & gcRoot, int & counter);
 | 
				
			||||||
void printGCWarning();
 | 
					void printGCWarning();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Whether we're running setuid. */
 | 
				
			||||||
 | 
					bool setuidMode = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1271,12 +1271,10 @@ void DerivationGoal::startBuilder()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /* If we are running as root, and the `build-allow-root' setting
 | 
					    /* If `build-users' is not empty, then we have to build as one of
 | 
				
			||||||
       is `false', then we have to build as one of the users listed in
 | 
					       the users listed in `build-users'. */
 | 
				
			||||||
       `build-users'. */
 | 
					    gid_t gidBuildGroup = -1;    
 | 
				
			||||||
    if (!queryBoolSetting("build-allow-root", true) &&
 | 
					    if (querySetting("build-users", Strings()).size() > 0) {
 | 
				
			||||||
        getuid() == rootUserId)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        buildUser.acquire();
 | 
					        buildUser.acquire();
 | 
				
			||||||
        assert(buildUser.getUID() != 0);
 | 
					        assert(buildUser.getUID() != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1288,6 +1286,14 @@ void DerivationGoal::startBuilder()
 | 
				
			||||||
        if (chown(tmpDir.c_str(), buildUser.getUID(), (gid_t) -1) == -1)
 | 
					        if (chown(tmpDir.c_str(), buildUser.getUID(), (gid_t) -1) == -1)
 | 
				
			||||||
            throw SysError(format("cannot change ownership of `%1%'") % tmpDir);
 | 
					            throw SysError(format("cannot change ownership of `%1%'") % tmpDir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* What group to execute the builder in? */
 | 
				
			||||||
 | 
					        string buildGroup = querySetting("build-users-group", "nix");
 | 
				
			||||||
 | 
					        struct group * gr = getgrnam(buildGroup.c_str());
 | 
				
			||||||
 | 
					        if (!gr) throw Error(
 | 
				
			||||||
 | 
					            format("the group `%1%' specified in `build-users-group' does not exist")
 | 
				
			||||||
 | 
					            % buildGroup);
 | 
				
			||||||
 | 
					        gidBuildGroup = gr->gr_gid;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        /* Check that the Nix store has the appropriate permissions,
 | 
					        /* Check that the Nix store has the appropriate permissions,
 | 
				
			||||||
           i.e., owned by root and mode 1777 (sticky bit on so that
 | 
					           i.e., owned by root and mode 1777 (sticky bit on so that
 | 
				
			||||||
           the builder can create its output but not mess with the
 | 
					           the builder can create its output but not mess with the
 | 
				
			||||||
| 
						 | 
					@ -1295,13 +1301,13 @@ void DerivationGoal::startBuilder()
 | 
				
			||||||
        struct stat st;
 | 
					        struct stat st;
 | 
				
			||||||
        if (stat(nixStore.c_str(), &st) == -1)
 | 
					        if (stat(nixStore.c_str(), &st) == -1)
 | 
				
			||||||
            throw SysError(format("cannot stat `%1%'") % nixStore);
 | 
					            throw SysError(format("cannot stat `%1%'") % nixStore);
 | 
				
			||||||
        if (st.st_uid != rootUserId)
 | 
					 | 
				
			||||||
            throw Error(format("`%1%' is not owned by root") % nixStore);
 | 
					 | 
				
			||||||
        if (!(st.st_mode & S_ISVTX) ||
 | 
					        if (!(st.st_mode & S_ISVTX) ||
 | 
				
			||||||
            ((st.st_mode & S_IRWXO) != S_IRWXO))
 | 
					            ((st.st_mode & S_IRWXG) != S_IRWXG) ||
 | 
				
			||||||
 | 
					            (st.st_gid != gidBuildGroup))
 | 
				
			||||||
            throw Error(format(
 | 
					            throw Error(format(
 | 
				
			||||||
                "builder does not have write permission to `%1%'; "
 | 
					                "builder does not have write permission to `%1%'; "
 | 
				
			||||||
                "try `chmod 1777 %1%'") % nixStore);
 | 
					                "try `chgrp %1% %2%; chmod 1775 %2%'")
 | 
				
			||||||
 | 
					                % buildGroup % nixStore);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -1343,23 +1349,25 @@ void DerivationGoal::startBuilder()
 | 
				
			||||||
                envStrs.push_back(i->first + "=" + i->second);
 | 
					                envStrs.push_back(i->first + "=" + i->second);
 | 
				
			||||||
            const char * * envArr = strings2CharPtrs(envStrs);
 | 
					            const char * * envArr = strings2CharPtrs(envStrs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* If we are running as root and `build-allow-root' is
 | 
					            /* If we are running in `build-users' mode, then switch to
 | 
				
			||||||
               `false', then switch to the user we allocated above.
 | 
					               the user we allocated above.  Make sure that we drop
 | 
				
			||||||
               Make sure that we drop all root privileges.  Note that
 | 
					               all root privileges.  Note that initChild() above has
 | 
				
			||||||
               initChild() above has closed all file descriptors
 | 
					               closed all file descriptors except std*, so that's
 | 
				
			||||||
               except std*, so that's safe.  Also note that setuid()
 | 
					               safe.  Also note that setuid() when run as root sets
 | 
				
			||||||
               when run as root sets the real, effective and saved
 | 
					               the real, effective and saved UIDs. */
 | 
				
			||||||
               UIDs. */
 | 
					 | 
				
			||||||
            if (buildUser.getUID() != 0) {
 | 
					            if (buildUser.getUID() != 0) {
 | 
				
			||||||
                printMsg(lvlError, format("switching to uid `%1%'") % buildUser.getUID());
 | 
					                printMsg(lvlError, format("switching to uid `%1%'") % buildUser.getUID());
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                /* !!! setgid also */
 | 
					 | 
				
			||||||
                if (setgroups(0, 0) == -1)
 | 
					                if (setgroups(0, 0) == -1)
 | 
				
			||||||
                    throw SysError("cannot clear the set of supplementary groups");
 | 
					                    throw SysError("cannot clear the set of supplementary groups");
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
                setuid(buildUser.getUID());
 | 
					                setuid(buildUser.getUID());
 | 
				
			||||||
                assert(getuid() == buildUser.getUID());
 | 
					                assert(getuid() == buildUser.getUID());
 | 
				
			||||||
                assert(geteuid() == buildUser.getUID());
 | 
					                assert(geteuid() == buildUser.getUID());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                setgid(gidBuildGroup);
 | 
				
			||||||
 | 
					                assert(getgid() == gidBuildGroup);
 | 
				
			||||||
 | 
					                assert(getegid() == gidBuildGroup);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            /* Execute the program.  This should not return. */
 | 
					            /* Execute the program.  This should not return. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,10 +235,10 @@ void canonicalisePathMetaData(const Path & path)
 | 
				
			||||||
                throw SysError(format("changing mode of `%1%' to %2$o") % path % mode);
 | 
					                throw SysError(format("changing mode of `%1%' to %2$o") % path % mode);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (st.st_uid != getuid() || st.st_gid != getgid()) {
 | 
					        if (st.st_uid != geteuid() || st.st_gid != getegid()) {
 | 
				
			||||||
            if (chown(path.c_str(), getuid(), getgid()) == -1)
 | 
					            if (chown(path.c_str(), geteuid(), getegid()) == -1)
 | 
				
			||||||
                throw SysError(format("changing owner/group of `%1%' to %2%/%3%")
 | 
					                throw SysError(format("changing owner/group of `%1%' to %2%/%3%")
 | 
				
			||||||
                    % path % getuid() % getgid());
 | 
					                    % path % geteuid() % getegid());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (st.st_mtime != 0) {
 | 
					        if (st.st_mtime != 0) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue