Microsoft Proposes Unprivileged Chroot On Linux
Microsoft engineer Mickaël Salaün has re-proposed a Linux kernel patch from 2012 that allows processes without the
CAP_SYS_CHROOT capability to use the chroot system call. Other kernel developers are not amused.
Software running on Linux can't just
chroot willy nilly, only processes with teh
CAP_SYS_CHROOT capability are allowed to do that. Microsoft developer Mickaël Salaün has re-proposed a patch, originally written by Andy Lutomirski in 2012, that would allow unprivileged users to run any program with the
no_new_privs (No New Privileges Flag) bit set to use
chroot as well.
"The chroot system call is currently limited to be used by processes with the CAP_SYS_CHROOT capability. This protects against malicious procesess willing to trick SUID-like binaries. The following patch allows unprivileged users to safely use chroot(2)."
Mickaël Salaün argues that the patch would allow
chroot to be safely used for security-purposes in new ways as long as other security measures are taken.
"Being able to easily change root directories enable to ease some development workflow and can be used as a tool to strengthen unprivileged security sandboxes. chroot(2) is not an access-control mechanism per se, but it can be used to limit the absolute view of the filesystem, and then limit ways to access data and kernel interfaces (e.g. /proc, /sys, /dev, etc.).
Users may not wish to expose namespace complexity to potentially malicious processes, or limit their use because of limited resources. The chroot feature is much more simple (and limited) than the mount namespace, but can still be useful. As for containers, users of chroot(2) should take care of file descriptors or data accessible by other means (e.g. current working directory, leaked FDs, passed FDs, devices, mount points, etc.). There is a lot of literature that discuss the limitations of chroot, and users of this feature should be aware of the multiple ways to bypass it. Using chroot(2) for security purposes can make sense if it is combined with other features (e.g. dedicated user, seccomp, LSM access-controls, etc.).
One could argue that chroot(2) is useless without a properly populated root hierarchy (i.e. without /dev and /proc). However, there are multiple use cases that don't require the chrooting process to create file hierarchies with special files nor mount points, e.g.:
- A process sandboxing itself, once all its libraries are loaded, may not need files other than regular files, or even no file at all.
- Some pre-populated root hierarchies could be used to chroot into, provided for instance by development environments or tailored distributions.
- Processes executed in a chroot may not require access to these special files (e.g. with minimal runtimes, or by emulating some special files with a LD_PRELOADed library or seccomp).
Allowing a task to change its own root directory is not a threat to the system if we can prevent confused deputy attacks, which could be performed through execution of SUID-like binaries. This can be prevented if the calling task sets PR_SET_NO_NEW_PRIVS on itself with prctl(2). To only affect this task, its filesystem information must not be shared with other tasks, which can be achieved by not passing CLONE_FS to clone(2). A similar no_new_privs check is already used by seccomp to avoid the same kind of security issues. Furthermore, because of its security use and to avoid giving a new way for attackers to get out of a chroot (e.g. using /proc/<pid>/root), an unprivileged chroot is only allowed if the new root directory is the same or beneath the current one. This still allows a process to use a subset of its legitimate filesystem to chroot into and then further reduce its view of the filesystem.
This change may not impact systems relying on other permission models than POSIX capabilities (e.g. Tomoyo). Being able to use chroot(2) on such systems may require to update their security policies.
Only the chroot system call is relaxed with this no_new_privs check; the init_chroot() helper doesn't require such change.
Allowing unprivileged users to use chroot(2) is one of the initial objectives of no_new_privs: https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html"
Long-time kernel developer Eric W. Biederman from Arista Networks, who literally wrote the book on Virtual servers and checkpoint/restart in mainstream Linux, was not amused.
"I don't see the point of allowing chroot once you are in your locked down sandbox.
Last time I remember talking architecture we agreed that user namespaces would be used for enabling features and that no_new_privs would just be used to lock-down userspace. That way no_new_privs could be kept simple and trivial to audit and understand.
You can build your sandbox and use chroot if you use a user namespace at the start. A mount namespace would also help lock things down. Still allowing chroot after the sanbox has been built, a seccomp filter has been installed and no_new_privs has been enabled seems like it is asking for trouble and may weaken existing sandboxes.
So I think we need a pretty compelling use case to consider allowing chroot(2). You haven't even mentioned what your usecase is at this point so I don't know why we would tackle that complexity."
Intel engineer Casey Schaufler, who has worked on Unix and Unix-like kernels since the 1970s, was also skeptical to the proposed change to the Linux
chroot system. He noted that
no_new_privs isn't something code should rely too much on because it is "imperfect". He had this to say on the Linux kernel mailing list:
"Mount namespaces have pretty well obsoleted chroot(). CAP_SYS_CHROOT is one of the few fine grained capabilities. We're still finding edge cases (e.g. ptrace) where no_new_privs is imperfect. I doesn't seem that there is a compelling reason to remove the privilege requirement on chroot()."
chroot patch by Andy Lutomirski from 2012 would fundamentally change how
chroot works on Linux even though the patch itself is rather small. The patch did not pass the smell test in 2012 and it would appear that the more seasoned kernel developers are as unhappy with the proposal today as they were nine years ago. It seems unlikely that this (re-)proposal will get approved by Linus Torvalds or even reach him (kernel patches are screened several times before they reach Torvalds so he can make a final decision).