* 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:
Eelco Dolstra 2006-12-07 16:33:31 +00:00
parent ec23ecc64d
commit f76fdb6d42
2 changed files with 69 additions and 31 deletions

View file

@ -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

View file

@ -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");
} }