aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/mm.h15
-rw-r--r--include/linux/security.h17
-rw-r--r--kernel/sysctl.c7
-rw-r--r--mm/Kconfig6
-rw-r--r--mm/mmap.c3
-rw-r--r--mm/nommu.c3
-rw-r--r--security/Kconfig16
-rw-r--r--security/Makefile2
-rw-r--r--security/commoncap.c2
-rw-r--r--security/min_addr.c49
-rw-r--r--security/selinux/hooks.c2
11 files changed, 92 insertions, 30 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index ba3a7cb1eaa0..9a72cc78e6b8 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -34,8 +34,6 @@ extern int sysctl_legacy_va_layout;
34#define sysctl_legacy_va_layout 0 34#define sysctl_legacy_va_layout 0
35#endif 35#endif
36 36
37extern unsigned long mmap_min_addr;
38
39#include <asm/page.h> 37#include <asm/page.h>
40#include <asm/pgtable.h> 38#include <asm/pgtable.h>
41#include <asm/processor.h> 39#include <asm/processor.h>
@@ -575,19 +573,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
575} 573}
576 574
577/* 575/*
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 */
581static 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/*
591 * Some inline functions in vmstat.h depend on page_zone() 576 * Some inline functions in vmstat.h depend on page_zone()
592 */ 577 */
593#include <linux/vmstat.h> 578#include <linux/vmstat.h>
diff --git a/include/linux/security.h b/include/linux/security.h
index ac4bc3760b46..dc3472c1f781 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -28,6 +28,7 @@
28#include <linux/resource.h> 28#include <linux/resource.h>
29#include <linux/sem.h> 29#include <linux/sem.h>
30#include <linux/shm.h> 30#include <linux/shm.h>
31#include <linux/mm.h> /* PAGE_ALIGN */
31#include <linux/msg.h> 32#include <linux/msg.h>
32#include <linux/sched.h> 33#include <linux/sched.h>
33#include <linux/key.h> 34#include <linux/key.h>
@@ -95,6 +96,7 @@ extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
95extern int cap_netlink_recv(struct sk_buff *skb, int cap); 96extern int cap_netlink_recv(struct sk_buff *skb, int cap);
96 97
97extern unsigned long mmap_min_addr; 98extern unsigned long mmap_min_addr;
99extern unsigned long dac_mmap_min_addr;
98/* 100/*
99 * Values used in the task_security_ops calls 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)
147 opts->num_mnt_opts = 0; 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 */
156static 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
165extern 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 * struct security_operations - main security structure 168 * struct security_operations - main security structure
152 * 169 *
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 98e02328c67d..58be76017fd0 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -49,6 +49,7 @@
49#include <linux/acpi.h> 49#include <linux/acpi.h>
50#include <linux/reboot.h> 50#include <linux/reboot.h>
51#include <linux/ftrace.h> 51#include <linux/ftrace.h>
52#include <linux/security.h>
52#include <linux/slow-work.h> 53#include <linux/slow-work.h>
53#include <linux/perf_counter.h> 54#include <linux/perf_counter.h>
54 55
@@ -1306,10 +1307,10 @@ static struct ctl_table vm_table[] = {
1306 { 1307 {
1307 .ctl_name = CTL_UNNUMBERED, 1308 .ctl_name = CTL_UNNUMBERED,
1308 .procname = "mmap_min_addr", 1309 .procname = "mmap_min_addr",
1309 .data = &mmap_min_addr, 1310 .data = &dac_mmap_min_addr,
1310 .maxlen = sizeof(unsigned long), 1311 .maxlen = sizeof(unsigned long),
1311 .mode = 0644, 1312 .mode = 0644,
1312 .proc_handler = &proc_doulongvec_minmax, 1313 .proc_handler = &mmap_min_addr_handler,
1313 }, 1314 },
1314#ifdef CONFIG_NUMA 1315#ifdef CONFIG_NUMA
1315 { 1316 {
diff --git a/mm/Kconfig b/mm/Kconfig
index c948d4ca8bde..fe5f674d7a7d 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -225,9 +225,9 @@ config DEFAULT_MMAP_MIN_ADDR
225 For most ia64, ppc64 and x86 users with lots of address space 225 For most ia64, ppc64 and x86 users with lots of address space
226 a value of 65536 is reasonable and should cause no problems. 226 a value of 65536 is reasonable and should cause no problems.
227 On arm and other archs it should not be higher than 32768. 227 On arm and other archs it should not be higher than 32768.
228 Programs which use vm86 functionality would either need additional 228 Programs which use vm86 functionality or have some need to map
229 permissions from either the LSM or the capabilities module or have 229 this low address space will need CAP_SYS_RAWIO or disable this
230 this protection disabled. 230 protection by setting the value to 0.
231 231
232 This value can be changed after boot using the 232 This value can be changed after boot using the
233 /proc/sys/vm/mmap_min_addr tunable. 233 /proc/sys/vm/mmap_min_addr tunable.
diff --git a/mm/mmap.c b/mm/mmap.c
index 34579b23ebd5..8101de490c73 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -88,9 +88,6 @@ int sysctl_overcommit_ratio = 50; /* default is 50% */
88int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; 88int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
89struct percpu_counter vm_committed_as; 89struct percpu_counter vm_committed_as;
90 90
91/* amount of vm to protect from userspace access */
92unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
93
94/* 91/*
95 * Check that a process has enough memory to allocate a new virtual 92 * Check that a process has enough memory to allocate a new virtual
96 * mapping. 0 means there is enough memory for the allocation to 93 * mapping. 0 means there is enough memory for the allocation to
diff --git a/mm/nommu.c b/mm/nommu.c
index 53cab10fece4..28754c40be98 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -69,9 +69,6 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
69int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS; 69int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS;
70int heap_stack_gap = 0; 70int heap_stack_gap = 0;
71 71
72/* amount of vm to protect from userspace access */
73unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
74
75atomic_long_t mmap_pages_allocated; 72atomic_long_t mmap_pages_allocated;
76 73
77EXPORT_SYMBOL(mem_map); 74EXPORT_SYMBOL(mem_map);
diff --git a/security/Kconfig b/security/Kconfig
index d23c839038f0..9c60c346a91d 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -113,6 +113,22 @@ config SECURITY_ROOTPLUG
113 113
114 If you are unsure how to answer this question, answer N. 114 If you are unsure how to answer this question, answer N.
115 115
116config 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
116source security/selinux/Kconfig 132source security/selinux/Kconfig
117source security/smack/Kconfig 133source security/smack/Kconfig
118source security/tomoyo/Kconfig 134source security/tomoyo/Kconfig
diff --git a/security/Makefile b/security/Makefile
index c67557cdaa85..b56e7f9ecbc2 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -8,7 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack
8subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo 8subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo
9 9
10# always enable default capabilities 10# always enable default capabilities
11obj-y += commoncap.o 11obj-y += commoncap.o min_addr.o
12 12
13# Object file lists 13# Object file lists
14obj-$(CONFIG_SECURITY) += security.o capability.o 14obj-$(CONFIG_SECURITY) += security.o capability.o
diff --git a/security/commoncap.c b/security/commoncap.c
index 6bcf6e81e547..e3097c0a1311 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1005,7 +1005,7 @@ int cap_file_mmap(struct file *file, unsigned long reqprot,
1005{ 1005{
1006 int ret = 0; 1006 int ret = 0;
1007 1007
1008 if (addr < mmap_min_addr) { 1008 if (addr < dac_mmap_min_addr) {
1009 ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO, 1009 ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO,
1010 SECURITY_CAP_AUDIT); 1010 SECURITY_CAP_AUDIT);
1011 /* set PF_SUPERPRIV if it turns out we allow the low mmap */ 1011 /* set PF_SUPERPRIV if it turns out we allow the low mmap */
diff --git a/security/min_addr.c b/security/min_addr.c
new file mode 100644
index 000000000000..14cc7b3b8d03
--- /dev/null
+++ b/security/min_addr.c
@@ -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*/
7unsigned long mmap_min_addr;
8/* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
9unsigned 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 */
15static 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 */
31int 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
43int __init init_mmap_min_addr(void)
44{
45 update_mmap_min_addr();
46
47 return 0;
48}
49pure_initcall(init_mmap_min_addr);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e6d1432b0800..8d8b69c5664e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3036,7 +3036,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
3036 * at bad behaviour/exploit that we always want to get the AVC, even 3036 * at bad behaviour/exploit that we always want to get the AVC, even
3037 * if DAC would have also denied the operation. 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 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, 3040 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3041 MEMPROTECT__MMAP_ZERO, NULL); 3041 MEMPROTECT__MMAP_ZERO, NULL);
3042 if (rc) 3042 if (rc)