diff mbox series

[v2,5/5] sysctl: add support for mfd_noexec

Message ID 20220805222126.142525-6-jeffxu@google.com
State New
Headers show
Series mm/memfd: MFD_NOEXEC for memfd_create | expand

Commit Message

Jeff Xu Aug. 5, 2022, 10:21 p.m. UTC
From: Jeff Xu <jeffxu@chromium.org>

Add vm.mfd_noexec.  When the value is 1 (enabled),
memfd_create syscall will created non-executable memfd.

The default value is 0 (disabled), admin can change the
setting from 0 => 1, however 1 => 0 is not allowed,
unless reboot.

Signed-off-by: Jeff Xu <jeffxu@chromium.org>
---
 include/linux/mm.h |  4 ++++
 kernel/sysctl.c    |  9 +++++++++
 mm/memfd.c         | 27 +++++++++++++++++++++++++++
 3 files changed, 40 insertions(+)

Comments

kernel test robot Aug. 13, 2022, 7:06 p.m. UTC | #1
Hi,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on 9e2f40233670c70c25e0681cb66d50d1e2742829]

url:    https://github.com/intel-lab-lkp/linux/commits/jeffxu-google-com/mm-memfd-MFD_NOEXEC-for-memfd_create/20220806-062430
base:   9e2f40233670c70c25e0681cb66d50d1e2742829
config: openrisc-randconfig-r004-20220805 (https://download.01.org/0day-ci/archive/20220814/202208140205.5zR1h5VB-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/e71897c778df5381c6d1ca858ae096a557a08a2a
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review jeffxu-google-com/mm-memfd-MFD_NOEXEC-for-memfd_create/20220806-062430
        git checkout e71897c778df5381c6d1ca858ae096a557a08a2a
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=openrisc SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> or1k-linux-ld: kernel/sysctl.o:(.data+0x440): undefined reference to `sysctl_mfd_noexec_scope'
>> or1k-linux-ld: kernel/sysctl.o:(.data+0x450): undefined reference to `mfd_noexec_dointvec_minmax'
diff mbox series

Patch

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7898e29bcfb5..1c66cf4aca11 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -203,6 +203,10 @@  extern int sysctl_overcommit_memory;
 extern int sysctl_overcommit_ratio;
 extern unsigned long sysctl_overcommit_kbytes;
 
+extern int sysctl_mfd_noexec_scope;
+extern int mfd_noexec_dointvec_minmax(struct ctl_table *table, int write,
+		void *buffer, size_t *lenp, loff_t *ppos);
+
 int overcommit_ratio_handler(struct ctl_table *, int, void *, size_t *,
 		loff_t *);
 int overcommit_kbytes_handler(struct ctl_table *, int, void *, size_t *,
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index b233714a1c78..54510da007ff 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2362,6 +2362,15 @@  static struct ctl_table vm_table[] = {
 		.mode		= 0644,
 		.proc_handler	= mmap_min_addr_handler,
 	},
+	{
+		.procname       = "mfd_noexec",
+		.data           = &sysctl_mfd_noexec_scope,
+		.maxlen         = sizeof(sysctl_mfd_noexec_scope),
+		.mode           = 0644,
+		.proc_handler   = mfd_noexec_dointvec_minmax,
+		.extra1         = SYSCTL_ZERO,
+		.extra2         = SYSCTL_ONE,
+	},
 #endif
 #ifdef CONFIG_NUMA
 	{
diff --git a/mm/memfd.c b/mm/memfd.c
index b841514eb0fd..c6ccb8481ed2 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -20,6 +20,11 @@ 
 #include <linux/memfd.h>
 #include <uapi/linux/memfd.h>
 
+#define MFD_NOEXEC_SCOPE_DISABLED	0
+#define MFD_NOEXEC_SCOPE_ENABLED	1
+
+int sysctl_mfd_noexec_scope __read_mostly = MFD_NOEXEC_SCOPE_DISABLED;
+
 /*
  * We need a tag: a new tag would expand every xa_node by 8 bytes,
  * so reuse a tag which we firmly believe is never set or cleared on tmpfs
@@ -275,6 +280,10 @@  SYSCALL_DEFINE2(memfd_create,
 	char *name;
 	long len;
 
+	if (sysctl_mfd_noexec_scope == MFD_NOEXEC_SCOPE_ENABLED) {
+		flags |= MFD_NOEXEC;
+	}
+
 	if (!(flags & MFD_HUGETLB)) {
 		if (flags & ~(unsigned int)MFD_ALL_FLAGS)
 			return -EINVAL;
@@ -351,3 +360,21 @@  SYSCALL_DEFINE2(memfd_create,
 	kfree(name);
 	return error;
 }
+
+#ifdef CONFIG_SYSCTL
+int mfd_noexec_dointvec_minmax(struct ctl_table *table, int write,
+		void *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct ctl_table table_copy;
+
+	if (write && !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	/* Lock the max value if it ever gets set. */
+	table_copy = *table;
+	if (*(int *)table_copy.data == *(int *)table_copy.extra2)
+		table_copy.extra1 = table_copy.extra2;
+
+	return proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos);
+}
+#endif