From patchwork Mon Sep 4 17:54:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kleber Sacilotto de Souza X-Patchwork-Id: 809782 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 3xmHYK5TmXz9t3k; Tue, 5 Sep 2017 03:54:45 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1dova4-0006SY-N0; Mon, 04 Sep 2017 17:54:40 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1dova3-0006Ro-JB for kernel-team@lists.ubuntu.com; Mon, 04 Sep 2017 17:54:39 +0000 Received: from mail-wm0-f72.google.com ([74.125.82.72]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1dova3-0005OS-Bc for kernel-team@lists.ubuntu.com; Mon, 04 Sep 2017 17:54:39 +0000 Received: by mail-wm0-f72.google.com with SMTP id p17so1129728wmd.3 for ; Mon, 04 Sep 2017 10:54:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=ZbYo6/Sn8rDTnUWU6I2XFmDpHw/410ahkDh1TduawrE=; b=kaFQaFcwt0a5yQGxx4FzdkDiglZJQyxDYCnZPa6JjKY0MVdL2QuVnZB+NLe6TNr81I KME2gnscMy+1NrfWYBygrGo8oTg1lReU3bgtF/WcsrH+qv8PBnwk5D4BkzzkoDXXaJ9C deY9O1DzlDpd07fOS+d+id8xaWx27i9zdPLRcSJWOWElXch91k5w5yqaWwp88F1uMEHO aGV1JOsPsC1Ppa/2+9f4I30kiSGp8rHIMq3U59ux7QZqDtmsYO6pGaiECuiFdS9HmAQJ 9J9o0wtVa30t+cUxw1AxXonMqeHIC7lJO6XT3n2RiTG0tSY7VSB+juLgGKSDd/OelM3i owQA== X-Gm-Message-State: AHPjjUg/bDndG35QogAyMd1aQcdp0fqNJm/zeMo21wuF2+ubxRpxNe0u BfQvR3+FOqBNwju0AFoe31lusfVZz3Wotr+snEoPgnDEBAyX5+hj+pz37f1pRYN7a9FLP6pjgz0 EuK0fHAj4VyG+jXR2BZGOba5zv6jMF92A X-Received: by 10.80.222.203 with SMTP id d11mr1080260edl.256.1504547678661; Mon, 04 Sep 2017 10:54:38 -0700 (PDT) X-Google-Smtp-Source: ADKCNb7o81kt6IuYxk1sW0nLWsyZef8ZCeSNlrJsQiWwEQCPTdIjSGtx61rUhgTl6VJ5vWGvtwEZrQ== X-Received: by 10.80.222.203 with SMTP id d11mr1080251edl.256.1504547678357; Mon, 04 Sep 2017 10:54:38 -0700 (PDT) Received: from localhost ([2a02:8109:a540:7e8:b446:acfd:5411:b887]) by smtp.gmail.com with ESMTPSA id a28sm4410639edd.95.2017.09.04.10.54.37 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 04 Sep 2017 10:54:37 -0700 (PDT) From: Kleber Sacilotto de Souza To: kernel-team@lists.ubuntu.com Subject: [Trusty SRU][PATCH 1/2] vfs: Commit to never having exectuables on proc and sysfs. Date: Mon, 4 Sep 2017 19:54:33 +0200 Message-Id: <20170904175434.7071-2-kleber.souza@canonical.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170904175434.7071-1-kleber.souza@canonical.com> References: <20170904175434.7071-1-kleber.souza@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: "Eric W. Biederman" CVE-2016-10044 Today proc and sysfs do not contain any executable files. Several applications today mount proc or sysfs without noexec and nosuid and then depend on there being no exectuables files on proc or sysfs. Having any executable files show on proc or sysfs would cause a user space visible regression, and most likely security problems. Therefore commit to never allowing executables on proc and sysfs by adding a new flag to mark them as filesystems without executables and enforce that flag. Test the flag where MNT_NOEXEC is tested today, so that the only user visible effect will be that exectuables will be treated as if the execute bit is cleared. The filesystems proc and sysfs do not currently incoporate any executable files so this does not result in any user visible effects. This makes it unnecessary to vet changes to proc and sysfs tightly for adding exectuable files or changes to chattr that would modify existing files, as no matter what the individual file say they will not be treated as exectuable files by the vfs. Not having to vet changes to closely is important as without this we are only one proc_create call (or another goof up in the implementation of notify_change) from having problematic executables on proc. Those mistakes are all too easy to make and would create a situation where there are security issues or the assumptions of some program having to be broken (and cause userspace regressions). Signed-off-by: "Eric W. Biederman" (backported from commit 90f8572b0f021fdd1baa68e00a8c30482ee9e5f4) Signed-off-by: Kleber Sacilotto de Souza Acked-by: Colin Ian King --- fs/exec.c | 10 ++++++++-- fs/open.c | 2 +- fs/proc/root.c | 2 ++ fs/sysfs/mount.c | 3 +++ include/linux/fs.h | 2 ++ kernel/sys.c | 3 +-- mm/mmap.c | 4 ++-- mm/nommu.c | 2 +- security/security.c | 2 +- 9 files changed, 21 insertions(+), 9 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index dd7ab64bd5a2..f96daeca68a9 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -107,6 +107,12 @@ bool path_nosuid(const struct path *path) } EXPORT_SYMBOL(path_nosuid); +bool path_noexec(const struct path *path) +{ + return (path->mnt->mnt_flags & MNT_NOEXEC) || + (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); +} + /* * Note that a shared library must be both readable and executable due to * security reasons. @@ -140,7 +146,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) goto exit; error = -EACCES; - if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) + if (path_noexec(&file->f_path)) goto exit; fsnotify_open(file); @@ -798,7 +804,7 @@ struct file *open_exec(const char *name) if (!S_ISREG(file_inode(file)->i_mode)) goto exit; - if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) + if (path_noexec(&file->f_path)) goto exit; fsnotify_open(file); diff --git a/fs/open.c b/fs/open.c index 6dcf14157e27..d8aa5ebbbf84 100644 --- a/fs/open.c +++ b/fs/open.c @@ -344,7 +344,7 @@ retry: * with the "noexec" flag. */ res = -EACCES; - if (path.mnt->mnt_flags & MNT_NOEXEC) + if (path_noexec(&path)) goto out_path_release; } diff --git a/fs/proc/root.c b/fs/proc/root.c index c198775a5617..3ce05378b960 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -139,6 +139,8 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, } sb->s_flags |= MS_ACTIVE; + /* User space would break if executables appear on proc */ + sb->s_iflags |= SB_I_NOEXEC; } return dget(sb->s_root); diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index f4d0799b5779..d705cabe9d6a 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -139,6 +139,9 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, } sb->s_flags |= MS_ACTIVE; } + if (sb->s_root) + /* Userspace would break if executables appear on sysfs */ + sb->s_root->d_sb->s_iflags |= SB_I_NOEXEC; return dget(sb->s_root); } diff --git a/include/linux/fs.h b/include/linux/fs.h index 7e76dbc028d5..67a0bb3f3b19 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1221,6 +1221,7 @@ extern struct list_head super_blocks; extern spinlock_t sb_lock; /* sb->s_iflags */ +#define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ #define SB_I_NOSUID 0x00000004 /* Ignore suid on this fs */ /* Possible states of 'frozen' field */ @@ -2831,5 +2832,6 @@ static inline bool dir_relax(struct inode *inode) } extern bool path_nosuid(const struct path *path); +extern bool path_noexec(const struct path *path); #endif /* _LINUX_FS_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 17b7417d0bf6..3b663a209691 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1648,8 +1648,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) * overall picture. */ err = -EACCES; - if (!S_ISREG(inode->i_mode) || - exe.file->f_path.mnt->mnt_flags & MNT_NOEXEC) + if (!S_ISREG(inode->i_mode) || path_noexec(&exe.file->f_path)) goto exit; err = inode_permission(inode, MAY_EXEC); diff --git a/mm/mmap.c b/mm/mmap.c index 72f35bce0f16..8cbdd057bf83 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1261,7 +1261,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, * mounted, in which case we dont add PROT_EXEC.) */ if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC)) - if (!(file && (file->f_path.mnt->mnt_flags & MNT_NOEXEC))) + if (!(file && path_noexec(&file->f_path))) prot |= PROT_EXEC; if (!len) @@ -1341,7 +1341,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, case MAP_PRIVATE: if (!(file->f_mode & FMODE_READ)) return -EACCES; - if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) { + if (path_noexec(&file->f_path)) { if (vm_flags & VM_EXEC) return -EPERM; vm_flags &= ~VM_MAYEXEC; diff --git a/mm/nommu.c b/mm/nommu.c index 4efb31662bd1..e3053616ffad 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1031,7 +1031,7 @@ static int validate_mmap_request(struct file *file, /* handle executable mappings and implied executable * mappings */ - if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) { + if (path_noexec(&file->f_path)) { if (prot & PROT_EXEC) return -EPERM; } diff --git a/security/security.c b/security/security.c index ae6eba6b010d..79d239fdba70 100644 --- a/security/security.c +++ b/security/security.c @@ -719,7 +719,7 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot) * ditto if it's not on noexec mount, except that on !MMU we need * BDI_CAP_EXEC_MMAP (== VM_MAYEXEC) in this case */ - if (!(file->f_path.mnt->mnt_flags & MNT_NOEXEC)) { + if (!path_noexec(&file->f_path)) { #ifndef CONFIG_MMU unsigned long caps = 0; struct address_space *mapping = file->f_mapping;