mailing list of musl libc
 help / color / mirror / code / Atom feed
* faccessat and AT_SYMLINK_NOFOLLOW
@ 2015-02-04 19:25 Nick Kralevich
  2015-02-05 20:37 ` Rich Felker
  0 siblings, 1 reply; 2+ messages in thread
From: Nick Kralevich @ 2015-02-04 19:25 UTC (permalink / raw)
  To: musl

In some sense, this is a continuation of the earlier thread at
http://www.openwall.com/lists/musl/2014/09/25/1 . That thread is the
only concrete discussion I can find describing the intended behavior
of faccessat and AT_SYMLINK_NOFOLLOW

I'm working on a modification to Android's libc for faccessat.
Currently, in Android's libc, faccessat() completely ignores any flags
argument, and just passes through the call to the kernel (dropping the
flags field).

I've proposed a modification to Android's libc to implement
AT_SYMLINK_NOFOLLOW (https://android-review.googlesource.com/128582).
By calling access() on /proc/self/fd/FDNUM, where FDNUM was created
using open(O_PATH | O_NOFOLLOW), we can ask the kernel to make an
access control decision on the symlink itself. The model was suggested
by Rich in https://sourceware.org/bugzilla/show_bug.cgi?id=14578
(although that was for a different bug).

However, as I've digged into this more, I'm more and more confused
about what the correct behavior should be for
faccessat(AT_SYMLINK_NOFOLLOW).

Imagine the following code:

  symlink("foo.is.dangling", "foo");
  if (faccessat(AT_FDCWD, "foo", R_OK, AT_SYMLINK_NOFOLLOW) == 0) {
    int fd = openat(AT_FDCWD, "foo", O_RDONLY | O_NOFOLLOW);
  }

For glibc, faccessat(AT_NOFOLLOW) will return true, since the symlink
exists and the permissions on the symlink allow access. (Symlinks on
Linux are always 777, so glibc considers any symlink to be globally
accessible)

However, the openat() call will fail, since the target is a symlink.

It seems to me that, if faccessat(R_OK, AT_SYMLINK_NOFOLLOW) returns
true, than the openat() should succeed (absent race conditions).
Similarly, if faccessat() returns false, then the openat() should
fail. To do so otherwise seems counter-intuitive to me.

I'm curious what others think the appropriate behavior of
faccessat(AT_SYMLINK_NOFOLLOW) should be. Clearly the glibc behavior
here is wrong, but I'm not sure what the right behavior should be...

-- 
Nick Kralevich | Android Security | nnk@google.com | 650.214.4037


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: faccessat and AT_SYMLINK_NOFOLLOW
  2015-02-04 19:25 faccessat and AT_SYMLINK_NOFOLLOW Nick Kralevich
@ 2015-02-05 20:37 ` Rich Felker
  0 siblings, 0 replies; 2+ messages in thread
From: Rich Felker @ 2015-02-05 20:37 UTC (permalink / raw)
  To: musl

On Wed, Feb 04, 2015 at 11:25:49AM -0800, Nick Kralevich wrote:
> In some sense, this is a continuation of the earlier thread at
> http://www.openwall.com/lists/musl/2014/09/25/1 . That thread is the
> only concrete discussion I can find describing the intended behavior
> of faccessat and AT_SYMLINK_NOFOLLOW
> 
> I'm working on a modification to Android's libc for faccessat.
> Currently, in Android's libc, faccessat() completely ignores any flags
> argument, and just passes through the call to the kernel (dropping the
> flags field).
> 
> I've proposed a modification to Android's libc to implement
> AT_SYMLINK_NOFOLLOW (https://android-review.googlesource.com/128582).
> By calling access() on /proc/self/fd/FDNUM, where FDNUM was created
> using open(O_PATH | O_NOFOLLOW), we can ask the kernel to make an
> access control decision on the symlink itself. The model was suggested
> by Rich in https://sourceware.org/bugzilla/show_bug.cgi?id=14578
> (although that was for a different bug).
> 
> However, as I've digged into this more, I'm more and more confused
> about what the correct behavior should be for
> faccessat(AT_SYMLINK_NOFOLLOW).
> 
> Imagine the following code:
> 
>   symlink("foo.is.dangling", "foo");
>   if (faccessat(AT_FDCWD, "foo", R_OK, AT_SYMLINK_NOFOLLOW) == 0) {
>     int fd = openat(AT_FDCWD, "foo", O_RDONLY | O_NOFOLLOW);
>   }
> 
> For glibc, faccessat(AT_NOFOLLOW) will return true, since the symlink
> exists and the permissions on the symlink allow access. (Symlinks on
> Linux are always 777, so glibc considers any symlink to be globally
> accessible)
> 
> However, the openat() call will fail, since the target is a symlink.
> 
> It seems to me that, if faccessat(R_OK, AT_SYMLINK_NOFOLLOW) returns
> true, than the openat() should succeed (absent race conditions).
> Similarly, if faccessat() returns false, then the openat() should
> fail. To do so otherwise seems counter-intuitive to me.
> 
> I'm curious what others think the appropriate behavior of
> faccessat(AT_SYMLINK_NOFOLLOW) should be. Clearly the glibc behavior
> here is wrong, but I'm not sure what the right behavior should be...

It seems to me that what you're asking is whether AT_SYMLINK_NOFOLLOW
should mean "report accessibility for the symlink itself" or "force
failure when the target is a symlink"; the latter is what O_NOFOLLOW
does for open[at]. I don't have any strong opinion on the topic, but I
think the ambiguity is a strong suggestion that supporting
AT_SYMLINK_NOFOLLOW for faccessat is a bad idea. In particular, it
would be bad to choose an interpretation now and have POSIX later
mandate the opposite one.

Furthermore, faccessat (like access) is pretty much a useless
operation. It's fundamentally subject to TOCTOU races, and by default
it uses the read ids of the caller rather than the effective ids. The
intended use of these functions originally seems to have been letting
suid/sgid programs emulate the permissions of the user who invoked
them (rather than their current effective ids), but such usage is
incorrect and dangerous because of the race. I would go so far as to
say POSIX should mark both access and faccessat obsolescent. They have
no valid uses and plenty of erroneous uses that result in security
flaws. If you want to know if open will succeed, just try to do it.

Rich


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2015-02-05 20:37 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-04 19:25 faccessat and AT_SYMLINK_NOFOLLOW Nick Kralevich
2015-02-05 20:37 ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).