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.
Unified · Split
| @@ -34,8 +34,6 @@ extern int sysctl_legacy_va_layout; · 33 unmodified lines | ||
| 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> |
| @@ -574,19 +572,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone, · 532 unmodified lines | ||
| 574 | 572 | set_page_section(page, pfn_to_section_nr(pfn)); |
| 575 | 573 | } |
| 576 | 574 | |
| 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 | −} | |
| 589 | − | |
| 590 | 575 | /* |
| 591 | 576 | * Some inline functions in vmstat.h depend on page_zone() |
| 592 | 577 | */ |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 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 @@ extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); · 61 unmodified lines | ||
| 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 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) · 46 unmodified lines | ||
| 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 | * |
| @@ -49,6 +49,7 @@ · 48 unmodified lines | ||
| 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 | |
| @@ -1306,10 +1307,10 @@ static struct ctl_table vm_table[] = { · 1251 unmodified lines | ||
| 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 | { |
| @@ -225,9 +225,9 @@ config DEFAULT_MMAP_MIN_ADDR · 224 unmodified lines | ||
| 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. |
| @@ -88,9 +88,6 @@ int sysctl_overcommit_ratio = 50; /* default is 50% */ · 87 unmodified lines | ||
| 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 |
| @@ -69,9 +69,6 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; · 68 unmodified lines | ||
| 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); |
| @@ -113,6 +113,22 @@ config SECURITY_ROOTPLUG · 112 unmodified lines | ||
| 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 |
| @@ -8,7 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack · 7 unmodified lines | ||
| 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 |
| @@ -1005,7 +1005,7 @@ int cap_file_mmap(struct file *file, unsigned long reqprot, · 1004 unmodified lines | ||
| 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 */ |
| @@ -0,0 +1,49 @@ | ||
| 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); | |
| @@ -3036,7 +3036,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot, · 3035 unmodified lines | ||
| 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) |