1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-08 06:53:54 +02:00

Merge pull request #9261 from flokli/backport-3564

[2.3-maintenance] Wait for build users when none are available
This commit is contained in:
John Ericson 2023-11-01 20:01:36 -04:00 committed by GitHub
commit f76990444c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -524,17 +524,24 @@ public:
uid_t getGID() { assert(gid); return gid; } uid_t getGID() { assert(gid); return gid; }
std::vector<gid_t> getSupplementaryGIDs() { return supplementaryGIDs; } std::vector<gid_t> getSupplementaryGIDs() { return supplementaryGIDs; }
bool findFreeUser();
bool enabled() { return uid != 0; } bool enabled() { return uid != 0; }
}; };
Sync<PathSet> UserLock::lockedPaths_; Sync<PathSet> UserLock::lockedPaths_;
UserLock::UserLock() UserLock::UserLock()
{ {
assert(settings.buildUsersGroup != ""); assert(settings.buildUsersGroup != "");
createDirs(settings.nixStateDir + "/userpool");
/* Mark that user is not enabled by default */
uid = 0;
}
bool UserLock::findFreeUser() {
/* Get the members of the build-users-group. */ /* Get the members of the build-users-group. */
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str()); struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
@ -564,7 +571,6 @@ UserLock::UserLock()
throw Error(format("the user '%1%' in the group '%2%' does not exist") throw Error(format("the user '%1%' in the group '%2%' does not exist")
% i % settings.buildUsersGroup); % i % settings.buildUsersGroup);
createDirs(settings.nixStateDir + "/userpool");
fnUserLock = (format("%1%/userpool/%2%") % settings.nixStateDir % pw->pw_uid).str(); fnUserLock = (format("%1%/userpool/%2%") % settings.nixStateDir % pw->pw_uid).str();
@ -605,20 +611,17 @@ UserLock::UserLock()
supplementaryGIDs.resize(ngroups); supplementaryGIDs.resize(ngroups);
#endif #endif
return; return true;
} }
} catch (...) { } catch (...) {
lockedPaths_.lock()->erase(fnUserLock); lockedPaths_.lock()->erase(fnUserLock);
return false;
} }
} }
return false;
throw Error(format("all build users are currently in use; "
"consider creating additional users and adding them to the '%1%' group")
% settings.buildUsersGroup);
} }
UserLock::~UserLock() UserLock::~UserLock()
{ {
auto lockedPaths(lockedPaths_.lock()); auto lockedPaths(lockedPaths_.lock());
@ -626,7 +629,6 @@ UserLock::~UserLock()
lockedPaths->erase(fnUserLock); lockedPaths->erase(fnUserLock);
} }
void UserLock::kill() void UserLock::kill()
{ {
killUser(uid); killUser(uid);
@ -1415,6 +1417,30 @@ void DerivationGoal::tryToBuild()
{ {
trace("trying to build"); trace("trying to build");
/* If `build-users-group' is not empty, then we have to build as
one of the members of that group. */
if (settings.buildUsersGroup != "" && getuid() == 0) {
#if defined(__linux__) || defined(__APPLE__)
if (!buildUser) buildUser = std::make_unique<UserLock>();
if (!buildUser->enabled()) {
if (!buildUser->findFreeUser()) {
debug("waiting for build users");
worker.waitForAWhile(shared_from_this());
return;
}
/* Make sure that no other processes are executing under this
uid. */
buildUser->kill();
}
#else
/* Don't know how to block the creation of setuid/setgid
binaries on this platform. */
throw Error("build users are not supported on this platform for security reasons");
#endif
}
/* Obtain locks on all output paths. The locks are automatically /* Obtain locks on all output paths. The locks are automatically
released when we exit this function or Nix crashes. If we released when we exit this function or Nix crashes. If we
can't acquire the lock, then continue; hopefully some other can't acquire the lock, then continue; hopefully some other
@ -1931,22 +1957,6 @@ void DerivationGoal::startBuilder()
#endif #endif
} }
/* If `build-users-group' is not empty, then we have to build as
one of the members of that group. */
if (settings.buildUsersGroup != "" && getuid() == 0) {
#if defined(__linux__) || defined(__APPLE__)
buildUser = std::make_unique<UserLock>();
/* Make sure that no other processes are executing under this
uid. */
buildUser->kill();
#else
/* Don't know how to block the creation of setuid/setgid
binaries on this platform. */
throw Error("build users are not supported on this platform for security reasons");
#endif
}
/* Create a temporary directory where the build will take /* Create a temporary directory where the build will take
place. */ place. */
auto drvName = storePathToName(drvPath); auto drvName = storePathToName(drvPath);
@ -4465,7 +4475,7 @@ void Worker::waitForInput()
if (!waitingForAWhile.empty()) { if (!waitingForAWhile.empty()) {
useTimeout = true; useTimeout = true;
if (lastWokenUp == steady_time_point::min()) if (lastWokenUp == steady_time_point::min())
printError("waiting for locks or build slots..."); printError("waiting for locks, build slots or build users...");
if (lastWokenUp == steady_time_point::min() || lastWokenUp > before) lastWokenUp = before; if (lastWokenUp == steady_time_point::min() || lastWokenUp > before) lastWokenUp = before;
timeout.tv_sec = std::max(1L, timeout.tv_sec = std::max(1L,
(long) std::chrono::duration_cast<std::chrono::seconds>( (long) std::chrono::duration_cast<std::chrono::seconds>(