* If not running as root, let the setuid helper kill the build user's
processes before and after the build.
This commit is contained in:
		
							parent
							
								
									ec23ecc64d
								
							
						
					
					
						commit
						f76fdb6d42
					
				
					 2 changed files with 69 additions and 31 deletions
				
			
		|  | @ -351,6 +351,8 @@ public: | |||
|     void acquire(); | ||||
|     void release(); | ||||
| 
 | ||||
|     void kill(); | ||||
| 
 | ||||
|     string getUser() { return user; } | ||||
|     uid_t getUID() { return uid; } | ||||
|     uid_t getGID() { return gid; } | ||||
|  | @ -452,29 +454,8 @@ void UserLock::release() | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool amPrivileged() | ||||
| { | ||||
|     return geteuid() == 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool haveBuildUsers() | ||||
| { | ||||
|     return querySetting("build-users-group", "") != ""; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void killUserWrapped(uid_t uid) | ||||
| { | ||||
|     if (amPrivileged()) | ||||
|         killUser(uid); | ||||
|     else | ||||
|         /* !!! TODO */ | ||||
|         printMsg(lvlError, "must kill"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void getOwnership(const Path & path) | ||||
| static void runSetuidHelper(const string & command, | ||||
|     const string & arg) | ||||
| { | ||||
|     string program = nixLibexecDir + "/nix-setuid-helper"; | ||||
|              | ||||
|  | @ -491,8 +472,8 @@ void getOwnership(const Path & path) | |||
|             std::vector<const char *> args; /* careful with c_str()!
 | ||||
|                                                */ | ||||
|             args.push_back(program.c_str()); | ||||
|             args.push_back("get-ownership"); | ||||
|             args.push_back(path.c_str()); | ||||
|             args.push_back(command.c_str()); | ||||
|             args.push_back(arg.c_str()); | ||||
|             args.push_back(0); | ||||
| 
 | ||||
|             execve(program.c_str(), (char * *) &args[0], 0); | ||||
|  | @ -514,6 +495,34 @@ void getOwnership(const Path & path) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void UserLock::kill() | ||||
| { | ||||
|     assert(enabled()); | ||||
|     if (amPrivileged()) | ||||
|         killUser(uid); | ||||
|     else | ||||
|         runSetuidHelper("kill", user); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool amPrivileged() | ||||
| { | ||||
|     return geteuid() == 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool haveBuildUsers() | ||||
| { | ||||
|     return querySetting("build-users-group", "") != ""; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void getOwnership(const Path & path) | ||||
| { | ||||
|     runSetuidHelper("get-ownership", path); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void deletePathWrapped(const Path & path) | ||||
| { | ||||
|     /* When using build users and we're not root, we may not have
 | ||||
|  | @ -850,7 +859,7 @@ void DerivationGoal::buildDone() | |||
|        open and modifies them after they have been chown'ed to | ||||
|        root. */ | ||||
|     if (buildUser.enabled()) | ||||
|         killUserWrapped(buildUser.getUID()); | ||||
|         buildUser.kill(); | ||||
| 
 | ||||
|     /* Close the read side of the logger pipe. */ | ||||
|     logPipe.readSide.close(); | ||||
|  | @ -1332,7 +1341,7 @@ void DerivationGoal::startBuilder() | |||
| 
 | ||||
|         /* Make sure that no other processes are executing under this
 | ||||
|            uid. */ | ||||
|         killUserWrapped(buildUser.getUID()); | ||||
|         buildUser.kill(); | ||||
|          | ||||
|         /* Change ownership of the temporary build directory, if we're
 | ||||
|            root.  If we're not root, then the setuid helper will do it | ||||
|  |  | |||
|  | @ -66,6 +66,15 @@ static uid_t nameToUid(const string & userName) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void checkIfBuildUser(const StringSet & buildUsers, | ||||
|     const string & userName) | ||||
| { | ||||
|     if (buildUsers.find(userName) == buildUsers.end()) | ||||
|         throw Error(format("user `%1%' is not a member of the build users group") | ||||
|             % userName); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Run `program' under user account `targetUser'.  `targetUser' should
 | ||||
|    be a member of `buildUsersGroup'.  The ownership of the current | ||||
|    directory is changed from the Nix user (uidNix) to the target | ||||
|  | @ -80,10 +89,9 @@ static void runBuilder(uid_t uidNix, gid_t gidBuildUsers, | |||
|     if (uidTargetUser == 0) | ||||
|         throw Error("won't setuid to root"); | ||||
| 
 | ||||
|     /* Verify that the target user is a member of that group. */ | ||||
|     if (buildUsers.find(targetUser) == buildUsers.end()) | ||||
|         throw Error(format("user `%1%' is not a member of the build users group") | ||||
|             % targetUser); | ||||
|     /* Verify that the target user is a member of the build users
 | ||||
|        group. */ | ||||
|     checkIfBuildUser(buildUsers, targetUser); | ||||
|      | ||||
|     /* Chown the current directory, *if* it is owned by the Nix
 | ||||
|        account.  The idea is that the current directory is the | ||||
|  | @ -118,6 +126,21 @@ static void runBuilder(uid_t uidNix, gid_t gidBuildUsers, | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void killBuildUser(gid_t gidBuildUsers, | ||||
|     const StringSet & buildUsers, const string & userName) | ||||
| { | ||||
|     uid_t uid = nameToUid(userName); | ||||
|      | ||||
|     /* Verify that the user whose processes we are to kill is a member
 | ||||
|        of the build users group. */ | ||||
|     checkIfBuildUser(buildUsers, userName); | ||||
| 
 | ||||
|     assert(uid != 0); | ||||
| 
 | ||||
|     killUser(uid); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #ifndef NIX_SETUID_CONFIG_FILE | ||||
| #define NIX_SETUID_CONFIG_FILE "/etc/nix-setuid.conf" | ||||
| #endif | ||||
|  | @ -204,6 +227,12 @@ static void run(int argc, char * * argv) | |||
|         secureChown(-1, gidBuildUsers, uidNix, gidBuildUsers, argv[2]); | ||||
|     } | ||||
| 
 | ||||
|     else if (command == "kill") { | ||||
|         /* Syntax: nix-setuid-helper kill <username> */ | ||||
|         if (argc != 3) throw Error("missing user name"); | ||||
|         killBuildUser(gidBuildUsers, buildUsers, argv[2]); | ||||
|     } | ||||
| 
 | ||||
|     else throw Error ("invalid command"); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue