1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/init.h> 3 #include <linux/mm.h> 4 #include <linux/security.h> 5 #include <linux/sysctl.h> 6 #include <linux/minmax.h> 7 8 /* amount of vm to protect from userspace access by both DAC and the LSM*/ 9 unsigned long mmap_min_addr; 10 /* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */ 11 unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; 12 /* amount of vm to protect from userspace using the LSM = CONFIG_LSM_MMAP_MIN_ADDR */ 13 14 /* 15 * Update mmap_min_addr = max(dac_mmap_min_addr, CONFIG_LSM_MMAP_MIN_ADDR) 16 */ 17 static void update_mmap_min_addr(void) 18 { 19 #ifdef CONFIG_LSM_MMAP_MIN_ADDR 20 mmap_min_addr = umax(dac_mmap_min_addr, CONFIG_LSM_MMAP_MIN_ADDR); 21 #else 22 mmap_min_addr = dac_mmap_min_addr; 23 #endif 24 } 25 26 /* 27 * sysctl handler which just sets dac_mmap_min_addr = the new value and then 28 * calls update_mmap_min_addr() so non MAP_FIXED hints get rounded properly 29 */ 30 int mmap_min_addr_handler(const struct ctl_table *table, int write, 31 void *buffer, size_t *lenp, loff_t *ppos) 32 { 33 int ret; 34 35 if (write && !capable(CAP_SYS_RAWIO)) 36 return -EPERM; 37 38 ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos); 39 40 update_mmap_min_addr(); 41 42 return ret; 43 } 44 45 static const struct ctl_table min_addr_sysctl_table[] = { 46 { 47 .procname = "mmap_min_addr", 48 .data = &dac_mmap_min_addr, 49 .maxlen = sizeof(unsigned long), 50 .mode = 0644, 51 .proc_handler = mmap_min_addr_handler, 52 }, 53 }; 54 55 static int __init init_mmap_min_addr(void) 56 { 57 register_sysctl_init("vm", min_addr_sysctl_table); 58 update_mmap_min_addr(); 59 60 return 0; 61 } 62 pure_initcall(init_mmap_min_addr); 63