2023-01-27 17:52:01 +02:00
|
|
|
#if __linux__
|
|
|
|
|
2023-01-25 18:31:27 +02:00
|
|
|
#include "namespaces.hh"
|
|
|
|
#include "util.hh"
|
2023-01-27 16:25:56 +02:00
|
|
|
#include "finally.hh"
|
|
|
|
|
2023-02-10 15:38:14 +02:00
|
|
|
#include <sys/mount.h>
|
2023-01-25 18:31:27 +02:00
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
bool userNamespacesSupported()
|
|
|
|
{
|
2023-01-27 16:25:56 +02:00
|
|
|
static auto res = [&]() -> bool
|
2023-01-25 18:31:27 +02:00
|
|
|
{
|
|
|
|
if (!pathExists("/proc/self/ns/user")) {
|
2023-01-27 16:25:56 +02:00
|
|
|
debug("'/proc/self/ns/user' does not exist; your kernel was likely built without CONFIG_USER_NS=y");
|
2023-01-25 18:31:27 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Path maxUserNamespaces = "/proc/sys/user/max_user_namespaces";
|
|
|
|
if (!pathExists(maxUserNamespaces) ||
|
|
|
|
trim(readFile(maxUserNamespaces)) == "0")
|
|
|
|
{
|
2023-01-27 16:25:56 +02:00
|
|
|
debug("user namespaces appear to be disabled; check '/proc/sys/user/max_user_namespaces'");
|
2023-01-25 18:31:27 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Path procSysKernelUnprivilegedUsernsClone = "/proc/sys/kernel/unprivileged_userns_clone";
|
|
|
|
if (pathExists(procSysKernelUnprivilegedUsernsClone)
|
|
|
|
&& trim(readFile(procSysKernelUnprivilegedUsernsClone)) == "0")
|
|
|
|
{
|
2023-01-27 16:25:56 +02:00
|
|
|
debug("user namespaces appear to be disabled; check '/proc/sys/kernel/unprivileged_userns_clone'");
|
2023-01-25 18:31:27 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-02-10 15:38:14 +02:00
|
|
|
try {
|
|
|
|
Pid pid = startProcess([&]()
|
|
|
|
{
|
|
|
|
_exit(0);
|
|
|
|
}, {
|
|
|
|
.cloneFlags = CLONE_NEWUSER
|
|
|
|
});
|
|
|
|
|
|
|
|
auto r = pid.wait();
|
|
|
|
assert(!r);
|
|
|
|
} catch (SysError & e) {
|
|
|
|
debug("user namespaces do not work on this system: %s", e.msg());
|
|
|
|
return false;
|
|
|
|
}
|
2023-02-08 00:01:39 +02:00
|
|
|
|
2023-02-10 15:38:14 +02:00
|
|
|
return true;
|
2023-01-25 18:31:27 +02:00
|
|
|
}();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-02-10 15:38:14 +02:00
|
|
|
bool mountAndPidNamespacesSupported()
|
2023-01-27 16:25:56 +02:00
|
|
|
{
|
|
|
|
static auto res = [&]() -> bool
|
|
|
|
{
|
2023-02-10 15:38:14 +02:00
|
|
|
try {
|
|
|
|
|
|
|
|
Pid pid = startProcess([&]()
|
|
|
|
{
|
|
|
|
/* Make sure we don't remount the parent's /proc. */
|
|
|
|
if (mount(0, "/", 0, MS_PRIVATE | MS_REC, 0) == -1)
|
|
|
|
_exit(1);
|
|
|
|
|
|
|
|
/* Test whether we can remount /proc. The kernel disallows
|
|
|
|
this if /proc is not fully visible, i.e. if there are
|
|
|
|
filesystems mounted on top of files inside /proc. See
|
|
|
|
https://lore.kernel.org/lkml/87tvsrjai0.fsf@xmission.com/T/. */
|
|
|
|
if (mount("none", "/proc", "proc", 0, 0) == -1)
|
|
|
|
_exit(2);
|
|
|
|
|
|
|
|
_exit(0);
|
|
|
|
}, {
|
|
|
|
.cloneFlags = CLONE_NEWNS | CLONE_NEWPID | (userNamespacesSupported() ? CLONE_NEWUSER : 0)
|
|
|
|
});
|
|
|
|
|
|
|
|
if (pid.wait()) {
|
|
|
|
debug("PID namespaces do not work on this system: cannot remount /proc");
|
2023-01-27 16:25:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-02-10 15:38:14 +02:00
|
|
|
} catch (SysError & e) {
|
|
|
|
debug("mount namespaces do not work on this system: %s", e.msg());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-01-27 16:25:56 +02:00
|
|
|
return true;
|
|
|
|
}();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-01-25 18:31:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|