Received: by 2002:a25:c593:0:0:0:0:0 with SMTP id v141csp1571591ybe; Fri, 6 Sep 2019 21:46:33 -0700 (PDT) X-Google-Smtp-Source: APXvYqw2gkB3WKQ+tOLh8qec8VKpOQo4KEpB3awwwL0dCy/6OWQJ9YtaoJo95tLmzRFIwVQJ9/hx X-Received: by 2002:a5d:8d8b:: with SMTP id b11mr13695694ioj.90.1567831593013; Fri, 06 Sep 2019 21:46:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1567831593; cv=none; d=google.com; s=arc-20160816; b=zTdV6YinDmrnsz61Wek9WFcHFLF+1re6ouvaR64YRdvMAXopvlfCSSroHNzNszWIGi gSdUznhUeahAt4KYt2SpfTnEMUNfAEUfogCphsUPyWrHcbLl2LVu5l2U3AhIVy7PCE7q UswygVL3Zgzhtl66vH+SuNamoLq7KkpIYHBY0mCCvNPdvJ+kM08BHNbxGn9xIjxDN1D/ gcZc17RfFCNtKp6XyIa4N4oliYAe0Xqu1gI9uRA918u1S6OdWAMRx2RO5g3YmYnOw4a/ vsPXUEtObD0YhswsTFz0yJroXWrnvxIbPI7Axjp0O3IfU10C8D6QQWK6UHieyNVi9YOO Fd+g== 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=8PtCAl4YeKmi4oI9cAH0/AwBEmmDV6Xz0XIoySOVqQ0=; b=XEh7xaGguxtnHUgd9+p+NoQrlCquceKcoxZVpF7+bCigXX0/5zfVunOluMufj10I9k xHnPRJMzWVT1Nz+XEKOY6eRGPGhv1Y0Kaglh4TL0NvR3nkLnv49v1r1q6XqaG7crpMXm yDBwLt63K5CfGw6JNyIURz7gSgaeZ1DFs3vhCT7NMzwdMvrOBP8opEW4rMjzRYHe1JZd RncxxoWu/p8XqaL2wphcq9i6N5VRxUVt64cznswNSqGxgFbHLTrHHBHxEikkycqncO/L hUDUtyeIlByko3T6oULxAVMpaokiSn8qgjV5l9AI2glhrlVxeJugMRGkIgkDQdUqlj5m B1oQ== 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 s19si10514585jam.89.2019.09.06.21.46.17; Fri, 06 Sep 2019 21:46:32 -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 S2405742AbfIFP0p (ORCPT + 99 others); Fri, 6 Sep 2019 11:26:45 -0400 Received: from smtp-sh2.infomaniak.ch ([128.65.195.6]:33283 "EHLO smtp-sh2.infomaniak.ch" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404269AbfIFP0i (ORCPT ); Fri, 6 Sep 2019 11:26:38 -0400 Received: from smtp5.infomaniak.ch (smtp5.infomaniak.ch [83.166.132.18]) by smtp-sh2.infomaniak.ch (8.14.4/8.14.4/Debian-8+deb8u2) with ESMTP id x86FP7rm085954 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 6 Sep 2019 17:25:07 +0200 Received: from localhost (ns3096276.ip-94-23-54.eu [94.23.54.103]) (authenticated bits=0) by smtp5.infomaniak.ch (8.14.5/8.14.5) with ESMTP id x86FP6Sd047657; Fri, 6 Sep 2019 17:25:06 +0200 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= To: linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= , Aleksa Sarai , Alexei Starovoitov , Al Viro , Andy Lutomirski , Christian Heimes , Daniel Borkmann , Eric Chiang , Florian Weimer , James Morris , Jan Kara , Jann Horn , Jonathan Corbet , Kees Cook , Matthew Garrett , Matthew Wilcox , Michael Kerrisk , =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= , Mimi Zohar , =?UTF-8?q?Philippe=20Tr=C3=A9buchet?= , Scott Shell , Sean Christopherson , Shuah Khan , Song Liu , Steve Dower , Steve Grubb , Thibaut Sautereau , Vincent Strubel , Yves-Alexis Perez , kernel-hardening@lists.openwall.com, linux-api@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH v2 3/5] fs: Enable to enforce noexec mounts or file exec through O_MAYEXEC Date: Fri, 6 Sep 2019 17:24:53 +0200 Message-Id: <20190906152455.22757-4-mic@digikod.net> X-Mailer: git-send-email 2.23.0.rc1 In-Reply-To: <20190906152455.22757-1-mic@digikod.net> References: <20190906152455.22757-1-mic@digikod.net> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Antivirus: Dr.Web (R) for Unix mail servers drweb plugin ver.6.0.2.8 X-Antivirus-Code: 0x100000 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Enable to either propagate the mount options from the underlying VFS mount to prevent execution, or to propagate the file execute permission. This may allow a script interpreter to check execution permissions before reading commands from a file. The main goal is to be able to protect the kernel by restricting arbitrary syscalls that an attacker could perform with a crafted binary or certain script languages. It also improves multilevel isolation by reducing the ability of an attacker to use side channels with specific code. These restrictions can natively be enforced for ELF binaries (with the noexec mount option) but require this kernel extension to properly handle scripts (e.g., Python, Perl). Add a new sysctl fs.open_mayexec_enforce to control this behavior. A following patch adds documentation. Changes since v1: * move code from Yama to the FS subsystem (suggested by Kees Cook) * make omayexec_inode_permission() static (suggested by Jann Horn) * use mode 0600 for the sysctl * only match regular files (not directories nor other types), which follows the same semantic as commit 73601ea5b7b1 ("fs/open.c: allow opening only regular files during execve()") Signed-off-by: Mickaël Salaün Reviewed-by: Philippe Trébuchet Reviewed-by: Thibaut Sautereau Cc: Al Viro Cc: Kees Cook Cc: Mickaël Salaün --- fs/namei.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 3 ++ kernel/sysctl.c | 7 +++++ 3 files changed, 78 insertions(+) diff --git a/fs/namei.c b/fs/namei.c index 0a6b9483d0cb..abd29a76ecef 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "internal.h" #include "mount.h" @@ -411,6 +412,34 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask) return 0; } +#define OMAYEXEC_ENFORCE_NONE 0 +#define OMAYEXEC_ENFORCE_MOUNT (1 << 0) +#define OMAYEXEC_ENFORCE_FILE (1 << 1) +#define _OMAYEXEC_LAST OMAYEXEC_ENFORCE_FILE +#define _OMAYEXEC_MASK ((_OMAYEXEC_LAST << 1) - 1) + +/** + * omayexec_inode_permission - check O_MAYEXEC before accessing an inode + * @inode: inode structure to check + * @mask: permission mask + * + * Return 0 if access is permitted, -EACCES otherwise. + */ +static int omayexec_inode_permission(struct inode *inode, int mask) +{ + if (!(mask & MAY_OPENEXEC)) + return 0; + + if ((sysctl_omayexec_enforce & OMAYEXEC_ENFORCE_MOUNT) && + !(mask & MAY_EXECMOUNT)) + return -EACCES; + + if (sysctl_omayexec_enforce & OMAYEXEC_ENFORCE_FILE) + return generic_permission(inode, MAY_EXEC); + + return 0; +} + /** * inode_permission - Check for access rights to a given inode * @inode: Inode to check permission on @@ -454,10 +483,48 @@ int inode_permission(struct inode *inode, int mask) if (retval) return retval; + retval = omayexec_inode_permission(inode, mask); + if (retval) + return retval; + return security_inode_permission(inode, mask); } EXPORT_SYMBOL(inode_permission); +/* + * Handle open_mayexec_enforce sysctl + */ +#ifdef CONFIG_SYSCTL +int proc_omayexec(struct ctl_table *table, int write, void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + int error; + + if (write) { + struct ctl_table table_copy; + int tmp_mayexec_enforce; + + if (!capable(CAP_MAC_ADMIN)) + return -EPERM; + tmp_mayexec_enforce = *((int *)table->data); + table_copy = *table; + /* do not erase sysctl_omayexec_enforce */ + table_copy.data = &tmp_mayexec_enforce; + error = proc_dointvec(&table_copy, write, buffer, lenp, ppos); + if (error) + return error; + if ((tmp_mayexec_enforce | _OMAYEXEC_MASK) != _OMAYEXEC_MASK) + return -EINVAL; + *((int *)table->data) = tmp_mayexec_enforce; + } else { + error = proc_dointvec(table, write, buffer, lenp, ppos); + if (error) + return error; + } + return 0; +} +#endif + /** * path_get - get a reference to a path * @path: path to get the reference to @@ -887,6 +954,7 @@ int sysctl_protected_symlinks __read_mostly = 0; int sysctl_protected_hardlinks __read_mostly = 0; int sysctl_protected_fifos __read_mostly; int sysctl_protected_regular __read_mostly; +int sysctl_omayexec_enforce __read_mostly = OMAYEXEC_ENFORCE_NONE; /** * may_follow_link - Check symlink following for unsafe situations diff --git a/include/linux/fs.h b/include/linux/fs.h index e57609dac8dd..735f5950cfed 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -81,6 +81,7 @@ extern int sysctl_protected_symlinks; extern int sysctl_protected_hardlinks; extern int sysctl_protected_fifos; extern int sysctl_protected_regular; +extern int sysctl_omayexec_enforce; typedef __kernel_rwf_t rwf_t; @@ -3452,6 +3453,8 @@ int proc_nr_dentry(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); int proc_nr_inodes(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); +int proc_omayexec(struct ctl_table *table, int write, void __user *buffer, + size_t *lenp, loff_t *ppos); int __init get_filesystem_list(char *buf); #define __FMODE_EXEC ((__force int) FMODE_EXEC) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 078950d9605b..eaaeb229a828 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1911,6 +1911,13 @@ static struct ctl_table fs_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = &two, }, + { + .procname = "open_mayexec_enforce", + .data = &sysctl_omayexec_enforce, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_omayexec, + }, #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) { .procname = "binfmt_misc", -- 2.23.0