Commit 788084aba2ab7348257597496befcbccabdc98a3
Committed by
James Morris
1 parent
8cf948e744
Exists in
master
and in
20 other branches
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>
Showing 11 changed files with 92 additions and 30 deletions Side-by-side Diff
include/linux/mm.h
... | ... | @@ -34,8 +34,6 @@ |
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> |
... | ... | @@ -572,19 +570,6 @@ |
572 | 570 | set_page_zone(page, zone); |
573 | 571 | set_page_node(page, node); |
574 | 572 | set_page_section(page, pfn_to_section_nr(pfn)); |
575 | -} | |
576 | - | |
577 | -/* | |
578 | - * If a hint addr is less than mmap_min_addr change hint to be as | |
579 | - * low as possible but still greater than mmap_min_addr | |
580 | - */ | |
581 | -static inline unsigned long round_hint_to_min(unsigned long hint) | |
582 | -{ | |
583 | - hint &= PAGE_MASK; | |
584 | - if (((void *)hint != NULL) && | |
585 | - (hint < mmap_min_addr)) | |
586 | - return PAGE_ALIGN(mmap_min_addr); | |
587 | - return hint; | |
588 | 573 | } |
589 | 574 | |
590 | 575 | /* |
include/linux/security.h
... | ... | @@ -28,6 +28,7 @@ |
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> |
... | ... | @@ -95,6 +96,7 @@ |
95 | 96 | extern int cap_netlink_recv(struct sk_buff *skb, int cap); |
96 | 97 | |
97 | 98 | extern unsigned long mmap_min_addr; |
99 | +extern unsigned long dac_mmap_min_addr; | |
98 | 100 | /* |
99 | 101 | * Values used in the task_security_ops calls |
100 | 102 | */ |
... | ... | @@ -147,6 +149,21 @@ |
147 | 149 | opts->num_mnt_opts = 0; |
148 | 150 | } |
149 | 151 | |
152 | +/* | |
153 | + * If a hint addr is less than mmap_min_addr change hint to be as | |
154 | + * low as possible but still greater than mmap_min_addr | |
155 | + */ | |
156 | +static inline unsigned long round_hint_to_min(unsigned long hint) | |
157 | +{ | |
158 | + hint &= PAGE_MASK; | |
159 | + if (((void *)hint != NULL) && | |
160 | + (hint < mmap_min_addr)) | |
161 | + return PAGE_ALIGN(mmap_min_addr); | |
162 | + return hint; | |
163 | +} | |
164 | + | |
165 | +extern int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp, | |
166 | + void __user *buffer, size_t *lenp, loff_t *ppos); | |
150 | 167 | /** |
151 | 168 | * struct security_operations - main security structure |
152 | 169 | * |
kernel/sysctl.c
... | ... | @@ -49,6 +49,7 @@ |
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 | |
55 | 56 | |
... | ... | @@ -1306,10 +1307,10 @@ |
1306 | 1307 | { |
1307 | 1308 | .ctl_name = CTL_UNNUMBERED, |
1308 | 1309 | .procname = "mmap_min_addr", |
1309 | - .data = &mmap_min_addr, | |
1310 | - .maxlen = sizeof(unsigned long), | |
1310 | + .data = &dac_mmap_min_addr, | |
1311 | + .maxlen = sizeof(unsigned long), | |
1311 | 1312 | .mode = 0644, |
1312 | - .proc_handler = &proc_doulongvec_minmax, | |
1313 | + .proc_handler = &mmap_min_addr_handler, | |
1313 | 1314 | }, |
1314 | 1315 | #ifdef CONFIG_NUMA |
1315 | 1316 | { |
mm/Kconfig
... | ... | @@ -225,9 +225,9 @@ |
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. |
mm/mmap.c
... | ... | @@ -88,9 +88,6 @@ |
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 |
mm/nommu.c
... | ... | @@ -69,9 +69,6 @@ |
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); |
security/Kconfig
... | ... | @@ -113,6 +113,22 @@ |
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 |
security/Makefile
security/commoncap.c
... | ... | @@ -1005,7 +1005,7 @@ |
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 */ |
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); |
security/selinux/hooks.c
... | ... | @@ -3036,7 +3036,7 @@ |
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) |