It is possible for a program to inherit or be passed an open file descriptor, for a file it would not otherwise be permitted to read (or write). For example:

(sudo -u nobody echo "hello world") > ~/test-file
(sudo -u nobody cat) < ~/test-file

Question: If you inherit a current directory (or root directory) which your user would not otherwise be permitted to access, are you allowed to access it?

2 Answers 2


The comparison to file descriptors is highly misleading: the current and root directory of a process are not file descriptors or any kind of pointers to an "open file description" (a struct file), but just pointers to directory entries (struct dentrys).

The kernel does not keep an open file description referring to the directory inode pointed by either the current or the root directory, which could be inherited by child processes via any kind of handle.

In order for they to be used in any way, the current and root directory have to be opened by path, just like any other file, and all the standard checks apply.

Opening a file with O_PATH will return just an opaque handle, and it will succeed with any file that couldn't be normally opened for read or write, provided that the path to it is accessible:

$ perl -e 'sysopen my $fh, "/root", 0, 0 or die "$!"'
Permission denied at -e line 1.
$ perl -e 'sysopen my $fh, "/root", 010000000, 0 or die "$!"' # 010000000 is O_PATH

Such an opaque fd cannot be used as a normal fd even by privileged processes, and fortunately there's no way to do an openat(fd, "", AT_EMPTY_PATH|O_RDWR) in order to dup() it into a regular file descriptor ;-)

BTW, the musl library defines O_SEARCH as O_PATH since 2012.

  • @sourcejedi I don't care about upvotes, but I don't understand what the fuss is about. The O_PATH semantics are just better and all the other unices will follow suit sooner or later (and define both O_EXEC and O_SEARCH as O_PATH). Just as they did with sharing the stack segment in rfork/clone.
    – user313992
    Commented Jun 12, 2019 at 23:22
  • Linux isn't obligated to implement POSIX. But I don't think it's great for libc to stub O_SEARCH with a meaning which does not "[meet] the POSIX requirements for O_SEARCH". If nothing else, it makes it harder to realize what the different requirements are, even though the POSIX requirements are so straighforward. I accept O_EXEC looks more awkward since POSIX fexecve() is not standardized as accepting any non-O_EXEC fd, but if we need a temporary lowest common denominator, it seems simpler to generalize the POSIX spec to include the support for O_RDONLY fds.
    – sourcejedi
    Commented Jun 13, 2019 at 9:11
  • I can't really work out what you're making an analogy with. FreeBSD deprecates rfork_thread() & RFMEM "may not generally be called directly from high level languages including C" & rfork() does not mention vfork semantics. Any improvement in semantics seems a bit obscure / an implementation detail for a small number of platforms such as pthreads.
    – sourcejedi
    Commented Jun 13, 2019 at 9:23
  • It's a historical analogy. They first implemented it differently (as in plan9), then made it as in linux.
    – user313992
    Commented Jun 13, 2019 at 11:48
  • 1
    @sourcejedi A big performance difference for pthreads is something big, not an obscure implementation detail. Here is a link to the thread I was remembering.
    – user313992
    Commented Jun 13, 2019 at 12:57


# sudo -u nobody ls .
ls: cannot access '.': Permission denied

# sudo -u nobody ls -d .
ls: cannot access '.': Permission denied

# chmod o-rwx /chroot
# chroot --userspec=nobody:nobody /chroot
chroot: failed to run command ‘/bin/bash’: Permission denied

The same is also true for write access to the current directory (or root directory). If it was not, I suspect it would be a source of security bugs :-).

Similar behaviour applies to file descriptors opened with O_PATH on Linux.

POSIX (which does not define O_PATH) implies that openat(fd, path, ...) and similar functions will re-check permission to access the open directory fd, unless fd was opened with O_SEARCH. Linux does not support O_SEARCH.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .