mirror of
https://github.com/NixOS/nix.git
synced 2024-11-27 09:12:40 +00:00
* 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
|
#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'
|
### Option `build-users'
|
||||||
#
|
#
|
||||||
# This option is only applicable if `build-allow-root' is `false' and
|
# This option contains a list of user names under which Nix can
|
||||||
# Nix is invoked under the `root' user (or setuid-root). It contains
|
# execute builds. In multi-user Nix installations, builds should not
|
||||||
# a list of user names under which Nix can execute builds. Builds
|
# be performed by the Nix account since that would allow users to
|
||||||
# cannot be performed by root since that would allow users to take
|
# arbitrarily modify the Nix store and database by supplying specially
|
||||||
# over the system by supplying specially crafted builders; and they
|
# crafted builders; and they cannot be performed by the calling user
|
||||||
# cannot be performed by the calling user since that would allow
|
# since that would allow him/her to influence the build result.
|
||||||
# him/her to influence the build result.
|
|
||||||
#
|
#
|
||||||
# Thus this list should contain a number of `special' user accounts
|
# Thus this list should contain a number of `special' user accounts
|
||||||
# created specifically for Nix, e.g., `nix-builder-1',
|
# created specifically for Nix, e.g., `nix-builder-1',
|
||||||
# `nix-builder-2', and so on. The more users the better, since at
|
# `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
|
# 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:
|
# Example:
|
||||||
# build-users = nix-builder-1 nix-builder-2 nix-builder-3
|
# build-users = nix-builder-1 nix-builder-2 nix-builder-3
|
||||||
#build-users =
|
#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'
|
### Option `system'
|
||||||
#
|
#
|
||||||
# This option specifies the canonical Nix system name of the current
|
# This option specifies the canonical Nix system name of the current
|
||||||
|
@ -258,6 +258,8 @@ static void setuidInit()
|
|||||||
if (setuid(nixUid)) abort();
|
if (setuid(nixUid)) abort();
|
||||||
if (setgid(nixGid)) abort();
|
if (setgid(nixGid)) abort();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
setuidMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +24,9 @@ namespace nix {
|
|||||||
Path makeRootName(const Path & gcRoot, int & counter);
|
Path makeRootName(const Path & gcRoot, int & counter);
|
||||||
void printGCWarning();
|
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
|
/* If `build-users' is not empty, then we have to build as one of
|
||||||
is `false', then we have to build as one of the users listed in
|
the users listed in `build-users'. */
|
||||||
`build-users'. */
|
gid_t gidBuildGroup = -1;
|
||||||
if (!queryBoolSetting("build-allow-root", true) &&
|
if (querySetting("build-users", Strings()).size() > 0) {
|
||||||
getuid() == rootUserId)
|
|
||||||
{
|
|
||||||
buildUser.acquire();
|
buildUser.acquire();
|
||||||
assert(buildUser.getUID() != 0);
|
assert(buildUser.getUID() != 0);
|
||||||
|
|
||||||
@ -1288,6 +1286,14 @@ void DerivationGoal::startBuilder()
|
|||||||
if (chown(tmpDir.c_str(), buildUser.getUID(), (gid_t) -1) == -1)
|
if (chown(tmpDir.c_str(), buildUser.getUID(), (gid_t) -1) == -1)
|
||||||
throw SysError(format("cannot change ownership of `%1%'") % tmpDir);
|
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,
|
/* Check that the Nix store has the appropriate permissions,
|
||||||
i.e., owned by root and mode 1777 (sticky bit on so that
|
i.e., owned by root and mode 1777 (sticky bit on so that
|
||||||
the builder can create its output but not mess with the
|
the builder can create its output but not mess with the
|
||||||
@ -1295,13 +1301,13 @@ void DerivationGoal::startBuilder()
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(nixStore.c_str(), &st) == -1)
|
if (stat(nixStore.c_str(), &st) == -1)
|
||||||
throw SysError(format("cannot stat `%1%'") % nixStore);
|
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) ||
|
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(
|
throw Error(format(
|
||||||
"builder does not have write permission to `%1%'; "
|
"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);
|
envStrs.push_back(i->first + "=" + i->second);
|
||||||
const char * * envArr = strings2CharPtrs(envStrs);
|
const char * * envArr = strings2CharPtrs(envStrs);
|
||||||
|
|
||||||
/* If we are running as root and `build-allow-root' is
|
/* If we are running in `build-users' mode, then switch to
|
||||||
`false', then switch to the user we allocated above.
|
the user we allocated above. Make sure that we drop
|
||||||
Make sure that we drop all root privileges. Note that
|
all root privileges. Note that initChild() above has
|
||||||
initChild() above has closed all file descriptors
|
closed all file descriptors except std*, so that's
|
||||||
except std*, so that's safe. Also note that setuid()
|
safe. Also note that setuid() when run as root sets
|
||||||
when run as root sets the real, effective and saved
|
the real, effective and saved UIDs. */
|
||||||
UIDs. */
|
|
||||||
if (buildUser.getUID() != 0) {
|
if (buildUser.getUID() != 0) {
|
||||||
printMsg(lvlError, format("switching to uid `%1%'") % buildUser.getUID());
|
printMsg(lvlError, format("switching to uid `%1%'") % buildUser.getUID());
|
||||||
|
|
||||||
/* !!! setgid also */
|
|
||||||
if (setgroups(0, 0) == -1)
|
if (setgroups(0, 0) == -1)
|
||||||
throw SysError("cannot clear the set of supplementary groups");
|
throw SysError("cannot clear the set of supplementary groups");
|
||||||
|
|
||||||
setuid(buildUser.getUID());
|
setuid(buildUser.getUID());
|
||||||
assert(getuid() == buildUser.getUID());
|
assert(getuid() == buildUser.getUID());
|
||||||
assert(geteuid() == buildUser.getUID());
|
assert(geteuid() == buildUser.getUID());
|
||||||
|
|
||||||
|
setgid(gidBuildGroup);
|
||||||
|
assert(getgid() == gidBuildGroup);
|
||||||
|
assert(getegid() == gidBuildGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Execute the program. This should not return. */
|
/* 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);
|
throw SysError(format("changing mode of `%1%' to %2$o") % path % mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st.st_uid != getuid() || st.st_gid != getgid()) {
|
if (st.st_uid != geteuid() || st.st_gid != getegid()) {
|
||||||
if (chown(path.c_str(), getuid(), getgid()) == -1)
|
if (chown(path.c_str(), geteuid(), getegid()) == -1)
|
||||||
throw SysError(format("changing owner/group of `%1%' to %2%/%3%")
|
throw SysError(format("changing owner/group of `%1%' to %2%/%3%")
|
||||||
% path % getuid() % getgid());
|
% path % geteuid() % getegid());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st.st_mtime != 0) {
|
if (st.st_mtime != 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user