Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Unprivileged Chroot() (lwn.net)
59 points by rwmj on March 18, 2021 | hide | past | favorite | 46 comments


This just feels like law of unintended consequences waiting to happen. Like the use cases are super cool, like using it with FUSE to basically redirect a file system view. But it feels like asking for trouble. You would need to know the interaction between all manner of systems that could be used to effect an escalation.


I'm intrigued to know if Microsoft (where the patch submitter works) have a use case for this or if it's related to one of his other security projects (see http://digikod.net/). I think it needs a strong motivating case.


For me personally a potential application seems to be embedding general purpose languages as scripting tools within nonprivileged applications; such a chroot would make it easier for the app to grant some filesystem access to a potentially malicious script without trying to restrict the language, API and libraries used for that.


Why not use a mount namespace? And how are you creating a /dev without root?


I feel like you're assuming that mount namespaces are something greater than they actually are. You still need chroot(2) or pivot_root(2) to actually put a process into its own isolated directory. There's no magic here.

Try running `unshare -m` to see what it's like in "just" a mount namespace.


Microsoft OpenSSH is at least faking it.

    4084 2021-03-02 01:08:24.055 fatal: safely_chroot: stat("C:\\sftpjail"): No such file or directory


My reaction:

Why? Oh that makes sense. Wait! Abysmal Security Nightmare! Nooooooo Don't do that, Pleeeeeeease.

One of the main reason is that:

1. It increases the attack surface.

2. At least currently PR_SET_NO_NEW_PRIVS must not be relied on to be perfect for security. Must use cases use it as an additional security layer, but the chroot patch uses it as a fundamental required to be perfect building block.

3. As far as I can tell the benefit it gives is not worth the increased attack surface even if PR_SET_NO_NEW_PRIVS would work perfectly. But I might be wrong.

Honestly the additional constraints it puts on chroot are good and I believe should be fulfilled for must use cases of chroot. So I think best would be either a "CAP_RESTRICTED_CHROOT" capability which allows chroot but only under given circumstances or a prctrl which "degrades" CAP_SYS_CHROOT to only work under given circumstances.

In both cases programs which drop all CAP's they don't need would not be affected by this feature made for programs which use chroot.

But in the current design the sandbox of ALL!!!! sandboxed programs which drop the CAP_SYS_CHROOT capability is weakened. Which IMHO is unreasonable.


The security concerns are overblown because this assumes everyone will start using chroot for everything, which isn't the case. There are plenty of use cases where you intentionally sacrifice security for usability.

What's the danger here, that a program will create a chroot and that an attacker will then break out of it? So we're back to where we are now, which is not using chroots.


> What's the danger here, that a program will create a chroot and that an attacker will then break out of it? So we're back to where we are now, which is not using chroots.

Not quite right

Currently chroot needs privilegs, so a program which runs sandboxed will not ever be able to chroot and will be stuck in the sandbox.

But with that patch a sandboxed program could start a chroot and then use the chroot environment to weaken or escape the sandbox it is in.

So as far as I understand this change will actively weaken the security of all sandboxes which dropped the privilege to do chroot (or never had it), which are most of them.

The main way you could take advantage of it would be in combination with a RCE vulnerability in a software which runs itself in a sandbox.

> which is not using chroots.

Currently we can make sure chroot is not used by making sure no SYS_CAP_CHROOT or similar capability is given. With the patch it will be impossible to make sure chroot is not used!

Because anyone anywhere with anyuser will be able to use it.

Which would be fine with the constraints the patch adds to chroot, but the problem is that it's known that one of the main constraints it adds doesn't work perfectly/has security gaps.

> intentionally sacrifice security for usability.

The problem is that with the patch everyone using various non-vm sandboxing mechanisms will be forced to sacrifice security for usability, it's not a "opt-in for this programs which do care".

Which is why I think putting this behind another capability or similar would be best (one a unprivileged user can have).


One thing i wonder about when reading about the issues of chroot is why they just didn't make "PR_SET_NO_NEW_PRIVS" default of chroot from the beginning and make other ways to strengthen chroot security (because it was after all intended to provide security so why did backwards compatibility trump security?)


PR_SET_NO_NEW_PRIVS was added in Linux 3.5

chroot() is from ancient Unix/BSD times and was in Linux since pretty much the beginning of Linux.

Changing its behavior after the fact would break expected behavior of existing programs AND would break compatibility with other Unixen.


Yes, it'd break compatibility, but mostly compatibility of components added after chroot if I'm not mistaken? Would escaping chroot and/or rooting by tampering with /bin/su(-do) have been possible on these older unices?


Those problems were known before Linux was a thing, which is part of the reasons only root was historically allowed to do a chroot().

Even Unix v7 insists on chroot() being only called by the root user (the chroot syscall is in /usr/sys/sys/sys4.c).


Unixen, is that german?


Interesting. According to the German Wiktionary, yes.

Back in high school (in Austria, speaking German) I've been told several times by a Unix grey beard I had as a teacher that "Unixen" is the preferred plural of Unix, similar to "VAXen" for VAX, which the English Wiktionary does seem to know about.


There's plenty of uses of chroot outside security (i.e. bootstrapping or troubleshooting a broken system), and Linux doesn't break userspace. Ever.


Isn't it just the ABI and basic semantics that is never supposed to be broken? By extending that logic one could say that the kernel should never patch kernel exploits since it'd break things the exploits expects, naturally this is a silly hyperbole and i do understand that the line has to be drawn somewhere but chroot is old and imho additions that has enabled breaking out would have broken the original semantic.

I do see the usage for bootstrapping and troubleshooting so that does cause an issue.


If the Linux kernel does not implement chroot as described below, then it cannot claim to be POSIX-compliant.

Going out of compliance will come at some cost.

https://pubs.opengroup.org/onlinepubs/7908799/xsh/chroot.htm...


I think Linux explicitly claims not to be POSIX compliant because you have to pay for that.


This is what the wiki says. I've never heard of Linux-FT, but I did remember that someone took the certification process all the way.

Linux systems adhere to POSIX,[81] SUS,[82] LSB, ISO, and ANSI standards where possible, although to date only one Linux distribution has been POSIX.1 certified, Linux-FT.[83][84]

https://en.wikipedia.org/wiki/Linux

Archive.org has the supporting documents.

https://web.archive.org/web/20160404122450/http://www.linuxj...

"Unifix GmbH (Braunschweig, Germany) developed a Linux system that has been certified to conform to FIPS 151-2 (a superset of POSIX.1). This technology was available in Unifix' own distribution called Unifix Linux 2.0 and in Lasermoon's Linux-FT."

https://web.archive.org/web/20111010111215/http://www.debian...


Nothing in that spec says anything about the process having the opurtunity to escalate privileges or escaping the chroot after invoking the call to chroot.


Historic reasons (like chroot being older etc.).

But I believe the appropriate solution would be either:

- a prctrl like PR_SET_RESTRICED_CHROOT which will "degrade" CAP_SYS_CHROOT to require all the thinks listed (but still requires CAP_SYS_CHROOT).

- a new capability like CAP_SYS_RESTRICTED_CHROOT (probably not an option).

The current patch would weakening the security sandbox of any process dropping CAP_SYS_CHROOT which IMHO is unacceptable given that PR_SET_NO_NEW_PRIVS is known as being imperfect.


Can't unshare essentially do the same thing?

unshare --map-current-user --root=<new root> <program>

And works completely unprivileged using namespaces.


Be aware that on some distributions such as Debian or RHEL, user namespaces are restricted by default and cannot be used like this from unprivileged user accounts. Although Debian is going to change the default with the next release.

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=898446


If those distros are paranoid about the security implications of user namespaces, then they would certainly apply that reasoning to user chroot.


Interesting.

Still, as namespaces gain more and more traction, the value of adding rootless chroot goes down.



Yes but it does so as the root user in the new user namespace, which is allowed according to existing rules. The change in question is about not requiring root in any user namespace.


Thanks for the link!

In that case, it seems completely arbitrary to not make chroot work as a normal user then.


I custom compiled a kernel to support userland chroot a number of years ago; it was trivial. It served the use case just fine.

There are probably people today who run things in Docker containers as root who are thinking "OMG, this is a horrible idea!".

In the chroot environments I created at the time everything was statically linked and there was nothing else for the program(s) to run. Everything was audited. It didn't start with "it works on my machine, so why can't I ship my machine?" as a premise.


Ahh.... we just need Capsicum/CloudABI for real to end the badness. Security and expressive power one can actually understand.


> If these conditions are met, it is argued, it is safe to allow a process to call chroot().

It is safe only insofar some other software with elevated privileges whose security model assumes that only root can chroot, not run.

This is an issue with security that is had to avoid; some software is written on the assumption that certain things are impossible that may become possible in the future.

It is also why most capabilities are in practice useless as a tool of granularity on the average system and that all capabilities can often be constructed from a subset that is often as large as a single one, as so much software was written and designed before such capabilities existed, under the assumption that, if one have one, one have all.


Maybe chroot is not the right solution, but having unprivileged containers/jails natively supported (not docker/systemd-containerd overlay) sounds useful.


Why not use unveil() (From OpenBSD) for this use case?


That doesn't let you construct an arbitrarily structured virtualized filesystem like chroot does, just hide parts of the existing filesystem


Yes, but wasn't the use case to reduce access, not to fake a new root?


The use case is isolation, which is not necessarily exactly the same as reducing access.

For example, maybe you don't want the process to be able to easily detect that it has had its access reduced, by simulating a full-access environment.

Or for example, maybe you don't care about access at all and you just want to avoid conflicts between two processes by giving them separated namespaces for their data.


Can you elaborate on this please? I'd consider unveil to be far more capable of creating "an arbitrarily structured virtualized filesystem" view than chroot. I'd also invert the thinking of "just hide parts of the existing filesystem" as it whitelists paths and access rather than blacklisting.


How do you bind a /tmp/empty to /home/$USER with unveil, so that you can see and capture the files some program creates?


Sorry I don't quite grok your comment. It sounds like a bind mount so I'm unsure how it relates to unveil or chroot?


Chroot is more or less a bind mount over /. Bind mounts generalize chroot. Unveil does not, and therefore does not allow you to provide arbitrary views of the file system.

It's useful for other reasons. On OpenBSD, a full web browser compromise does not lead to full file system access.


Unveil has no way to change the existing structure of the filesystem. With chroot it's easy: create the structure you want in a subdirectory and then chroot into it


If changing a process root directory is really what you want to do then yes chroot is the right tool for the job. But from a perspective of "jailing" daemons as mentioned in the article I think unveil is a better API.

I'm not sure what pieces of software populate directories and then chroot into them aside from maybe some build systems? But those likely create or bind in some /dev and /proc pieces which would be privileged operations anyway. And in such a case would containers not have surplanted chroot?


"Jailing" isn't necessarily just about security, but isolation in general. Unveil would be a stronger tool if the concern is strictly security, but also there's no reason they couldn't both be used.

Chroot is itself sometimes used to provide container-style functionality, so I think it's wrong to say containers "surplanted" it.


> And in such a case would containers not have surplanted chroot?

Containers use chroot


They don't use fs namespaces?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: