This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH v15 2/9] namei: LOOKUP_NO_MAGICLINKS: block magic-link resolution
- From: Aleksa Sarai <cyphar at cyphar dot com>
- To: Al Viro <viro at zeniv dot linux dot org dot uk>, Jeff Layton <jlayton at kernel dot org>, "J. Bruce Fields" <bfields at fieldses dot org>, Arnd Bergmann <arnd at arndb dot de>, David Howells <dhowells at redhat dot com>, Shuah Khan <shuah at kernel dot org>, Shuah Khan <skhan at linuxfoundation dot org>, Ingo Molnar <mingo at redhat dot com>, Peter Zijlstra <peterz at infradead dot org>
- Cc: Aleksa Sarai <cyphar at cyphar dot com>, Christian Brauner <christian dot brauner at ubuntu dot com>, David Drysdale <drysdale at google dot com>, Andy Lutomirski <luto at kernel dot org>, Linus Torvalds <torvalds at linux-foundation dot org>, Eric Biederman <ebiederm at xmission dot com>, Andrew Morton <akpm at linux-foundation dot org>, Alexei Starovoitov <ast at kernel dot org>, Kees Cook <keescook at chromium dot org>, Jann Horn <jannh at google dot com>, Tycho Andersen <tycho at tycho dot ws>, Chanho Min <chanho dot min at lge dot com>, Oleg Nesterov <oleg at redhat dot com>, Rasmus Villemoes <linux at rasmusvillemoes dot dk>, Alexander Shishkin <alexander dot shishkin at linux dot intel dot com>, Jiri Olsa <jolsa at redhat dot com>, Namhyung Kim <namhyung at kernel dot org>, Christian Brauner <christian at brauner dot io>, Aleksa Sarai <asarai at suse dot de>, containers at lists dot linux-foundation dot org, linux-alpha at vger dot kernel dot org, linux-api at vger dot kernel dot org, libc-alpha at sourceware dot org, linux-arch at vger dot kernel dot org, linux-arm-kernel at lists dot infradead dot org, linux-fsdevel at vger dot kernel dot org, linux-ia64 at vger dot kernel dot org, linux-kernel at vger dot kernel dot org, linux-kselftest at vger dot kernel dot org, linux-m68k at lists dot linux-m68k dot org, linux-mips at vger dot kernel dot org, linux-parisc at vger dot kernel dot org, linuxppc-dev at lists dot ozlabs dot org, linux-s390 at vger dot kernel dot org, linux-sh at vger dot kernel dot org, linux-xtensa at linux-xtensa dot org, sparclinux at vger dot kernel dot org
- Date: Tue, 5 Nov 2019 20:05:46 +1100
- Subject: [PATCH v15 2/9] namei: LOOKUP_NO_MAGICLINKS: block magic-link resolution
- References: <20191105090553.6350-1-cyphar@cyphar.com>
/* Background. */
There has always been a special class of symlink-like objects in procfs
(and a few other pseudo-filesystems) which allow for non-lexical
resolution of paths using nd_jump_link(). These "magic-links" do not
follow traditional mount namespace boundaries, and have been used
consistently in container escape attacks because they can be used to
trick unsuspecting privileged processes into resolving unexpected paths.
It is also non-trivial for userspace to unambiguously avoid resolving
magic-links, because they do not have a reliable indication that they
are a magic-link (in order to verify them you'd have to manually open
the path given by readlink(2) and then verify that the two file
descriptors reference the same underlying file, which is plagued with
possible race conditions or supplementary attack scenarios).
It would therefore be very helpful for userspace to be able to avoid
these symlinks easily, thus hopefully removing a tool from attackers'
toolboxes.
This is part of a refresh of Al's AT_NO_JUMPS patchset[1] (which was a
variation on David Drysdale's O_BENEATH patchset[2], which in turn was
based on the Capsicum project[3]).
/* Userspace API. */
LOOKUP_NO_MAGICLINKS will be exposed to userspace through openat2(2).
/* Semantics. */
Unlike most other LOOKUP flags (most notably LOOKUP_FOLLOW),
LOOKUP_NO_MAGICLINKS applies to all components of the path.
With LOOKUP_NO_MAGICLINKS, any magic-link path component encountered
during path resolution will yield -ELOOP. The handling of ~LOOKUP_FOLLOW
for a trailing magic-link is identical to LOOKUP_NO_SYMLINKS.
LOOKUP_NO_SYMLINKS implies LOOKUP_NO_MAGICLINKS.
/* Testing. */
LOOKUP_NO_MAGICLINKS is tested as part of the openat2(2) selftests.
[1]: https://lore.kernel.org/lkml/20170429220414.GT29622@ZenIV.linux.org.uk/
[2]: https://lore.kernel.org/lkml/1415094884-18349-1-git-send-email-drysdale@google.com/
[3]: https://lore.kernel.org/lkml/1404124096-21445-1-git-send-email-drysdale@google.com/
Cc: Christian Brauner <christian.brauner@ubuntu.com>
Suggested-by: David Drysdale <drysdale@google.com>
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Suggested-by: Andy Lutomirski <luto@kernel.org>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
fs/namei.c | 7 ++++++-
include/linux/namei.h | 2 ++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/fs/namei.c b/fs/namei.c
index 4e85d6fa4048..1f0d871199e5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -866,7 +866,7 @@ void nd_jump_link(struct path *path)
nd->path = *path;
nd->inode = nd->path.dentry->d_inode;
- nd->flags |= LOOKUP_JUMPED;
+ nd->flags |= LOOKUP_JUMPED | LOOKUP_MAGICLINK_JUMPED;
}
static inline void put_link(struct nameidata *nd)
@@ -1063,6 +1063,7 @@ const char *get_link(struct nameidata *nd)
return ERR_PTR(error);
nd->last_type = LAST_BIND;
+ nd->flags &= ~LOOKUP_MAGICLINK_JUMPED;
res = READ_ONCE(inode->i_link);
if (!res) {
const char * (*get)(struct dentry *, struct inode *,
@@ -1078,6 +1079,10 @@ const char *get_link(struct nameidata *nd)
} else {
res = get(dentry, inode, &last->done);
}
+ if (nd->flags & LOOKUP_MAGICLINK_JUMPED) {
+ if (unlikely(nd->flags & LOOKUP_NO_MAGICLINKS))
+ return ERR_PTR(-ELOOP);
+ }
if (IS_ERR_OR_NULL(res))
return res;
}
diff --git a/include/linux/namei.h b/include/linux/namei.h
index ee2e35af387f..a8b3f93338da 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -38,9 +38,11 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_JUMPED 0x1000
#define LOOKUP_ROOT 0x2000
#define LOOKUP_ROOT_GRABBED 0x0008
+#define LOOKUP_MAGICLINK_JUMPED 0x10000
/* Scoping flags for lookup. */
#define LOOKUP_NO_SYMLINKS 0x020000 /* No symlink crossing. */
+#define LOOKUP_NO_MAGICLINKS 0x040000 /* No /proc/$pid/fd/ "symlink" crossing. */
extern int path_pts(struct path *path);
--
2.23.0