Thread (13 messages) flat view 13 messages, 6 authors, 2014-11-05

Re: [PATCH 1/3] fs: add O_BENEATH flag to openat(2)

From: Andy Lutomirski <hidden>
Date: 2014-11-05 17:28:39
Also in: lkml

On Wed, Nov 5, 2014 at 9:21 AM, David Drysdale [off-list ref] wrote:
On Tue, Nov 4, 2014 at 9:40 AM, David Drysdale [off-list ref] wrote:
quoted
On Mon, Nov 3, 2014 at 5:22 PM, Eric W.Biederman [off-list ref] wrote:
quoted
On November 3, 2014 7:42:58 AM PST, Andy Lutomirski [off-list ref] wrote:
quoted
On Mon, Nov 3, 2014 at 7:20 AM, Al Viro [off-list ref]
wrote:
quoted
On Mon, Nov 03, 2014 at 11:48:23AM +0000, David Drysdale wrote:
quoted
Add a new O_BENEATH flag for openat(2) which restricts the
provided path, rejecting (with -EACCES) paths that are not beneath
the provided dfd.  In particular, reject:
 - paths that contain .. components
 - paths that begin with /
 - symlinks that have paths as above.
Yecch...  The degree of usefulness aside (and I'm not convinced that
it
quoted
is non-zero),
This is extremely useful in conjunction with seccomp.
quoted
WTF pass one bit out of nameidata->flags in a separate argument?
Through the mutual recursion, no less...  And then you are not even
attempting
quoted
to detect symlinks that are not followed by interpretation of _any_
pathname.

How many symlinks like that are there?  Is there anything except
nd_jump_link users?  All of those are in /proc.  Arguably O_BENEATH
should prevent traversal of all of those links.
Not commenting on the sanity of this one way or another, and I haven't read the patch.  There is an absolutely trivial implementation of this.

After the path is resolved, walk backwards along d_parent and the mount tree, and see if you come to the file or directory dfd refers to.

That can handle magic proc symlinks, and does not need to disallow .. or / explicitly so it should be much simpler code.

My gut says that if Al says blech when looking at your code it is too complex to give you a security guarantee.

Eric
Well, the 'yecch' was deserved for the unnecessary duplication of the
flags.  Without that, the patch looks much simpler -- I'll send out a v2
with those changes for discussion, and think about your alternative
implementation suggestion (thanks!) separately.
One concern with the "walk upwards and see if you get back where you
started" approach -- it will allow use of a symlink that lives outside the
original directory, but which points back inside it.  That's going to be
slightly surprising behaviour for users, and I worry that there's the
potential for unexpected information leakage from it.

(BTW, size-wise my initial naive implementation of the walk-upward
approach is only marginally smaller than the v2 patch.)
It has another problem.  Since we still haven't fixed the eternal
/proc/PID/fd-doesn't-respect-file-mode issue, you can have a read-only
fd somewhere and reopen it read-write using O_BENEATH on a different
fd.

For example:

fd 3 points to /sandbox
/sandbox/blocked has mode 0700 and isn't owned by us
/sandbox/blocked/foo has mode 0666
fd 4 points to /sandbox/blocked/foo, O_RDONLY

openat(3, "/proc/self/fd/4", O_RDWR | O_BENEATH) will get a read-write
descriptor pointing at /sandbox/blocked/foo, which should have been
impossible.

Also, I really don't like the information leak.  The result of asking
a server for "/home/victim/compromising-directory/../../www/index.html"
should not reveal whether compromising-directory exists.

--Andy
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help