diff --git a/src/libstore/include/nix/store/globals.hh b/src/libstore/include/nix/store/globals.hh index afa01413eba..c3542d0979b 100644 --- a/src/libstore/include/nix/store/globals.hh +++ b/src/libstore/include/nix/store/globals.hh @@ -178,9 +178,31 @@ public: {"build-compress-log"}}; }; -class Settings : public virtual Config, private GCSettings, private LogFileSettings +struct AutoAllocateUidSettings : public virtual Config { + Setting startId{ + this, +#ifdef __linux__ + 0x34000000, +#else + 56930, +#endif + "start-id", + "The first UID and GID to use for dynamic ID allocation."}; + Setting uidCount{ + this, +#ifdef __linux__ + maxIdsPerBuild * 128, +#else + 128, +#endif + "id-count", + "The number of UIDs/GIDs to use for dynamic ID allocation."}; +}; + +class Settings : public virtual Config, private AutoAllocateUidSettings, private GCSettings, private LogFileSettings +{ StringSet getDefaultSystemFeatures(); StringSet getDefaultExtraPlatforms(); @@ -219,6 +241,15 @@ public: return *this; } + /** + * Get AutoAllocateUidSettings if auto-allocate-uids is enabled. + * @return Pointer to settings if enabled, nullptr otherwise. + */ + const AutoAllocateUidSettings * getAutoAllocateUidSettings() const + { + return autoAllocateUids ? this : nullptr; + } + static unsigned int getDefaultCores(); /** @@ -658,26 +689,6 @@ public: true, Xp::AutoAllocateUids}; - Setting startId{ - this, -#ifdef __linux__ - 0x34000000, -#else - 56930, -#endif - "start-id", - "The first UID and GID to use for dynamic ID allocation."}; - - Setting uidCount{ - this, -#ifdef __linux__ - maxIdsPerBuild * 128, -#else - 128, -#endif - "id-count", - "The number of UIDs/GIDs to use for dynamic ID allocation."}; - #ifdef __linux__ Setting useCgroups{ this, diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index 9da51643d2f..f0f57fea3ff 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -235,7 +235,7 @@ class DerivationBuilderImpl : public DerivationBuilder, public DerivationBuilder */ virtual std::unique_ptr getBuildUser() { - return acquireUserLock(1, false); + return acquireUserLock(settings.buildUsersGroup, 1, false); } /** diff --git a/src/libstore/unix/build/linux-derivation-builder.cc b/src/libstore/unix/build/linux-derivation-builder.cc index c16c9ef8e59..1012a07344a 100644 --- a/src/libstore/unix/build/linux-derivation-builder.cc +++ b/src/libstore/unix/build/linux-derivation-builder.cc @@ -215,7 +215,7 @@ struct ChrootLinuxDerivationBuilder : ChrootDerivationBuilder, LinuxDerivationBu std::unique_ptr getBuildUser() override { - return acquireUserLock(drvOptions.useUidRange(drv) ? 65536 : 1, true); + return acquireUserLock(settings.buildUsersGroup, drvOptions.useUidRange(drv) ? 65536 : 1, true); } void prepareUser() override diff --git a/src/libstore/unix/include/nix/store/user-lock.hh b/src/libstore/unix/include/nix/store/user-lock.hh index 828980d6fdb..1f7e2af31a4 100644 --- a/src/libstore/unix/include/nix/store/user-lock.hh +++ b/src/libstore/unix/include/nix/store/user-lock.hh @@ -36,7 +36,7 @@ struct UserLock * Acquire a user lock for a UID range of size `nrIds`. Note that this * may return nullptr if no user is available. */ -std::unique_ptr acquireUserLock(uid_t nrIds, bool useUserNamespace); +std::unique_ptr acquireUserLock(const std::string & userGroup, uid_t nrIds, bool useUserNamespace); bool useBuildUsers(); diff --git a/src/libstore/unix/user-lock.cc b/src/libstore/unix/user-lock.cc index c5e6455e8d9..c324addac46 100644 --- a/src/libstore/unix/user-lock.cc +++ b/src/libstore/unix/user-lock.cc @@ -64,15 +64,15 @@ struct SimpleUserLock : UserLock return supplementaryGIDs; } - static std::unique_ptr acquire() + static std::unique_ptr + acquire(const std::filesystem::path & userPoolDir, const std::string & buildUsersGroup) { - assert(settings.buildUsersGroup != ""); - createDirs(settings.nixStateDir + "/userpool"); + assert(buildUsersGroup != ""); /* Get the members of the build-users-group. */ - struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str()); + struct group * gr = getgrnam(buildUsersGroup.c_str()); if (!gr) - throw Error("the group '%s' specified in 'build-users-group' does not exist", settings.buildUsersGroup); + throw Error("the group '%s' specified in 'build-users-group' does not exist", buildUsersGroup); /* Copy the result of getgrnam. */ Strings users; @@ -82,7 +82,7 @@ struct SimpleUserLock : UserLock } if (users.empty()) - throw Error("the build users group '%s' has no members", settings.buildUsersGroup); + throw Error("the build users group '%s' has no members", buildUsersGroup); /* Find a user account that isn't currently in use for another build. */ @@ -91,13 +91,13 @@ struct SimpleUserLock : UserLock struct passwd * pw = getpwnam(i.c_str()); if (!pw) - throw Error("the user '%s' in the group '%s' does not exist", i, settings.buildUsersGroup); + throw Error("the user '%s' in the group '%s' does not exist", i, buildUsersGroup); - auto fnUserLock = fmt("%s/userpool/%s", settings.nixStateDir, pw->pw_uid); + auto fnUserLock = userPoolDir / std::to_string(pw->pw_uid); AutoCloseFD fd = open(fnUserLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600); if (!fd) - throw SysError("opening user lock '%s'", fnUserLock); + throw SysError("opening user lock %s", PathFmt(fnUserLock)); if (lockFile(fd.get(), ltWrite, false)) { auto lock = std::make_unique(); @@ -108,7 +108,7 @@ struct SimpleUserLock : UserLock /* Sanity check... */ if (lock->uid == getuid() || lock->uid == geteuid()) - throw Error("the Nix user should not be a member of '%s'", settings.buildUsersGroup); + throw Error("the Nix user should not be a member of '%s'", buildUsersGroup); #ifdef __linux__ /* Get the list of supplementary groups of this user. This is @@ -158,36 +158,37 @@ struct AutoUserLock : UserLock return {}; } - static std::unique_ptr acquire(uid_t nrIds, bool useUserNamespace) + static std::unique_ptr acquire( + const std::filesystem::path & userPoolDir, + const std::string & buildUsersGroup, + uid_t nrIds, + bool useUserNamespace, + const AutoAllocateUidSettings & uidSettings) { #if !defined(__linux__) useUserNamespace = false; #endif experimentalFeatureSettings.require(Xp::AutoAllocateUids); - assert(settings.startId > 0); - assert(settings.uidCount % maxIdsPerBuild == 0); - assert((uint64_t) settings.startId + (uint64_t) settings.uidCount <= std::numeric_limits::max()); + assert(uidSettings.startId > 0); + assert(uidSettings.uidCount % maxIdsPerBuild == 0); + assert((uint64_t) uidSettings.startId + (uint64_t) uidSettings.uidCount <= std::numeric_limits::max()); assert(nrIds <= maxIdsPerBuild); - createDirs(settings.nixStateDir + "/userpool2"); - - size_t nrSlots = settings.uidCount / maxIdsPerBuild; + size_t nrSlots = uidSettings.uidCount / maxIdsPerBuild; for (size_t i = 0; i < nrSlots; i++) { debug("trying user slot '%d'", i); - createDirs(settings.nixStateDir + "/userpool2"); - - auto fnUserLock = fmt("%s/userpool2/slot-%d", settings.nixStateDir, i); + auto fnUserLock = userPoolDir / fmt("slot-%d", i); AutoCloseFD fd = open(fnUserLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600); if (!fd) - throw SysError("opening user lock '%s'", fnUserLock); + throw SysError("opening user lock %s", PathFmt(fnUserLock)); if (lockFile(fd.get(), ltWrite, false)) { - auto firstUid = settings.startId + i * maxIdsPerBuild; + auto firstUid = uidSettings.startId + i * maxIdsPerBuild; auto pw = getpwuid(firstUid); if (pw) @@ -199,10 +200,9 @@ struct AutoUserLock : UserLock if (useUserNamespace) lock->firstGid = firstUid; else { - struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str()); + struct group * gr = getgrnam(buildUsersGroup.c_str()); if (!gr) - throw Error( - "the group '%s' specified in 'build-users-group' does not exist", settings.buildUsersGroup); + throw Error("the group '%s' specified in 'build-users-group' does not exist", buildUsersGroup); lock->firstGid = gr->gr_gid; } lock->nrIds = nrIds; @@ -214,12 +214,17 @@ struct AutoUserLock : UserLock } }; -std::unique_ptr acquireUserLock(uid_t nrIds, bool useUserNamespace) +std::unique_ptr acquireUserLock(const std::string & userGroup, uid_t nrIds, bool useUserNamespace) { - if (settings.autoAllocateUids) - return AutoUserLock::acquire(nrIds, useUserNamespace); - else - return SimpleUserLock::acquire(); + if (auto * uidSettings = settings.getAutoAllocateUidSettings()) { + auto userPoolDir = std::filesystem::path{settings.nixStateDir} / "userpool2"; + createDirs(userPoolDir); + return AutoUserLock::acquire(userPoolDir, userGroup, nrIds, useUserNamespace, *uidSettings); + } else { + auto userPoolDir = std::filesystem::path{settings.nixStateDir} / "userpool"; + createDirs(userPoolDir); + return SimpleUserLock::acquire(userPoolDir, userGroup); + } } bool useBuildUsers()