diff options
-rw-r--r-- | Documentation/sysctl/vm.txt | 15 | ||||
-rw-r--r-- | include/linux/security.h | 17 | ||||
-rw-r--r-- | kernel/sysctl.c | 10 | ||||
-rw-r--r-- | mm/mmap.c | 4 | ||||
-rw-r--r-- | mm/mremap.c | 13 | ||||
-rw-r--r-- | mm/nommu.c | 2 | ||||
-rw-r--r-- | security/dummy.c | 6 | ||||
-rw-r--r-- | security/security.c | 2 | ||||
-rw-r--r-- | security/selinux/hooks.c | 12 | ||||
-rw-r--r-- | security/selinux/include/av_perm_to_string.h | 1 | ||||
-rw-r--r-- | security/selinux/include/av_permissions.h | 1 | ||||
-rw-r--r-- | security/selinux/include/class_to_string.h | 1 | ||||
-rw-r--r-- | security/selinux/include/flask.h | 1 |
13 files changed, 70 insertions, 15 deletions
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 1d192565e182..8cfca173d4bc 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt | |||
@@ -31,6 +31,7 @@ Currently, these files are in /proc/sys/vm: | |||
31 | - min_unmapped_ratio | 31 | - min_unmapped_ratio |
32 | - min_slab_ratio | 32 | - min_slab_ratio |
33 | - panic_on_oom | 33 | - panic_on_oom |
34 | - mmap_min_address | ||
34 | 35 | ||
35 | ============================================================== | 36 | ============================================================== |
36 | 37 | ||
@@ -216,3 +217,17 @@ above-mentioned. | |||
216 | The default value is 0. | 217 | The default value is 0. |
217 | 1 and 2 are for failover of clustering. Please select either | 218 | 1 and 2 are for failover of clustering. Please select either |
218 | according to your policy of failover. | 219 | according to your policy of failover. |
220 | |||
221 | ============================================================== | ||
222 | |||
223 | mmap_min_addr | ||
224 | |||
225 | This file indicates the amount of address space which a user process will | ||
226 | be restricted from mmaping. Since kernel null dereference bugs could | ||
227 | accidentally operate based on the information in the first couple of pages | ||
228 | of memory userspace processes should not be allowed to write to them. By | ||
229 | default this value is set to 0 and no protections will be enforced by the | ||
230 | security module. Setting this value to something like 64k will allow the | ||
231 | vast majority of applications to work correctly and provide defense in depth | ||
232 | against future potential kernel bugs. | ||
233 | |||
diff --git a/include/linux/security.h b/include/linux/security.h index 9eb9e0fe0331..c11dc8aa0351 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -71,6 +71,7 @@ struct xfrm_user_sec_ctx; | |||
71 | extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); | 71 | extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); |
72 | extern int cap_netlink_recv(struct sk_buff *skb, int cap); | 72 | extern int cap_netlink_recv(struct sk_buff *skb, int cap); |
73 | 73 | ||
74 | extern unsigned long mmap_min_addr; | ||
74 | /* | 75 | /* |
75 | * Values used in the task_security_ops calls | 76 | * Values used in the task_security_ops calls |
76 | */ | 77 | */ |
@@ -1241,8 +1242,9 @@ struct security_operations { | |||
1241 | int (*file_ioctl) (struct file * file, unsigned int cmd, | 1242 | int (*file_ioctl) (struct file * file, unsigned int cmd, |
1242 | unsigned long arg); | 1243 | unsigned long arg); |
1243 | int (*file_mmap) (struct file * file, | 1244 | int (*file_mmap) (struct file * file, |
1244 | unsigned long reqprot, | 1245 | unsigned long reqprot, unsigned long prot, |
1245 | unsigned long prot, unsigned long flags); | 1246 | unsigned long flags, unsigned long addr, |
1247 | unsigned long addr_only); | ||
1246 | int (*file_mprotect) (struct vm_area_struct * vma, | 1248 | int (*file_mprotect) (struct vm_area_struct * vma, |
1247 | unsigned long reqprot, | 1249 | unsigned long reqprot, |
1248 | unsigned long prot); | 1250 | unsigned long prot); |
@@ -1814,9 +1816,12 @@ static inline int security_file_ioctl (struct file *file, unsigned int cmd, | |||
1814 | 1816 | ||
1815 | static inline int security_file_mmap (struct file *file, unsigned long reqprot, | 1817 | static inline int security_file_mmap (struct file *file, unsigned long reqprot, |
1816 | unsigned long prot, | 1818 | unsigned long prot, |
1817 | unsigned long flags) | 1819 | unsigned long flags, |
1820 | unsigned long addr, | ||
1821 | unsigned long addr_only) | ||
1818 | { | 1822 | { |
1819 | return security_ops->file_mmap (file, reqprot, prot, flags); | 1823 | return security_ops->file_mmap (file, reqprot, prot, flags, addr, |
1824 | addr_only); | ||
1820 | } | 1825 | } |
1821 | 1826 | ||
1822 | static inline int security_file_mprotect (struct vm_area_struct *vma, | 1827 | static inline int security_file_mprotect (struct vm_area_struct *vma, |
@@ -2489,7 +2494,9 @@ static inline int security_file_ioctl (struct file *file, unsigned int cmd, | |||
2489 | 2494 | ||
2490 | static inline int security_file_mmap (struct file *file, unsigned long reqprot, | 2495 | static inline int security_file_mmap (struct file *file, unsigned long reqprot, |
2491 | unsigned long prot, | 2496 | unsigned long prot, |
2492 | unsigned long flags) | 2497 | unsigned long flags, |
2498 | unsigned long addr, | ||
2499 | unsigned long addr_only) | ||
2493 | { | 2500 | { |
2494 | return 0; | 2501 | return 0; |
2495 | } | 2502 | } |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 51f5dac42a00..d93e13d93f24 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -949,6 +949,16 @@ static ctl_table vm_table[] = { | |||
949 | .strategy = &sysctl_jiffies, | 949 | .strategy = &sysctl_jiffies, |
950 | }, | 950 | }, |
951 | #endif | 951 | #endif |
952 | #ifdef CONFIG_SECURITY | ||
953 | { | ||
954 | .ctl_name = CTL_UNNUMBERED, | ||
955 | .procname = "mmap_min_addr", | ||
956 | .data = &mmap_min_addr, | ||
957 | .maxlen = sizeof(unsigned long), | ||
958 | .mode = 0644, | ||
959 | .proc_handler = &proc_doulongvec_minmax, | ||
960 | }, | ||
961 | #endif | ||
952 | #if defined(CONFIG_X86_32) || \ | 962 | #if defined(CONFIG_X86_32) || \ |
953 | (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL)) | 963 | (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL)) |
954 | { | 964 | { |
@@ -1023,10 +1023,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, | |||
1023 | } | 1023 | } |
1024 | } | 1024 | } |
1025 | 1025 | ||
1026 | error = security_file_mmap(file, reqprot, prot, flags); | 1026 | error = security_file_mmap(file, reqprot, prot, flags, addr, 0); |
1027 | if (error) | 1027 | if (error) |
1028 | return error; | 1028 | return error; |
1029 | 1029 | ||
1030 | /* Clear old maps */ | 1030 | /* Clear old maps */ |
1031 | error = -ENOMEM; | 1031 | error = -ENOMEM; |
1032 | munmap_back: | 1032 | munmap_back: |
diff --git a/mm/mremap.c b/mm/mremap.c index 5d4bd4f95b8e..bc7c52efc71b 100644 --- a/mm/mremap.c +++ b/mm/mremap.c | |||
@@ -291,6 +291,10 @@ unsigned long do_mremap(unsigned long addr, | |||
291 | if ((addr <= new_addr) && (addr+old_len) > new_addr) | 291 | if ((addr <= new_addr) && (addr+old_len) > new_addr) |
292 | goto out; | 292 | goto out; |
293 | 293 | ||
294 | ret = security_file_mmap(0, 0, 0, 0, new_addr, 1); | ||
295 | if (ret) | ||
296 | goto out; | ||
297 | |||
294 | ret = do_munmap(mm, new_addr, new_len); | 298 | ret = do_munmap(mm, new_addr, new_len); |
295 | if (ret) | 299 | if (ret) |
296 | goto out; | 300 | goto out; |
@@ -390,8 +394,13 @@ unsigned long do_mremap(unsigned long addr, | |||
390 | 394 | ||
391 | new_addr = get_unmapped_area(vma->vm_file, 0, new_len, | 395 | new_addr = get_unmapped_area(vma->vm_file, 0, new_len, |
392 | vma->vm_pgoff, map_flags); | 396 | vma->vm_pgoff, map_flags); |
393 | ret = new_addr; | 397 | if (new_addr & ~PAGE_MASK) { |
394 | if (new_addr & ~PAGE_MASK) | 398 | ret = new_addr; |
399 | goto out; | ||
400 | } | ||
401 | |||
402 | ret = security_file_mmap(0, 0, 0, 0, new_addr, 1); | ||
403 | if (ret) | ||
395 | goto out; | 404 | goto out; |
396 | } | 405 | } |
397 | ret = move_vma(vma, addr, old_len, new_len, new_addr); | 406 | ret = move_vma(vma, addr, old_len, new_len, new_addr); |
diff --git a/mm/nommu.c b/mm/nommu.c index 2b16b00a5b11..989e2e9af5c3 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -639,7 +639,7 @@ static int validate_mmap_request(struct file *file, | |||
639 | } | 639 | } |
640 | 640 | ||
641 | /* allow the security API to have its say */ | 641 | /* allow the security API to have its say */ |
642 | ret = security_file_mmap(file, reqprot, prot, flags); | 642 | ret = security_file_mmap(file, reqprot, prot, flags, addr, 0); |
643 | if (ret < 0) | 643 | if (ret < 0) |
644 | return ret; | 644 | return ret; |
645 | 645 | ||
diff --git a/security/dummy.c b/security/dummy.c index 8ffd76405b5b..d6a112ce2975 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -420,8 +420,12 @@ static int dummy_file_ioctl (struct file *file, unsigned int command, | |||
420 | 420 | ||
421 | static int dummy_file_mmap (struct file *file, unsigned long reqprot, | 421 | static int dummy_file_mmap (struct file *file, unsigned long reqprot, |
422 | unsigned long prot, | 422 | unsigned long prot, |
423 | unsigned long flags) | 423 | unsigned long flags, |
424 | unsigned long addr, | ||
425 | unsigned long addr_only) | ||
424 | { | 426 | { |
427 | if (addr < mmap_min_addr) | ||
428 | return -EACCES; | ||
425 | return 0; | 429 | return 0; |
426 | } | 430 | } |
427 | 431 | ||
diff --git a/security/security.c b/security/security.c index fc8601b2b7ac..024484fc59b0 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -24,6 +24,7 @@ extern struct security_operations dummy_security_ops; | |||
24 | extern void security_fixup_ops(struct security_operations *ops); | 24 | extern void security_fixup_ops(struct security_operations *ops); |
25 | 25 | ||
26 | struct security_operations *security_ops; /* Initialized to NULL */ | 26 | struct security_operations *security_ops; /* Initialized to NULL */ |
27 | unsigned long mmap_min_addr; /* 0 means no protection */ | ||
27 | 28 | ||
28 | static inline int verify(struct security_operations *ops) | 29 | static inline int verify(struct security_operations *ops) |
29 | { | 30 | { |
@@ -176,4 +177,5 @@ EXPORT_SYMBOL_GPL(register_security); | |||
176 | EXPORT_SYMBOL_GPL(unregister_security); | 177 | EXPORT_SYMBOL_GPL(unregister_security); |
177 | EXPORT_SYMBOL_GPL(mod_reg_security); | 178 | EXPORT_SYMBOL_GPL(mod_reg_security); |
178 | EXPORT_SYMBOL_GPL(mod_unreg_security); | 179 | EXPORT_SYMBOL_GPL(mod_unreg_security); |
180 | EXPORT_SYMBOL_GPL(mmap_min_addr); | ||
179 | EXPORT_SYMBOL(security_ops); | 181 | EXPORT_SYMBOL(security_ops); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b29059ecc045..78c3f98fcdcf 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -2569,12 +2569,16 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared | |||
2569 | } | 2569 | } |
2570 | 2570 | ||
2571 | static int selinux_file_mmap(struct file *file, unsigned long reqprot, | 2571 | static int selinux_file_mmap(struct file *file, unsigned long reqprot, |
2572 | unsigned long prot, unsigned long flags) | 2572 | unsigned long prot, unsigned long flags, |
2573 | unsigned long addr, unsigned long addr_only) | ||
2573 | { | 2574 | { |
2574 | int rc; | 2575 | int rc = 0; |
2576 | u32 sid = ((struct task_security_struct*)(current->security))->sid; | ||
2575 | 2577 | ||
2576 | rc = secondary_ops->file_mmap(file, reqprot, prot, flags); | 2578 | if (addr < mmap_min_addr) |
2577 | if (rc) | 2579 | rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, |
2580 | MEMPROTECT__MMAP_ZERO, NULL); | ||
2581 | if (rc || addr_only) | ||
2578 | return rc; | 2582 | return rc; |
2579 | 2583 | ||
2580 | if (selinux_checkreqprot) | 2584 | if (selinux_checkreqprot) |
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index b83e74012a97..049bf69429b6 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h | |||
@@ -158,3 +158,4 @@ | |||
158 | S_(SECCLASS_KEY, KEY__CREATE, "create") | 158 | S_(SECCLASS_KEY, KEY__CREATE, "create") |
159 | S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind") | 159 | S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind") |
160 | S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect") | 160 | S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect") |
161 | S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero") | ||
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 5fee1735bffe..eda89a2ec635 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h | |||
@@ -823,3 +823,4 @@ | |||
823 | #define DCCP_SOCKET__NAME_BIND 0x00200000UL | 823 | #define DCCP_SOCKET__NAME_BIND 0x00200000UL |
824 | #define DCCP_SOCKET__NODE_BIND 0x00400000UL | 824 | #define DCCP_SOCKET__NODE_BIND 0x00400000UL |
825 | #define DCCP_SOCKET__NAME_CONNECT 0x00800000UL | 825 | #define DCCP_SOCKET__NAME_CONNECT 0x00800000UL |
826 | #define MEMPROTECT__MMAP_ZERO 0x00000001UL | ||
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h index 378799068441..e77de0e62ea0 100644 --- a/security/selinux/include/class_to_string.h +++ b/security/selinux/include/class_to_string.h | |||
@@ -63,3 +63,4 @@ | |||
63 | S_("key") | 63 | S_("key") |
64 | S_(NULL) | 64 | S_(NULL) |
65 | S_("dccp_socket") | 65 | S_("dccp_socket") |
66 | S_("memprotect") | ||
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h index 35f309f47873..a9c2b20f14b5 100644 --- a/security/selinux/include/flask.h +++ b/security/selinux/include/flask.h | |||
@@ -49,6 +49,7 @@ | |||
49 | #define SECCLASS_PACKET 57 | 49 | #define SECCLASS_PACKET 57 |
50 | #define SECCLASS_KEY 58 | 50 | #define SECCLASS_KEY 58 |
51 | #define SECCLASS_DCCP_SOCKET 60 | 51 | #define SECCLASS_DCCP_SOCKET 60 |
52 | #define SECCLASS_MEMPROTECT 61 | ||
52 | 53 | ||
53 | /* | 54 | /* |
54 | * Security identifier indices for initial entities | 55 | * Security identifier indices for initial entities |