top | item 37863694

The Quest to Secure chown and symlinks

59 points| juanfatas | 2 years ago |buildkite.com

27 comments

order

pdimitar|2 years ago

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.

tinus_hn|2 years ago

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.

Hello71|2 years ago

  (cd "$path" && [ "$(pwd -P)" = "$path" ] && chown -R buildkite-agent:buildkite-agent .)
the real question though is why they're trusting just Docker alone to isolate customers; if they want the jobs to effectively be a single user to the system, they can even use unprivileged user namespaces?

lox|2 years ago

This stack is run by a single customer on trusted code isolated in their own AWS env. (I wrote it originally 6-7 years back)

There are radically better isolation strategies now. Firecracker and/or Sysbox hardened docker containers is one I’ve recently implemented.

Y_Y|2 years ago

When all you have is a hammer...

kazinator|2 years ago

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...

Quekid5|2 years ago

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.

jrmg|2 years ago

Why do the files have bad permissions to start with?

lox|2 years ago

Docker is running as root, so the files written in mounted volumes get mapped to uid 0 on the host. When the agent then goes to re-use the checked out code, it can’t run ‘git clean’.

Username space remapping wasn’t adequate, for reasons I’m a bit blurry on. I think recent kernels have some better options on remapping permissions across file systems.

angry_octet|2 years ago

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 setting.

https://wiki.alpinelinux.org/wiki/Sysctl.conf

tadfisher|2 years ago

Researching this, found [1]:

> POSIX guarantees that hard links can exist. It follows that, on POSIX systems without any non-standard protections, it's unsafe for anyone (but in particular, root) to do anything sensitive in a directory that is writable by another user. Cross-platform programs designed to do so are simply flawed.

I feel like something had to have been lost in translation from Unix to POSIX here. In the original implementation, were users able to hardlink (well, "link") files owned by others? If so, this is a foundational flaw that should probably be fixed across the board with something similar to Linux's non-standard sysctl option.

[1]: http://michael.orlitzky.com/articles/posix_hardlink_heartach...

remram|2 years ago

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

blibble|2 years ago

why is it running as root anyway?

should probably setuid to the correct user and do the thing there instead

Avamander|2 years ago

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).

nunez|2 years ago

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

somat|2 years ago

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.

tux2bsd|2 years ago

> checks if a file is a symlink

to expand on that:

"In computing, a symbolic link (also symlink or soft link) is a file whose purpose is to point to a file or directory (called the "target") by specifying a path thereto."