* Removed `build-allow-root'.
* Added `build-users-group', the group under which builds are to be performed. * Check that /nix/store has 1775 permission and is owner by the build-users-group.
This commit is contained in:
parent
84d6459bd5
commit
35247c4c9f
|
@ -78,37 +78,46 @@
|
|||
#build-max-jobs = 1
|
||||
|
||||
|
||||
### Option `build-allow-root'
|
||||
#
|
||||
# This option controls Nix's behaviour when it is invoked under the
|
||||
# `root' user (or setuid-root). If `true' (default), builds are
|
||||
# performed under the `root' user. If `false', builds are performed
|
||||
# under one of the users listed in the `build-users' option (see
|
||||
# below).
|
||||
#build-allow-root = true
|
||||
|
||||
|
||||
### Option `build-users'
|
||||
#
|
||||
# This option is only applicable if `build-allow-root' is `false' and
|
||||
# Nix is invoked under the `root' user (or setuid-root). It contains
|
||||
# a list of user names under which Nix can execute builds. Builds
|
||||
# cannot be performed by root since that would allow users to take
|
||||
# over the system by supplying specially crafted builders; and they
|
||||
# cannot be performed by the calling user since that would allow
|
||||
# him/her to influence the build result.
|
||||
# This option contains a list of user names under which Nix can
|
||||
# execute builds. In multi-user Nix installations, builds should not
|
||||
# be performed by the Nix account since that would allow users to
|
||||
# arbitrarily modify the Nix store and database by supplying specially
|
||||
# crafted builders; and they cannot be performed by the calling user
|
||||
# since that would allow him/her to influence the build result.
|
||||
#
|
||||
# Thus this list should contain a number of `special' user accounts
|
||||
# created specifically for Nix, e.g., `nix-builder-1',
|
||||
# `nix-builder-2', and so on. The more users the better, since at
|
||||
# most a number of builds equal to the number of build users can be
|
||||
# started.
|
||||
# running simultaneously.
|
||||
#
|
||||
# If this list is empty, builds will be performed under the Nix
|
||||
# account (that is, the uid under which the Nix daemon runs, or that
|
||||
# owns the setuid nix-worker program).
|
||||
#
|
||||
# Example:
|
||||
# build-users = nix-builder-1 nix-builder-2 nix-builder-3
|
||||
#build-users =
|
||||
|
||||
|
||||
### Option `build-users-group'
|
||||
#
|
||||
# If `build-users' is used, then this option specifies the group ID
|
||||
# (gid) under which each build is to be performed. This group should
|
||||
# have permission to create files in the Nix store, but not delete
|
||||
# them. I.e., /nix/store should be owned by the Nix account, its
|
||||
# group should be the group specified here, and its mode should be
|
||||
# 1775.
|
||||
#
|
||||
# The default is `nix'.
|
||||
#
|
||||
# Example:
|
||||
# build-users-group = nix
|
||||
#build-users-group =
|
||||
|
||||
|
||||
### Option `system'
|
||||
#
|
||||
# This option specifies the canonical Nix system name of the current
|
||||
|
|
|
@ -258,6 +258,8 @@ static void setuidInit()
|
|||
if (setuid(nixUid)) abort();
|
||||
if (setgid(nixGid)) abort();
|
||||
#endif
|
||||
|
||||
setuidMode = true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ namespace nix {
|
|||
Path makeRootName(const Path & gcRoot, int & counter);
|
||||
void printGCWarning();
|
||||
|
||||
/* Whether we're running setuid. */
|
||||
bool setuidMode = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1271,12 +1271,10 @@ void DerivationGoal::startBuilder()
|
|||
}
|
||||
|
||||
|
||||
/* If we are running as root, and the `build-allow-root' setting
|
||||
is `false', then we have to build as one of the users listed in
|
||||
`build-users'. */
|
||||
if (!queryBoolSetting("build-allow-root", true) &&
|
||||
getuid() == rootUserId)
|
||||
{
|
||||
/* If `build-users' is not empty, then we have to build as one of
|
||||
the users listed in `build-users'. */
|
||||
gid_t gidBuildGroup = -1;
|
||||
if (querySetting("build-users", Strings()).size() > 0) {
|
||||
buildUser.acquire();
|
||||
assert(buildUser.getUID() != 0);
|
||||
|
||||
|
@ -1288,6 +1286,14 @@ void DerivationGoal::startBuilder()
|
|||
if (chown(tmpDir.c_str(), buildUser.getUID(), (gid_t) -1) == -1)
|
||||
throw SysError(format("cannot change ownership of `%1%'") % tmpDir);
|
||||
|
||||
/* What group to execute the builder in? */
|
||||
string buildGroup = querySetting("build-users-group", "nix");
|
||||
struct group * gr = getgrnam(buildGroup.c_str());
|
||||
if (!gr) throw Error(
|
||||
format("the group `%1%' specified in `build-users-group' does not exist")
|
||||
% buildGroup);
|
||||
gidBuildGroup = gr->gr_gid;
|
||||
|
||||
/* Check that the Nix store has the appropriate permissions,
|
||||
i.e., owned by root and mode 1777 (sticky bit on so that
|
||||
the builder can create its output but not mess with the
|
||||
|
@ -1295,13 +1301,13 @@ void DerivationGoal::startBuilder()
|
|||
struct stat st;
|
||||
if (stat(nixStore.c_str(), &st) == -1)
|
||||
throw SysError(format("cannot stat `%1%'") % nixStore);
|
||||
if (st.st_uid != rootUserId)
|
||||
throw Error(format("`%1%' is not owned by root") % nixStore);
|
||||
if (!(st.st_mode & S_ISVTX) ||
|
||||
((st.st_mode & S_IRWXO) != S_IRWXO))
|
||||
((st.st_mode & S_IRWXG) != S_IRWXG) ||
|
||||
(st.st_gid != gidBuildGroup))
|
||||
throw Error(format(
|
||||
"builder does not have write permission to `%1%'; "
|
||||
"try `chmod 1777 %1%'") % nixStore);
|
||||
"try `chgrp %1% %2%; chmod 1775 %2%'")
|
||||
% buildGroup % nixStore);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1343,23 +1349,25 @@ void DerivationGoal::startBuilder()
|
|||
envStrs.push_back(i->first + "=" + i->second);
|
||||
const char * * envArr = strings2CharPtrs(envStrs);
|
||||
|
||||
/* If we are running as root and `build-allow-root' is
|
||||
`false', then switch to the user we allocated above.
|
||||
Make sure that we drop all root privileges. Note that
|
||||
initChild() above has closed all file descriptors
|
||||
except std*, so that's safe. Also note that setuid()
|
||||
when run as root sets the real, effective and saved
|
||||
UIDs. */
|
||||
/* If we are running in `build-users' mode, then switch to
|
||||
the user we allocated above. Make sure that we drop
|
||||
all root privileges. Note that initChild() above has
|
||||
closed all file descriptors except std*, so that's
|
||||
safe. Also note that setuid() when run as root sets
|
||||
the real, effective and saved UIDs. */
|
||||
if (buildUser.getUID() != 0) {
|
||||
printMsg(lvlError, format("switching to uid `%1%'") % buildUser.getUID());
|
||||
|
||||
/* !!! setgid also */
|
||||
if (setgroups(0, 0) == -1)
|
||||
throw SysError("cannot clear the set of supplementary groups");
|
||||
|
||||
setuid(buildUser.getUID());
|
||||
assert(getuid() == buildUser.getUID());
|
||||
assert(geteuid() == buildUser.getUID());
|
||||
|
||||
setgid(gidBuildGroup);
|
||||
assert(getgid() == gidBuildGroup);
|
||||
assert(getegid() == gidBuildGroup);
|
||||
}
|
||||
|
||||
/* Execute the program. This should not return. */
|
||||
|
|
|
@ -235,10 +235,10 @@ void canonicalisePathMetaData(const Path & path)
|
|||
throw SysError(format("changing mode of `%1%' to %2$o") % path % mode);
|
||||
}
|
||||
|
||||
if (st.st_uid != getuid() || st.st_gid != getgid()) {
|
||||
if (chown(path.c_str(), getuid(), getgid()) == -1)
|
||||
if (st.st_uid != geteuid() || st.st_gid != getegid()) {
|
||||
if (chown(path.c_str(), geteuid(), getegid()) == -1)
|
||||
throw SysError(format("changing owner/group of `%1%' to %2%/%3%")
|
||||
% path % getuid() % getgid());
|
||||
% path % geteuid() % getegid());
|
||||
}
|
||||
|
||||
if (st.st_mtime != 0) {
|
||||
|
|
Loading…
Reference in a new issue