Received: by 2002:a25:86ce:0:0:0:0:0 with SMTP id y14csp15840ybm; Mon, 20 May 2019 11:03:10 -0700 (PDT) X-Google-Smtp-Source: APXvYqxYTcbFHo+3TsHG0e7AD92ViRbahas8gwAhCpmEPUVayf+m9sJiv1H3ylGZAg7iSUg7jImC X-Received: by 2002:a63:231d:: with SMTP id j29mr50622659pgj.278.1558375389928; Mon, 20 May 2019 11:03:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1558375389; cv=none; d=google.com; s=arc-20160816; b=jwNrwNUw7talvb8HLFVK5k7TsHhpRVY6MCz+ANBvkNEyclkkXCC1i7jlUQhxt+dfjL tZVo1G/KM3anz8pt8uhLB4+Jpsr4cgCYoZ1ResjHAacMh8kgw7bTyQ4nPHGatEDXorCh b/B7hHyFWa4nwAgpNGUpwntn66QDZqXR+sg39QDg0UULrD792XtjAJfPlcmxEai5Tyi/ H9p/TGrc/NoBAwzq5f21S5FQQaVFVJroKr5sqARvZeKMLOwZS1ljk1J59Drf133QAIIH 0TagKUmqNihF3t6HdbgZdjmUOPmnLm3Tfkz8WpvqowIYv8BQg6dEeCxL4EKQc1Rd3Esc 9fVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=GLeQxBTsGB5zHhfjX+T/GPe/5uxfUYjsGHpvwvfqvAs=; b=FHBKFwVXzPIwQtye1nl8PZw+ZBAknqybjC1sOCZGZJFdw1STPj2heElRRbqrl5n1GK 9LTGJgdcTlGfcYO1AlSt+P1JuLh2yohfV4XwP3nb0shhQdZ/YU6Qq7JHEcC281jl6OKS f868WS+LThZq5yQM+uqaJLIsIictmnzBEZiVb4lZ+Ep8JWvjOXKBclf0EEWCHxcB2I5k YnuJcXYNpF1SYnri1T1hA9Xrt/oojmJ4Lpxa0gLu+LL5RXQj8esHQbT+XlyvEpnM1osq IsBqVEQvorENO9I4Pu8NDkxSQ2Sf7FlPT/N7C5RrOhEEAbxZj8wNAyI5F1cuZM/ynakl jQAQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f16si18032895pfn.127.2019.05.20.11.02.55; Mon, 20 May 2019 11:03:09 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387862AbfETNe0 (ORCPT + 99 others); Mon, 20 May 2019 09:34:26 -0400 Received: from mx2.mailbox.org ([80.241.60.215]:62748 "EHLO mx2.mailbox.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387617AbfETNeZ (ORCPT ); Mon, 20 May 2019 09:34:25 -0400 Received: from smtp2.mailbox.org (smtp2.mailbox.org [80.241.60.241]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id 0C83CA1039; Mon, 20 May 2019 15:34:23 +0200 (CEST) X-Virus-Scanned: amavisd-new at heinlein-support.de Received: from smtp2.mailbox.org ([80.241.60.241]) by spamfilter06.heinlein-hosting.de (spamfilter06.heinlein-hosting.de [80.241.56.125]) (amavisd-new, port 10030) with ESMTP id sFqK244XqxzI; Mon, 20 May 2019 15:34:20 +0200 (CEST) From: Aleksa Sarai To: Al Viro , Jeff Layton , "J. Bruce Fields" , Arnd Bergmann , David Howells , Shuah Khan , Shuah Khan Cc: Aleksa Sarai , Eric Biederman , Andy Lutomirski , Andrew Morton , Alexei Starovoitov , Kees Cook , Jann Horn , Christian Brauner , Tycho Andersen , David Drysdale , Chanho Min , Oleg Nesterov , Aleksa Sarai , Linus Torvalds , containers@lists.linux-foundation.org, linux-kselftest@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org Subject: [PATCH RFC v8 03/10] open: O_EMPTYPATH: procfs-less file descriptor re-opening Date: Mon, 20 May 2019 23:32:58 +1000 Message-Id: <20190520133305.11925-4-cyphar@cyphar.com> In-Reply-To: <20190520133305.11925-1-cyphar@cyphar.com> References: <20190520133305.11925-1-cyphar@cyphar.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Userspace has made use of /proc/self/fd very liberally to allow for descriptors to be re-opened. There are a wide variety of uses for this feature, but it has always required constructing a pathname and could not be done without procfs mounted. The obvious solution for this is to extend openat(2) to have an AT_EMPTY_PATH-equivalent -- O_EMPTYPATH. Now that descriptor re-opening has been made safe through the new magic-link resolution restrictions, we can replicate these restrictions for O_EMPTYPATH. In particular, we only allow "upgrading" the file descriptor if the corresponding FMODE_PATH_* bit is set (or the FMODE_{READ,WRITE} cases for non-O_PATH file descriptors). When doing openat(O_EMPTYPATH|O_PATH), O_PATH takes precedence and O_EMPTYPATH is ignored. Very few users ever have a need to O_PATH re-open an existing file descriptor, and so accommodating them at the expense of further complicating O_PATH makes little sense. Ultimately, if users ask for this we can always add RESOLVE_EMPTY_PATH to resolveat(2) in the future. Signed-off-by: Aleksa Sarai --- fs/fcntl.c | 2 +- fs/namei.c | 27 +++++++++++++++++++++++++++ fs/open.c | 7 ++++++- include/linux/fcntl.h | 2 +- include/uapi/asm-generic/fcntl.h | 5 +++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/fs/fcntl.c b/fs/fcntl.c index 083185174c6d..6c85c4d0c006 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -1031,7 +1031,7 @@ static int __init fcntl_init(void) * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY * is defined as O_NONBLOCK on some platforms and not on others. */ - BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != + BUILD_BUG_ON(22 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | __FMODE_EXEC | __FMODE_NONOTIFY)); diff --git a/fs/namei.c b/fs/namei.c index 5ff61624b8f0..46c5302eea4a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3599,6 +3599,31 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) return error; } +static int do_o_emptypath(struct nameidata *nd, struct file *newfile) +{ + int error; + struct fd f; + + /* We don't support AT_FDCWD since O_PATH cannot be set here. */ + f = fdget_raw(nd->dfd); + if (!f.file) + return -EBADF; + + /* Update opath_mask as though we went through trailing_symlink(). */ + if (!(f.file->f_mode & (FMODE_READ | FMODE_PATH_READ))) + nd->opath_mask &= ~FMODE_PATH_READ; + if (!(f.file->f_mode & (FMODE_WRITE | FMODE_PATH_WRITE))) + nd->opath_mask &= ~FMODE_PATH_WRITE; + + /* Obey the same restrictions as magic-links. */ + error = may_open_magiclink(f.file->f_mode, nd->acc_mode); + if (!error) + error = vfs_open(&f.file->f_path, newfile); + + fdput(f); + return error; +} + static struct file *path_openat(struct nameidata *nd, const struct open_flags *op, unsigned flags) { @@ -3614,6 +3639,8 @@ static struct file *path_openat(struct nameidata *nd, if (unlikely(file->f_flags & __O_TMPFILE)) { error = do_tmpfile(nd, flags, op, file); + } else if (unlikely(file->f_flags & O_EMPTYPATH)) { + error = do_o_emptypath(nd, file); } else if (unlikely(file->f_flags & O_PATH)) { error = do_o_path(nd, flags, file); } else { diff --git a/fs/open.c b/fs/open.c index c1d4f343e85f..a6ccfea899b9 100644 --- a/fs/open.c +++ b/fs/open.c @@ -995,6 +995,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o lookup_flags |= LOOKUP_DIRECTORY; if (!(flags & O_NOFOLLOW)) lookup_flags |= LOOKUP_FOLLOW; + if (flags & O_EMPTYPATH) + lookup_flags |= LOOKUP_EMPTY; op->lookup_flags = lookup_flags; return 0; } @@ -1056,14 +1058,17 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { struct open_flags op; int fd = build_open_flags(flags, mode, &op); + int empty = 0; struct filename *tmp; if (fd) return fd; - tmp = getname(filename); + tmp = getname_flags(filename, op.lookup_flags, &empty); if (IS_ERR(tmp)) return PTR_ERR(tmp); + if (!empty) + op.open_flag &= ~O_EMPTYPATH; fd = get_unused_fd_flags(flags); if (fd >= 0) { diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h index d019df946cb2..2868ae6c8fc1 100644 --- a/include/linux/fcntl.h +++ b/include/linux/fcntl.h @@ -9,7 +9,7 @@ (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \ FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_EMPTYPATH) #ifndef force_o_largefile #define force_o_largefile() (!IS_ENABLED(CONFIG_ARCH_32BIT_OFF_T)) diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 9dc0bf0c5a6e..307f7c414a51 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -89,6 +89,11 @@ #define __O_TMPFILE 020000000 #endif +#ifndef O_EMPTYPATH +#define O_EMPTYPATH 040000000 +#endif + + /* a horrid kludge trying to make sure that this will fail on old kernels */ #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) #define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT) -- 2.21.0