Security/SELinux: seperate lsm specific mmap_min_addr

Currently SELinux enforcement of controls on the ability to map low memory
is determined by the mmap_min_addr tunable. This patch causes SELinux to
ignore the tunable and instead use a seperate Kconfig option specific to how
much space the LSM should protect.

The tunable will now only control the need for CAP_SYS_RAWIO and SELinux
permissions will always protect the amount of low memory designated by
CONFIG_LSM_MMAP_MIN_ADDR.

This allows users who need to disable the mmap_min_addr controls (usual reason
being they run WINE as a non-root user) to do so and still have SELinux
controls preventing confined domains (like a web server) from being able to
map some area of low memory.

Signed-off-by: Eric Paris <eparis@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>

authored by Eric Paris and committed by James Morris 788084ab 8cf948e7

+92 -30
-15
include/linux/mm.h
··· 34 34 #define sysctl_legacy_va_layout 0 35 35 #endif 36 36 37 - extern unsigned long mmap_min_addr; 38 - 39 37 #include <asm/page.h> 40 38 #include <asm/pgtable.h> 41 39 #include <asm/processor.h> ··· 570 572 set_page_zone(page, zone); 571 573 set_page_node(page, node); 572 574 set_page_section(page, pfn_to_section_nr(pfn)); 573 - } 574 - 575 - /* 576 - * If a hint addr is less than mmap_min_addr change hint to be as 577 - * low as possible but still greater than mmap_min_addr 578 - */ 579 - static inline unsigned long round_hint_to_min(unsigned long hint) 580 - { 581 - hint &= PAGE_MASK; 582 - if (((void *)hint != NULL) && 583 - (hint < mmap_min_addr)) 584 - return PAGE_ALIGN(mmap_min_addr); 585 - return hint; 586 575 } 587 576 588 577 /*
+17
include/linux/security.h
··· 28 28 #include <linux/resource.h> 29 29 #include <linux/sem.h> 30 30 #include <linux/shm.h> 31 + #include <linux/mm.h> /* PAGE_ALIGN */ 31 32 #include <linux/msg.h> 32 33 #include <linux/sched.h> 33 34 #include <linux/key.h> ··· 96 95 extern int cap_netlink_recv(struct sk_buff *skb, int cap); 97 96 98 97 extern unsigned long mmap_min_addr; 98 + extern unsigned long dac_mmap_min_addr; 99 99 /* 100 100 * Values used in the task_security_ops calls 101 101 */ ··· 149 147 opts->num_mnt_opts = 0; 150 148 } 151 149 150 + /* 151 + * If a hint addr is less than mmap_min_addr change hint to be as 152 + * low as possible but still greater than mmap_min_addr 153 + */ 154 + static inline unsigned long round_hint_to_min(unsigned long hint) 155 + { 156 + hint &= PAGE_MASK; 157 + if (((void *)hint != NULL) && 158 + (hint < mmap_min_addr)) 159 + return PAGE_ALIGN(mmap_min_addr); 160 + return hint; 161 + } 162 + 163 + extern int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp, 164 + void __user *buffer, size_t *lenp, loff_t *ppos); 152 165 /** 153 166 * struct security_operations - main security structure 154 167 *
+4 -3
kernel/sysctl.c
··· 49 49 #include <linux/acpi.h> 50 50 #include <linux/reboot.h> 51 51 #include <linux/ftrace.h> 52 + #include <linux/security.h> 52 53 #include <linux/slow-work.h> 53 54 #include <linux/perf_counter.h> 54 55 ··· 1307 1306 { 1308 1307 .ctl_name = CTL_UNNUMBERED, 1309 1308 .procname = "mmap_min_addr", 1310 - .data = &mmap_min_addr, 1311 - .maxlen = sizeof(unsigned long), 1309 + .data = &dac_mmap_min_addr, 1310 + .maxlen = sizeof(unsigned long), 1312 1311 .mode = 0644, 1313 - .proc_handler = &proc_doulongvec_minmax, 1312 + .proc_handler = &mmap_min_addr_handler, 1314 1313 }, 1315 1314 #ifdef CONFIG_NUMA 1316 1315 {
+3 -3
mm/Kconfig
··· 225 225 For most ia64, ppc64 and x86 users with lots of address space 226 226 a value of 65536 is reasonable and should cause no problems. 227 227 On arm and other archs it should not be higher than 32768. 228 - Programs which use vm86 functionality would either need additional 229 - permissions from either the LSM or the capabilities module or have 230 - this protection disabled. 228 + Programs which use vm86 functionality or have some need to map 229 + this low address space will need CAP_SYS_RAWIO or disable this 230 + protection by setting the value to 0. 231 231 232 232 This value can be changed after boot using the 233 233 /proc/sys/vm/mmap_min_addr tunable.
-3
mm/mmap.c
··· 88 88 int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; 89 89 struct percpu_counter vm_committed_as; 90 90 91 - /* amount of vm to protect from userspace access */ 92 - unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; 93 - 94 91 /* 95 92 * Check that a process has enough memory to allocate a new virtual 96 93 * mapping. 0 means there is enough memory for the allocation to
-3
mm/nommu.c
··· 69 69 int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS; 70 70 int heap_stack_gap = 0; 71 71 72 - /* amount of vm to protect from userspace access */ 73 - unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; 74 - 75 72 atomic_long_t mmap_pages_allocated; 76 73 77 74 EXPORT_SYMBOL(mem_map);
+16
security/Kconfig
··· 113 113 114 114 If you are unsure how to answer this question, answer N. 115 115 116 + config LSM_MMAP_MIN_ADDR 117 + int "Low address space for LSM to from user allocation" 118 + depends on SECURITY && SECURITY_SELINUX 119 + default 65535 120 + help 121 + This is the portion of low virtual memory which should be protected 122 + from userspace allocation. Keeping a user from writing to low pages 123 + can help reduce the impact of kernel NULL pointer bugs. 124 + 125 + For most ia64, ppc64 and x86 users with lots of address space 126 + a value of 65536 is reasonable and should cause no problems. 127 + On arm and other archs it should not be higher than 32768. 128 + Programs which use vm86 functionality or have some need to map 129 + this low address space will need the permission specific to the 130 + systems running LSM. 131 + 116 132 source security/selinux/Kconfig 117 133 source security/smack/Kconfig 118 134 source security/tomoyo/Kconfig
+1 -1
security/Makefile
··· 8 8 subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo 9 9 10 10 # always enable default capabilities 11 - obj-y += commoncap.o 11 + obj-y += commoncap.o min_addr.o 12 12 13 13 # Object file lists 14 14 obj-$(CONFIG_SECURITY) += security.o capability.o
+1 -1
security/commoncap.c
··· 1005 1005 { 1006 1006 int ret = 0; 1007 1007 1008 - if (addr < mmap_min_addr) { 1008 + if (addr < dac_mmap_min_addr) { 1009 1009 ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO, 1010 1010 SECURITY_CAP_AUDIT); 1011 1011 /* set PF_SUPERPRIV if it turns out we allow the low mmap */
+49
security/min_addr.c
··· 1 + #include <linux/init.h> 2 + #include <linux/mm.h> 3 + #include <linux/security.h> 4 + #include <linux/sysctl.h> 5 + 6 + /* amount of vm to protect from userspace access by both DAC and the LSM*/ 7 + unsigned long mmap_min_addr; 8 + /* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */ 9 + unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; 10 + /* amount of vm to protect from userspace using the LSM = CONFIG_LSM_MMAP_MIN_ADDR */ 11 + 12 + /* 13 + * Update mmap_min_addr = max(dac_mmap_min_addr, CONFIG_LSM_MMAP_MIN_ADDR) 14 + */ 15 + static void update_mmap_min_addr(void) 16 + { 17 + #ifdef CONFIG_LSM_MMAP_MIN_ADDR 18 + if (dac_mmap_min_addr > CONFIG_LSM_MMAP_MIN_ADDR) 19 + mmap_min_addr = dac_mmap_min_addr; 20 + else 21 + mmap_min_addr = CONFIG_LSM_MMAP_MIN_ADDR; 22 + #else 23 + mmap_min_addr = dac_mmap_min_addr; 24 + #endif 25 + } 26 + 27 + /* 28 + * sysctl handler which just sets dac_mmap_min_addr = the new value and then 29 + * calls update_mmap_min_addr() so non MAP_FIXED hints get rounded properly 30 + */ 31 + int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp, 32 + void __user *buffer, size_t *lenp, loff_t *ppos) 33 + { 34 + int ret; 35 + 36 + ret = proc_doulongvec_minmax(table, write, filp, buffer, lenp, ppos); 37 + 38 + update_mmap_min_addr(); 39 + 40 + return ret; 41 + } 42 + 43 + int __init init_mmap_min_addr(void) 44 + { 45 + update_mmap_min_addr(); 46 + 47 + return 0; 48 + } 49 + pure_initcall(init_mmap_min_addr);
+1 -1
security/selinux/hooks.c
··· 3036 3036 * at bad behaviour/exploit that we always want to get the AVC, even 3037 3037 * if DAC would have also denied the operation. 3038 3038 */ 3039 - if (addr < mmap_min_addr) { 3039 + if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { 3040 3040 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, 3041 3041 MEMPROTECT__MMAP_ZERO, NULL); 3042 3042 if (rc)