From patchwork Wed Oct 19 12:31:52 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mattias Nissler X-Patchwork-Id: 9384153 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 38420607D0 for ; Wed, 19 Oct 2016 14:28:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 299F429A36 for ; Wed, 19 Oct 2016 14:28:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1DF6D29A40; Wed, 19 Oct 2016 14:28:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 70AF829A36 for ; Wed, 19 Oct 2016 14:28:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S942009AbcJSO2N (ORCPT ); Wed, 19 Oct 2016 10:28:13 -0400 Received: from mail-qk0-f180.google.com ([209.85.220.180]:35435 "EHLO mail-qk0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932373AbcJSO2L (ORCPT ); Wed, 19 Oct 2016 10:28:11 -0400 Received: by mail-qk0-f180.google.com with SMTP id z190so38185660qkc.2 for ; Wed, 19 Oct 2016 07:28:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:from:to:cc:subject:date:message-id; bh=wOuBVfoFJkv2WSNmETfzQmZkEgRhtKHHfDawMOdQFsc=; b=in1KdQFK34EumWEwBJHklPerLy3OAA2BfKjZb2J8z7/2UdYcZ/IA9fqIr8vc7vPben 5qD7EUVBA1cpXB6zLqe3cZXuz4sduPYXkism8boRHsi0OEg1IgDz2cw4Srq/4ep07cuf 9yET7s7wdlSB5e43NF5BQwW9HMDn7U/a5QYsvtL5GpauTOi+4OeDENjLvTfP0zknt5XE dDGBrt3WNcKiRjyQzLEbUlMJHM0/1zwfY69PWTZ9Olp8s0/+HHeCQyF4BCXn58VfdzHX fzPuADsIakgqQLUff+RbPwZWPDoy9XlGMNCRdRW293okTVhZydfNLbtzUXNco9ZyeZK1 4IFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id; bh=wOuBVfoFJkv2WSNmETfzQmZkEgRhtKHHfDawMOdQFsc=; b=bWxTqEub3/KUfMNcCm4C7/JIHBgDN/bFpHsG2ywiXOGc1UUM6PBRCVjmpls9vrvISK wEY5Kr+oBIKLzp7bBbe18kncMO/AqERijNC0Z7p2cbK9CgIURJs5ttdQ1Vg3sYFU0ktf jkW9z5GWu5msmDB9l7wfpu7APJijqNKXnbKrnvbxYB+AjZ3G54/HArg4SGqz2dsv7Csj l5HkAIVZuk2zTwfhqPCqNQyfuQ8RTNLmi+uY+CiDYk5tAePWk7PkeUa2BcjEoXdT3jmg monO/8/QZpVO4rjSnPQrXCYBUgzUWUCGdV8d7HII6ciVusmabbuM35M9q93Ax1bcn1e+ 8MVg== X-Gm-Message-State: AA6/9RlfQ7U7G424VQt6l9i29H9KX0FcqPyB3htZowBWrMb2HzOJFhIILAa5+8Bvnm7G5Kds X-Received: by 10.194.189.198 with SMTP id gk6mr4174163wjc.167.1476880329839; Wed, 19 Oct 2016 05:32:09 -0700 (PDT) Received: from toroa.ham.corp.google.com ([172.16.99.5]) by smtp.gmail.com with ESMTPSA id za1sm64795006wjb.8.2016.10.19.05.32.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 19 Oct 2016 05:32:08 -0700 (PDT) From: Mattias Nissler To: linux-fsdevel@vger.kernel.org Cc: Alexander Viro , linux-kernel@vger.kernel.org, Colin Walters , "Austin S . Hemmelgarn" Subject: [PATCH v2] Add a "nosymlinks" mount option. Date: Wed, 19 Oct 2016 14:31:52 +0200 Message-Id: <1476880312-64786-1-git-send-email-mnissler@chromium.org> X-Mailer: git-send-email 2.8.0.rc3.226.g39d4020 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP For mounts that have the new "nosymlinks" option, don't follow symlinks when resolving paths. The new option is similar in spirit to the existing "nodev", "noexec", and "nosuid" options. Note that symlinks may still be created on mounts where the "nosymlinks" option is present. readlink() remains functional, so user space code that is aware of symlinks can still choose to follow them explicitly. Setting the "nosymlinks" mount option helps prevent privileged writers from modifying files unintentionally in case there is an unexpected link along the accessed path. The "nosymlinks" option is thus useful as a defensive measure for systems that need to deal with untrusted file systems in privileged contexts. Signed-off-by: Mattias Nissler --- fs/namei.c | 3 +++ fs/namespace.c | 9 ++++++--- fs/proc_namespace.c | 1 + fs/statfs.c | 2 ++ include/linux/mount.h | 3 ++- include/linux/statfs.h | 1 + include/uapi/linux/fs.h | 1 + 7 files changed, 16 insertions(+), 4 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 5b4eed2..4cddcf3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1021,6 +1021,9 @@ const char *get_link(struct nameidata *nd) touch_atime(&last->link); } + if (nd->path.mnt->mnt_flags & MNT_NOSYMLINKS) + return ERR_PTR(-EACCES); + error = security_inode_follow_link(dentry, inode, nd->flags & LOOKUP_RCU); if (unlikely(error)) diff --git a/fs/namespace.c b/fs/namespace.c index e6c234b..deec84e 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2732,6 +2732,8 @@ long do_mount(const char *dev_name, const char __user *dir_name, mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME); if (flags & MS_RDONLY) mnt_flags |= MNT_READONLY; + if (flags & MS_NOSYMLINKS) + mnt_flags |= MNT_NOSYMLINKS; /* The default atime for remount is preservation */ if ((flags & MS_REMOUNT) && @@ -2741,9 +2743,10 @@ long do_mount(const char *dev_name, const char __user *dir_name, mnt_flags |= path.mnt->mnt_flags & MNT_ATIME_MASK; } - flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | - MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | - MS_STRICTATIME | MS_NOREMOTELOCK); + flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_NOSYMLINKS | + MS_ACTIVE | MS_BORN | MS_NOATIME | MS_NODIRATIME | + MS_RELATIME | MS_KERNMOUNT | MS_STRICTATIME | + MS_NOREMOTELOCK); if (flags & MS_REMOUNT) retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index 3f1190d..a1949d9 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -67,6 +67,7 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) { MNT_NOATIME, ",noatime" }, { MNT_NODIRATIME, ",nodiratime" }, { MNT_RELATIME, ",relatime" }, + { MNT_NOSYMLINKS, ",nosymlinks" }, { 0, NULL } }; const struct proc_fs_info *fs_infop; diff --git a/fs/statfs.c b/fs/statfs.c index 083dc0a..7ff7c32 100644 --- a/fs/statfs.c +++ b/fs/statfs.c @@ -27,6 +27,8 @@ static int flags_by_mnt(int mnt_flags) flags |= ST_NODIRATIME; if (mnt_flags & MNT_RELATIME) flags |= ST_RELATIME; + if (mnt_flags & MNT_NOSYMLINKS) + flags |= ST_NOSYMLINKS; return flags; } diff --git a/include/linux/mount.h b/include/linux/mount.h index 1172cce..5e302f4 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -28,6 +28,7 @@ struct mnt_namespace; #define MNT_NODIRATIME 0x10 #define MNT_RELATIME 0x20 #define MNT_READONLY 0x40 /* does the user want this to be r/o? */ +#define MNT_NOSYMLINKS 0x80 #define MNT_SHRINKABLE 0x100 #define MNT_WRITE_HOLD 0x200 @@ -44,7 +45,7 @@ struct mnt_namespace; #define MNT_SHARED_MASK (MNT_UNBINDABLE) #define MNT_USER_SETTABLE_MASK (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC \ | MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \ - | MNT_READONLY) + | MNT_READONLY | MNT_NOSYMLINKS) #define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME ) #define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \ diff --git a/include/linux/statfs.h b/include/linux/statfs.h index 0166d32..994b059 100644 --- a/include/linux/statfs.h +++ b/include/linux/statfs.h @@ -39,5 +39,6 @@ struct kstatfs { #define ST_NOATIME 0x0400 /* do not update access times */ #define ST_NODIRATIME 0x0800 /* do not update directory access times */ #define ST_RELATIME 0x1000 /* update atime relative to mtime/ctime */ +#define ST_NOSYMLINKS 0x2000 /* do not follow symbolic links */ #endif diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index acb2b61..06193d8 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -130,6 +130,7 @@ struct inodes_stat_t { #define MS_I_VERSION (1<<23) /* Update inode I_version field */ #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ #define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */ +#define MS_NOSYMLINKS (1<<26) /* Do not follow symbolic links */ /* These sb flags are internal to the kernel */ #define MS_NOREMOTELOCK (1<<27)