From: Aleksa Sarai <cyphar@cyphar.com>
To: Al Viro <viro@zeniv.linux.org.uk>,
Jeff Layton <jlayton@kernel.org>,
"J. Bruce Fields" <bfields@fieldses.org>,
Arnd Bergmann <arnd@arndb.de>,
David Howells <dhowells@redhat.com>,
Shuah Khan <shuah@kernel.org>,
Shuah Khan <skhan@linuxfoundation.org>,
Ingo Molnar <mingo@redhat.com>,
Peter Zijlstra <peterz@infradead.org>
Cc: Aleksa Sarai <cyphar@cyphar.com>,
Eric Biederman <ebiederm@xmission.com>,
Andy Lutomirski <luto@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>,
Alexei Starovoitov <ast@kernel.org>,
Kees Cook <keescook@chromium.org>, Jann Horn <jannh@google.com>,
Tycho Andersen <tycho@tycho.ws>,
David Drysdale <drysdale@google.com>,
Chanho Min <chanho.min@lge.com>, Oleg Nesterov <oleg@redhat.com>,
Rasmus Villemoes <linux@rasmusvillemoes.dk>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@redhat.com>, Namhyung Kim <namhyung@kernel.org>,
Christian Brauner <christian@brauner.io>,
Aleksa Sarai <asarai@suse.de>,
Linus Torvalds <torvalds@linux-foundation.org>,
containers@lists.linux-foundation.org,
linux-alpha@vger.kernel.org, linux-api@vger.kernel.org,
libc-alpha@sourceware.org, linux-arch@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-fsdevel@vger.kernel.org, linux-ia64@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
linux-m68k@lists.linux-m68k.org, linux-mips@vger.kernel.org,
linux-parisc@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
linux-s390@vger.kernel.org, linux-sh@vger.kernel.org,
linux-xtensa@linux-xtensa.org, sparclinux@vger.kernel.org
Subject: [PATCH v13 9/9] Documentation: update path-lookup to mention trailing magic-links
Date: Tue, 1 Oct 2019 04:33:16 +1000 [thread overview]
Message-ID: <20190930183316.10190-10-cyphar@cyphar.com> (raw)
In-Reply-To: <20190930183316.10190-1-cyphar@cyphar.com>
We've introduced new (somewhat subtle) behaviour regarding trailing
magic-links, so it's best to make sure everyone can follow along with
the reasoning behind trailing_magiclink().
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
Documentation/filesystems/path-lookup.rst | 80 ++++++++++++++++++-----
1 file changed, 63 insertions(+), 17 deletions(-)
diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst
index 434a07b0002b..c30145b3d9ba 100644
--- a/Documentation/filesystems/path-lookup.rst
+++ b/Documentation/filesystems/path-lookup.rst
@@ -405,6 +405,10 @@ is requested. Keeping a reference in the ``nameidata`` ensures that
only one root is in effect for the entire path walk, even if it races
with a ``chroot()`` system call.
+It should be noted that in the case of ``LOOKUP_IN_ROOT`` or
+``LOOKUP_BENEATH``, the effective root becomes the directory file descriptor
+passed to ``openat2()`` (which exposes these ``LOOKUP_`` flags).
+
The root is needed when either of two conditions holds: (1) either the
pathname or a symbolic link starts with a "'/'", or (2) a "``..``"
component is being handled, since "``..``" from the root must always stay
@@ -1149,22 +1153,61 @@ so ``NULL`` is returned to indicate that the symlink can be released and
the stack frame discarded.
The other case involves things in ``/proc`` that look like symlinks but
-aren't really::
+aren't really (and are therefore commonly referred to as "magic-links")::
$ ls -l /proc/self/fd/1
lrwx------ 1 neilb neilb 64 Jun 13 10:19 /proc/self/fd/1 -> /dev/pts/4
Every open file descriptor in any process is represented in ``/proc`` by
-something that looks like a symlink. It is really a reference to the
-target file, not just the name of it. When you ``readlink`` these
-objects you get a name that might refer to the same file - unless it
-has been unlinked or mounted over. When ``walk_component()`` follows
-one of these, the ``->follow_link()`` method in "procfs" doesn't return
-a string name, but instead calls ``nd_jump_link()`` which updates the
-``nameidata`` in place to point to that target. ``->follow_link()`` then
-returns ``NULL``. Again there is no final component and ``get_link()``
-reports this by leaving the ``last_type`` field of ``nameidata`` as
-``LAST_BIND``.
+a magic-link. It is really a reference to the target file, not just the
+name of it (hence making them "magical" compared to ordinary symlinks).
+When you ``readlink`` these objects you get a name that might refer to
+the same file - unless it has been unlinked or mounted over. When
+``walk_component()`` follows one of these, the ``->follow_link()`` method
+in "procfs" doesn't return a string name, but instead calls
+``nd_jump_link()`` which updates the ``nameidata`` in place to point to
+that target. ``->follow_link()`` then returns ``NULL``. Again there is
+no final component and ``get_link()`` reports this by leaving the
+``last_type`` field of ``nameidata`` as ``LAST_BIND``.
+
+In order to avoid potential re-opening attacks (especially in the context
+of containers), it is necessary to restrict the ability for a trailing
+magic-link to be opened. The restrictions are as follows (and are
+implemented in ``trailing_magiclink()``):
+
+* If the ``open()`` is an "ordinary open" (without ``O_PATH``), the
+ access-mode of the ``open()`` call must be permitted by one of the
+ octets in the magic-link's file mode (elsewhere in Linux, ordinary
+ symlinks have a file mode of ``0777`` but this doesn't apply to
+ magic-links). Each "ordinary" file in ``/proc/self/fd/$n`` has the user
+ octet of its file mode set to correspond to the access-mode it was
+ opened with.
+
+ This restriction means that you cannot re-open an ``O_RDONLY`` file
+ descriptor through ``/proc/self/fd/$n`` with ``O_RDWR``.
+
+With a "half-open" (with ``O_PATH``), there is no ``-EACCES``-enforced
+restrictions on ``open()``, but there are rules about the mode shown in
+``/proc/self/fd/$n``:
+
+* If the target of the ``open()`` is not a magic-link, then the group
+ octet of the file mode is set to permit all access modes.
+
+* Otherwise, the mode of the new ``O_PATH`` descriptor is set to
+ effectively the same mode as the magic-link (though the permissions are
+ set in the group octet of the mode). This means that an ``O_PATH`` of a
+ magic-link gives you no more re-open permissions than the magic-link
+ itself.
+
+With these ``O_PATH`` restrictions, it is still possible to re-open an
+``O_PATH`` file descriptor but you cannot use ``O_PATH`` to work around
+the above restrictions on "ordinary opens" of magic-links.
+
+In order to avoid certain race conditions (where a file descriptor
+associated with a magic-link is swapped, causing the ``link_inode`` of
+``nameidata`` to become stale during magic-link traversal),
+``nd_jump_link()`` stores the mode of the magic-link during traversal in
+``last_magiclink``.
Following the symlink in the final component
--------------------------------------------
@@ -1187,7 +1230,8 @@ handles the final component. If the final component is a symlink
that needs to be followed, then ``trailing_symlink()`` is called to set
things up properly and the loop repeats, calling ``link_path_walk()``
again. This could loop as many as 40 times if the last component of
-each symlink is another symlink.
+each symlink is another symlink. ``trailing_magiclink()`` is then called to
+deal with permission checks relevant to ``/proc/$pid/fd``-style "symlinks".
The various functions that examine the final component and possibly
report that it is a symlink are ``lookup_last()``, ``mountpoint_last()``
@@ -1310,12 +1354,14 @@ longer needed.
``LOOKUP_JUMPED`` means that the current dentry was chosen not because
it had the right name but for some other reason. This happens when
following "``..``", following a symlink to ``/``, crossing a mount point
-or accessing a "``/proc/$PID/fd/$FD``" symlink. In this case the
-filesystem has not been asked to revalidate the name (with
-``d_revalidate()``). In such cases the inode may still need to be
-revalidated, so ``d_op->d_weak_revalidate()`` is called if
+or accessing a "``/proc/$PID/fd/$FD``" symlink (also known as a "magic
+link"). In this case the filesystem has not been asked to revalidate the
+name (with ``d_revalidate()``). In such cases the inode may still need
+to be revalidated, so ``d_op->d_weak_revalidate()`` is called if
``LOOKUP_JUMPED`` is set when the look completes - which may be at the
-final component or, when creating, unlinking, or renaming, at the penultimate component.
+final component or, when creating, unlinking, or renaming, at the
+penultimate component. ``LOOKUP_MAGICLINK_JUMPED`` is set alongside
+``LOOKUP_JUMPED`` if a magic-link was traversed.
Final-component flags
~~~~~~~~~~~~~~~~~~~~~
--
2.23.0
prev parent reply other threads:[~2019-09-30 21:04 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-09-30 18:33 [PATCH v13 0/9] namei: openat2(2) path resolution restrictions Aleksa Sarai
2019-09-30 18:33 ` [PATCH v13 1/9] namei: obey trailing magic-link DAC permissions Aleksa Sarai
2019-09-30 18:33 ` [PATCH v13 2/9] procfs: switch magic-link modes to be more sane Aleksa Sarai
2019-09-30 18:33 ` [PATCH v13 3/9] open: O_EMPTYPATH: procfs-less file descriptor re-opening Aleksa Sarai
2019-09-30 22:51 ` kbuild test robot
2019-09-30 23:09 ` Aleksa Sarai
2019-09-30 18:33 ` [PATCH v13 4/9] namei: O_BENEATH-style path resolution flags Aleksa Sarai
2019-09-30 18:33 ` [PATCH v13 5/9] namei: LOOKUP_IN_ROOT: chroot-like path resolution Aleksa Sarai
2019-09-30 18:33 ` [PATCH v13 6/9] namei: permit ".." resolution with LOOKUP_{IN_ROOT,BENEATH} Aleksa Sarai
2019-09-30 18:33 ` [PATCH v13 7/9] open: openat2(2) syscall Aleksa Sarai
2019-09-30 20:58 ` kbuild test robot
2019-09-30 22:41 ` Aleksa Sarai
2019-10-01 0:22 ` kbuild test robot
2019-10-01 5:06 ` kbuild test robot
2019-09-30 18:33 ` [PATCH v13 8/9] selftests: add openat2(2) selftests Aleksa Sarai
2019-09-30 18:33 ` Aleksa Sarai [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190930183316.10190-10-cyphar@cyphar.com \
--to=cyphar@cyphar.com \
--cc=akpm@linux-foundation.org \
--cc=alexander.shishkin@linux.intel.com \
--cc=arnd@arndb.de \
--cc=asarai@suse.de \
--cc=ast@kernel.org \
--cc=bfields@fieldses.org \
--cc=chanho.min@lge.com \
--cc=christian@brauner.io \
--cc=containers@lists.linux-foundation.org \
--cc=dhowells@redhat.com \
--cc=drysdale@google.com \
--cc=ebiederm@xmission.com \
--cc=jannh@google.com \
--cc=jlayton@kernel.org \
--cc=jolsa@redhat.com \
--cc=keescook@chromium.org \
--cc=libc-alpha@sourceware.org \
--cc=linux-alpha@vger.kernel.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-ia64@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-m68k@lists.linux-m68k.org \
--cc=linux-mips@vger.kernel.org \
--cc=linux-parisc@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=linux-sh@vger.kernel.org \
--cc=linux-xtensa@linux-xtensa.org \
--cc=linux@rasmusvillemoes.dk \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=luto@kernel.org \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
--cc=shuah@kernel.org \
--cc=skhan@linuxfoundation.org \
--cc=sparclinux@vger.kernel.org \
--cc=torvalds@linux-foundation.org \
--cc=tycho@tycho.ws \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).