Sandbox: Fix /dev/ptmx on recent kernels

This fixes "No such file or directory" when opening /dev/ptmx
(e.g. http://hydra.nixos.org/build/51094249).

The reason appears to be some changes to /dev/ptmx / /dev/pts handling
between Linux 4.4 and 4.9. See
https://patchwork.kernel.org/patch/7832531/.

The fix is to go back to mounting a proper /dev/pts instance inside
the sandbox. Happily, this now works inside user namespaces, even for
unprivileged users. So

  NIX_REMOTE=local?root=/tmp/nix nix-build \
    '<nixpkgs/nixos/tests/misc.nix>' -A test

works for non-root users.

The downside is that the fix breaks sandbox builds on older kernels
(probably pre-4.6), since mounting a devpts fails inside user
namespaces for some reason I've never been able to figure out. Builds
on those systems will fail with

  error: while setting up the build environment: mounting /dev/pts: Invalid argument

Ah well.
This commit is contained in:
Eelco Dolstra 2017-03-31 18:12:01 +02:00
parent 3ecb09a40a
commit 29d35805c6
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE

View file

@ -2391,8 +2391,6 @@ void DerivationGoal::runChild()
ss.push_back("/dev/tty"); ss.push_back("/dev/tty");
ss.push_back("/dev/urandom"); ss.push_back("/dev/urandom");
ss.push_back("/dev/zero"); ss.push_back("/dev/zero");
ss.push_back("/dev/ptmx");
ss.push_back("/dev/pts");
createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd"); createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd");
createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin"); createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin");
createSymlink("/proc/self/fd/1", chrootRootDir + "/dev/stdout"); createSymlink("/proc/self/fd/1", chrootRootDir + "/dev/stdout");
@ -2448,17 +2446,13 @@ void DerivationGoal::runChild()
fmt("size=%s", settings.get("sandbox-dev-shm-size", std::string("50%"))).c_str()) == -1) fmt("size=%s", settings.get("sandbox-dev-shm-size", std::string("50%"))).c_str()) == -1)
throw SysError("mounting /dev/shm"); throw SysError("mounting /dev/shm");
#if 0
// FIXME: can't figure out how to do this in a user
// namespace.
/* Mount a new devpts on /dev/pts. Note that this /* Mount a new devpts on /dev/pts. Note that this
requires the kernel to be compiled with requires the kernel to be compiled with
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y (which is the case CONFIG_DEVPTS_MULTIPLE_INSTANCES=y (which is the case
if /dev/ptx/ptmx exists). */ if /dev/ptx/ptmx exists). */
if (pathExists("/dev/pts/ptmx") && if (pathExists("/dev/pts/ptmx") &&
!pathExists(chrootRootDir + "/dev/ptmx") !pathExists(chrootRootDir + "/dev/ptmx")
&& dirsInChroot.find("/dev/pts") == dirsInChroot.end()) && !dirsInChroot.count("/dev/pts"))
{ {
if (mount("none", (chrootRootDir + "/dev/pts").c_str(), "devpts", 0, "newinstance,mode=0620") == -1) if (mount("none", (chrootRootDir + "/dev/pts").c_str(), "devpts", 0, "newinstance,mode=0620") == -1)
throw SysError("mounting /dev/pts"); throw SysError("mounting /dev/pts");
@ -2468,7 +2462,6 @@ void DerivationGoal::runChild()
Linux versions, it is created with permissions 0. */ Linux versions, it is created with permissions 0. */
chmod_(chrootRootDir + "/dev/pts/ptmx", 0666); chmod_(chrootRootDir + "/dev/pts/ptmx", 0666);
} }
#endif
/* Do the chroot(). */ /* Do the chroot(). */
if (chdir(chrootRootDir.c_str()) == -1) if (chdir(chrootRootDir.c_str()) == -1)