On 2025-03-25 07:19, Ethan Heilman wrote:
> Without this functionality in cat, users are likely to do the next
> easiest option which is to use two separate commands to first check if
> the file is a symlink and then read the file. This can be a source of
> bugs and harm security because using two commands introduces a TOCTOU
> (Time-of-Check to Time-of-Use) issue. This is because it is always
> possible after the symlink check has occurred, but before cat is run
> the file is replaced with symlink. Such race condition bugs are
> especially dangerous because the harmful behavior is triggered only in
> rare circumstances, allowing them to enter production and be hard to
> debug.

I made a small C library module called safepath in this area;
it seems like something that might interest you given the
topics in your post.

https://www.kylheku.com/cgit/safepath/about/

The idea is that we can beat the TOCtoTOU issue if we validate the
entire path from left to right, and check that every component
we visit is protected from tampering.

Think about it; why do you worry that the last component of
a path you are cat-ting can be turned into a symlink?

It's because the adversary has write permissions to that
directory which is the second-to-last component!

Or else not that, then some higher directory earlier in the path,
which lets them control the interpretation of subsequent
components.

What if there is no such component? E.g. you don't worry that
/usr/bin/grep can be replaced by a symlink by a malicious
user. That's because / is root-owned and unwritable to
others, and so is /bin.  Moreover, you don't have to just
believe that; this is verifiable.

Unfortunately, I am embarrassed to see I have not added
tests to safepath.

(I wrote a version of it in another language that I put into
production; that one is covered by a bunch of tests.)


> This is not a problem for directories because one can check if a
> directory is a symlink safely with any later action because you can
> compare the expected file path after traversing into that directory
> but before taking the action. This is safe because someone can’t
> change the directory you are already in into a symlink after you have
> transverse it.

Of course, that's if you have it has your CWD and from there use
a relative path.

When we have to feed several path arguments to a function or utility,
we can't be in both their directories at once.

Reply via email to