From mboxrd@z Thu Jan 1 00:00:00 1970 From: Aleksa Sarai Subject: [PATCH v13 5/9] namei: LOOKUP_IN_ROOT: chroot-like path resolution Date: Tue, 1 Oct 2019 04:33:12 +1000 Message-ID: <20190930183316.10190-6-cyphar@cyphar.com> References: <20190930183316.10190-1-cyphar@cyphar.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Kbo670mbZI5o58j0IUYmPPWnbtkzW+eluxYiAp+hGc0=; b=dFBxXU6WlEec/s BNKi3fi41rC89nDspg0iyKpRkQUHxe/CyHokcEIjV9gf1Z6h2J86FadJSwAjP3IhBlhb8MI/2EFdy VzS2Z3Lujo54W2xREP2hJIKImxZ1HqOoa7TuK+abg07grd1JRR8M4MzKOU7WqugAd7vP/CQJbC6Jz rieHDoca/bqeXKv4TtZPW/EflASuwIUxbljQi92qJo4YfDuljDZbo1Xrs+tyRvJpEFyI4LOKi2aJe fR8yIvFOla63DVNuLaA7przPPhfb0FlKHB2ZkvXKsSAnbJBPU/IWYC6/2DQb3DKJ0J1S7XuWtb/aF fwBcsF2tPRjfTnirTgIQ==; In-Reply-To: <20190930183316.10190-1-cyphar@cyphar.com> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: Al Viro , Jeff Layton , "J. Bruce Fields" , Arnd Bergmann , David Howells , Shuah Khan , Shuah Khan , Ingo Molnar , Peter Zijlstra Cc: linux-ia64@vger.kernel.org, linux-sh@vger.kernel.org, Alexander Shishkin , Rasmus Villemoes , Alexei Starovoitov , linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, sparclinux@vger.kernel.org, Jiri Olsa , linux-arch@vger.kernel.org, linux-s390@vger.kernel.org, Tycho Andersen , Aleksa Sarai , linux-arm-kernel@lists.infradead.org, linux-mips@vger.kernel.org, linux-xtensa@linux-xtensa.org, Kees Cook , Jann Horn , linuxppc-dev@lists.ozlabs.org, Aleksa Sarai , Andy Lutomirski , Namhyung Kim , David Drysdale , Christian Brauner , libc-alpha@sourceware.org, linux-parisc@vger.kernel.org, linux-m68k@li The primary motivation for the need for this flag is container runtimes which have to interact with malicious root filesystems in the host namespaces. One of the first requirements for a container runtime to be secure against a malicious rootfs is that they correctly scope symlinks (that is, they should be scoped as though they are chroot(2)ed into the container's rootfs) and ".."-style paths[*]. The already-existing LOOKUP_NO_XDEV and LOOKUP_NO_MAGICLINKS help defend against other potential attacks in a malicious rootfs scenario. Currently most container runtimes try to do this resolution in userspace[1], causing many potential race conditions. In addition, the "obvious" alternative (actually performing a {ch,pivot_}root(2)) requires a fork+exec (for some runtimes) which is *very* costly if necessary for every filesystem operation involving a container. [*] At the moment, ".." and magic-link jumping are disallowed for the same reason it is disabled for LOOKUP_BENEATH -- currently it is not safe to allow it. Future patches may enable it unconditionally once we have resolved the possible races (for "..") and semantics (for magic-link jumping). The most significant *at(2) semantic change with LOOKUP_IN_ROOT is that absolute pathnames no longer cause the dirfd to be ignored completely. The rationale is that LOOKUP_IN_ROOT must necessarily chroot-scope symlinks with absolute paths to dirfd, and so doing it for the base path seems to be the most consistent behaviour (and also avoids foot-gunning users who want to scope paths that are absolute). [1]: https://github.com/cyphar/filepath-securejoin Signed-off-by: Aleksa Sarai --- fs/namei.c | 5 +++++ include/linux/namei.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index b80efc0ae0f3..efed62c6136e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2274,6 +2274,11 @@ static const char *path_init(struct nameidata *nd, unsigned flags) nd->m_seq = read_seqbegin(&mount_lock); + /* LOOKUP_IN_ROOT treats absolute paths as being relative-to-dirfd. */ + if (flags & LOOKUP_IN_ROOT) + while (*s == '/') + s++; + /* Figure out the starting path and root (if needed). */ if (*s == '/') { error = nd_jump_root(nd); diff --git a/include/linux/namei.h b/include/linux/namei.h index 88b610ca4d83..1ace31052237 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -48,8 +48,9 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_NO_MAGICLINKS 0x080000 /* No /proc/$pid/fd/ "symlink" crossing. */ #define LOOKUP_NO_SYMLINKS 0x100000 /* No symlink crossing *at all*. Implies LOOKUP_NO_MAGICLINKS. */ +#define LOOKUP_IN_ROOT 0x200000 /* Treat dirfd as %current->fs->root. */ /* LOOKUP_* flags which do scope-related checks based on the dirfd. */ -#define LOOKUP_DIRFD_SCOPE_FLAGS LOOKUP_BENEATH +#define LOOKUP_DIRFD_SCOPE_FLAGS (LOOKUP_BENEATH | LOOKUP_IN_ROOT) extern int path_pts(struct path *path); -- 2.23.0