* 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 acquire(); | ||||||
|     void release(); |     void release(); | ||||||
| 
 | 
 | ||||||
|  |     void kill(); | ||||||
|  | 
 | ||||||
|     string getUser() { return user; } |     string getUser() { return user; } | ||||||
|     uid_t getUID() { return uid; } |     uid_t getUID() { return uid; } | ||||||
|     uid_t getGID() { return gid; } |     uid_t getGID() { return gid; } | ||||||
|  | @ -452,29 +454,8 @@ void UserLock::release() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| bool amPrivileged() | static void runSetuidHelper(const string & command, | ||||||
| { |     const string & arg) | ||||||
|     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) |  | ||||||
| { | { | ||||||
|     string program = nixLibexecDir + "/nix-setuid-helper"; |     string program = nixLibexecDir + "/nix-setuid-helper"; | ||||||
|              |              | ||||||
|  | @ -491,8 +472,8 @@ void getOwnership(const Path & path) | ||||||
|             std::vector<const char *> args; /* careful with c_str()!
 |             std::vector<const char *> args; /* careful with c_str()!
 | ||||||
|                                                */ |                                                */ | ||||||
|             args.push_back(program.c_str()); |             args.push_back(program.c_str()); | ||||||
|             args.push_back("get-ownership"); |             args.push_back(command.c_str()); | ||||||
|             args.push_back(path.c_str()); |             args.push_back(arg.c_str()); | ||||||
|             args.push_back(0); |             args.push_back(0); | ||||||
| 
 | 
 | ||||||
|             execve(program.c_str(), (char * *) &args[0], 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) | static void deletePathWrapped(const Path & path) | ||||||
| { | { | ||||||
|     /* When using build users and we're not root, we may not have
 |     /* 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 |        open and modifies them after they have been chown'ed to | ||||||
|        root. */ |        root. */ | ||||||
|     if (buildUser.enabled()) |     if (buildUser.enabled()) | ||||||
|         killUserWrapped(buildUser.getUID()); |         buildUser.kill(); | ||||||
| 
 | 
 | ||||||
|     /* Close the read side of the logger pipe. */ |     /* Close the read side of the logger pipe. */ | ||||||
|     logPipe.readSide.close(); |     logPipe.readSide.close(); | ||||||
|  | @ -1332,7 +1341,7 @@ void DerivationGoal::startBuilder() | ||||||
| 
 | 
 | ||||||
|         /* Make sure that no other processes are executing under this
 |         /* Make sure that no other processes are executing under this
 | ||||||
|            uid. */ |            uid. */ | ||||||
|         killUserWrapped(buildUser.getUID()); |         buildUser.kill(); | ||||||
|          |          | ||||||
|         /* Change ownership of the temporary build directory, if we're
 |         /* Change ownership of the temporary build directory, if we're
 | ||||||
|            root.  If we're not root, then the setuid helper will do it |            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
 | /* Run `program' under user account `targetUser'.  `targetUser' should
 | ||||||
|    be a member of `buildUsersGroup'.  The ownership of the current |    be a member of `buildUsersGroup'.  The ownership of the current | ||||||
|    directory is changed from the Nix user (uidNix) to the target |    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) |     if (uidTargetUser == 0) | ||||||
|         throw Error("won't setuid to root"); |         throw Error("won't setuid to root"); | ||||||
| 
 | 
 | ||||||
|     /* Verify that the target user is a member of that group. */ |     /* Verify that the target user is a member of the build users
 | ||||||
|     if (buildUsers.find(targetUser) == buildUsers.end()) |        group. */ | ||||||
|         throw Error(format("user `%1%' is not a member of the build users group") |     checkIfBuildUser(buildUsers, targetUser); | ||||||
|             % targetUser); |  | ||||||
|      |      | ||||||
|     /* Chown the current directory, *if* it is owned by the Nix
 |     /* Chown the current directory, *if* it is owned by the Nix
 | ||||||
|        account.  The idea is that the current directory is the |        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 | #ifndef NIX_SETUID_CONFIG_FILE | ||||||
| #define NIX_SETUID_CONFIG_FILE "/etc/nix-setuid.conf" | #define NIX_SETUID_CONFIG_FILE "/etc/nix-setuid.conf" | ||||||
| #endif | #endif | ||||||
|  | @ -204,6 +227,12 @@ static void run(int argc, char * * argv) | ||||||
|         secureChown(-1, gidBuildUsers, uidNix, gidBuildUsers, argv[2]); |         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"); |     else throw Error ("invalid command"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue