Live data from Hacker News

The Quest to Secure chown and symlinks

buildkite.com

21–29 of 29 posts

Re: The Quest to Secure chown and symlinks

#21

This just cements my conviction that file systems not having transactional operations is a huge omission nowadays. It really is time to start having file systems that are not just huge mutable spaces, and be more like proper ACID databases. I hope somebody is working on it because as things are going in the last years, I'd be retired before I have the time for it.

How does that solve the problem of links pointing places where you don’t expect them to, or any of the other issues in this article? The problem here is trying to cross a security boundary where your only tool is shell scripting. That’s just basically impossible to do securely. Use a real programming language, follow the rules required to make it secure and do all the checks you need to.

It would solve it by disallowing changing of the underlying path from a symlink to a file (and vice versa) while a transaction to do a `chown` is still underway.

Though that would require much more than just ACID semantics but also proper user / jail isolation.

Re: The Quest to Secure chown and symlinks

#22
post #11

I have a small project in this approximate area: https://www.kylheku.com/cgit/safepath/about/ safepath is a function which tries to analyze whether a path is safe to use. Roughly that means that it doesn't resolve in some way that can be controlled by another (non-root) user. A something similar to this is in TXR Lisp under the name path-components-safe: https://www.kylheku.com/cgit/txr/tree/stdlib/path-test.tl?hl...

This seems to still be vulnerable to TOCTOU? Tho, to be fair, it's probably an improvement by narrowing how simple it is to exploit relative to doing nothing.

I'm not going to sit there claiming it's not vulnerable to anything.

But, assuming it does what it's supposed to, the inherent semantics of the check is supposed to eliminate TOCtoTOU.

The reason is that if we validate, from left to right, that no part of the path is under the control of adversaries, then nothing can happen to that path between the time of check and time of use.

(At least nothing that isn't self-inflicted, which would be outside of the scope. If root checks a path for safety, but root itself has a parallel task going on which changes the permissions or symbolic links in ways that affect the security status of that path, we can regard that as root's self-inflicted problem. That's nearly the same as the ever-present threat that a careless sysadmin might "chmod 777" an sensitive file.)

In fact, development of this function was motivated by exploring the question: can we do security checks on a path in such a way that if the answer is affirmative, it continues to tell the truth moments later, when the same path is accessed?

Re: The Quest to Secure chown and symlinks

#23
post #16
post #2

test -L checks if a file is a symlink; no need for realpath comparisons (which is slower)

Yeah but what do you do if your are not using shell? Hint: it's stat(2) (or equivalent in your language library) Additional hint: if using pythons os.stat set follow_symlinks to false. It recently took me an embarrassing long time to figure out why my script was failing to find symlinks.

but they were using a shell script in this blog though (and, yes, stat(2) is the way to go there)

Re: The Quest to Secure chown and symlinks

#24
post #7

why is it running as root anyway? should probably setuid to the correct user and do the thing there instead

Well in some cases avoiding root might help. But you can have flaws like this root or not, for example Apache httpd still has a known TOCTOU vulnerability with symlinks with a broken check (SymlinksIfOwnerMatch does not actually work).

Re: The Quest to Secure chown and symlinks

#25
post #11

Earlier quoted context omitted.

This seems to still be vulnerable to TOCTOU? Tho, to be fair, it's probably an improvement by narrowing how simple it is to exploit relative to doing nothing.

I'm not going to sit there claiming it's not vulnerable to anything. But, assuming it does what it's supposed to, the inherent semantics of the check is supposed to eliminate TOCtoTOU. The reason is that if we validate, from left to right, that no part of the path is under the control of adversaries, then nothing can happen to that path between the time of check and time of use. (At least nothing that isn't self-infl…

My objection would be that one (or more) path component(s) could come under the control of an adversary in between the check and the use. Granted it might take a weird set of circumstances -- e.g. a deployment process running in parallel doing odd things with permissions[0] -- but the fundamental problem seems to be essentially unsolvable without kernel support.

It's definitely a great improvement, though.

[0] Which would arguably be a bug with the other process, but this is the world we live in :/

Re: The Quest to Secure chown and symlinks

#26
post #8

There would traditionally been another TOCTOU is the described solution, namely hardlinks. This can often be used to get root to do something to a file it shouldn't. The trad solution is to have user writeable areas (home, vartmp, tmp) on different volumes. Some tools have options to not traverse symlinks across volumes for this and other reasons. But on modern systems you are protected by the fs.protected_hardlinks…

Can a user make a hard link to a file they don't own? How does this attack work?

Answer: fs.protected_hardlinks=1 is what prevents the creation of hardlinks to files you don't own. It's on by default on all machines I checked though.

https://github.com/torvalds/linux/commit/800179c9b8a1e796e44...

Without this, a whole lot of attacks are possible with hardlinks.

Re: The Quest to Secure chown and symlinks

#27
post #23
post #16

Earlier quoted context omitted.

Yeah but what do you do if your are not using shell? Hint: it's stat(2) (or equivalent in your language library) Additional hint: if using pythons os.stat set follow_symlinks to false. It recently took me an embarrassing long time to figure out why my script was failing to find symlinks.

but they were using a shell script in this blog though (and, yes, stat(2) is the way to go there)

[dead]

Re: The Quest to Secure chown and symlinks

#28
post #25

Earlier quoted context omitted.

I'm not going to sit there claiming it's not vulnerable to anything. But, assuming it does what it's supposed to, the inherent semantics of the check is supposed to eliminate TOCtoTOU. The reason is that if we validate, from left to right, that no part of the path is under the control of adversaries, then nothing can happen to that path between the time of check and time of use. (At least nothing that isn't self-infl…

My objection would be that one (or more) path component(s) could come under the control of an adversary in between the check and the use. Granted it might take a weird set of circumstances -- e.g. a deployment process running in parallel doing odd things with permissions[0] -- but the fundamental problem seems to be essentially unsolvable without kernel support. It's definitely a great improvement, though. [0] Which…

Right. Basically the deployment would have to happen in a secret tree: a directory with a hard to guess name (e.g. 256 bit random hex string) in a root-owned directory that is not readable to anyone but root. Only when the deployment is finalized (all chown and chmod operations have been done) is that tree then renamed to its deployment location.

Whenever root creates an object owned by root, which is then chown-ed to non-root, if an adversary can point a root process at that object, that could subvert safepath.

Re: The Quest to Secure chown and symlinks

#29
post #25

Earlier quoted context omitted.

My objection would be that one (or more) path component(s) could come under the control of an adversary in between the check and the use. Granted it might take a weird set of circumstances -- e.g. a deployment process running in parallel doing odd things with permissions[0] -- but the fundamental problem seems to be essentially unsolvable without kernel support. It's definitely a great improvement, though. [0] Which…

Right. Basically the deployment would have to happen in a secret tree: a directory with a hard to guess name (e.g. 256 bit random hex string) in a root-owned directory that is not readable to anyone but root. Only when the deployment is finalized (all chown and chmod operations have been done) is that tree then renamed to its deployment location. Whenever root creates an object owned by root, which is then chown-ed t…

Just a little thing: Ownership could change from root-to-foo-and-back-again in between Check and Use. We might be talking degenerate cases, again.

... but again^2, probably a huge improvement over ignoring the problem. It will ultimately need OS-API support to avoid these types of issues fully.

As an aside: C++'s filesystem API is (very theoretically) largely unusable due to issues like these. Effectively, almost all of it is UB if even a single other process is doing writes on the filesystem you're accessing.

Post reply on HN