aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2007-06-28 15:55:21 -0400
committerJames Morris <jmorris@namei.org>2007-07-11 22:52:29 -0400
commited0321895182ffb6ecf210e066d87911b270d587 (patch)
tree832bb54666f73b06e55322df40f915c5e9ef64d7
parent13bddc2e9d591e31bf20020dc19ea6ca85de420e (diff)
security: Protection for exploiting null dereference using mmap
Add a new security check on mmap operations to see if the user is attempting to mmap to low area of the address space. The amount of space protected is indicated by the new proc tunable /proc/sys/vm/mmap_min_addr and defaults to 0, preserving existing behavior. This patch uses a new SELinux security class "memprotect." Policy already contains a number of allow rules like a_t self:process * (unconfined_t being one of them) which mean that putting this check in the process class (its best current fit) would make it useless as all user processes, which we also want to protect against, would be allowed. By taking the memprotect name of the new class it will also make it possible for us to move some of the other memory protect permissions out of 'process' and into the new class next time we bump the policy version number (which I also think is a good future idea) Acked-by: Stephen Smalley <sds@tycho.nsa.gov> Acked-by: Chris Wright <chrisw@sous-sol.org> Signed-off-by: Eric Paris <eparis@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--Documentation/sysctl/vm.txt15
-rw-r--r--include/linux/security.h17
-rw-r--r--kernel/sysctl.c10
-rw-r--r--mm/mmap.c4
-rw-r--r--mm/mremap.c13
-rw-r--r--mm/nommu.c2
-rw-r--r--security/dummy.c6
-rw-r--r--security/security.c2
-rw-r--r--security/selinux/hooks.c12
-rw-r--r--security/selinux/include/av_perm_to_string.h1
-rw-r--r--security/selinux/include/av_permissions.h1
-rw-r--r--security/selinux/include/class_to_string.h1
-rw-r--r--security/selinux/include/flask.h1
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.
216The default value is 0. 217The default value is 0.
2171 and 2 are for failover of clustering. Please select either 2181 and 2 are for failover of clustering. Please select either
218according to your policy of failover. 219according to your policy of failover.
220
221==============================================================
222
223mmap_min_addr
224
225This file indicates the amount of address space which a user process will
226be restricted from mmaping. Since kernel null dereference bugs could
227accidentally operate based on the information in the first couple of pages
228of memory userspace processes should not be allowed to write to them. By
229default this value is set to 0 and no protections will be enforced by the
230security module. Setting this value to something like 64k will allow the
231vast majority of applications to work correctly and provide defense in depth
232against 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;
71extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); 71extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
72extern int cap_netlink_recv(struct sk_buff *skb, int cap); 72extern int cap_netlink_recv(struct sk_buff *skb, int cap);
73 73
74extern 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
1815static inline int security_file_mmap (struct file *file, unsigned long reqprot, 1817static 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
1822static inline int security_file_mprotect (struct vm_area_struct *vma, 1827static 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
2490static inline int security_file_mmap (struct file *file, unsigned long reqprot, 2495static 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 {
diff --git a/mm/mmap.c b/mm/mmap.c
index 906ed402f7ca..9f70c8e8c871 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -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;
1032munmap_back: 1032munmap_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
421static int dummy_file_mmap (struct file *file, unsigned long reqprot, 421static 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;
24extern void security_fixup_ops(struct security_operations *ops); 24extern void security_fixup_ops(struct security_operations *ops);
25 25
26struct security_operations *security_ops; /* Initialized to NULL */ 26struct security_operations *security_ops; /* Initialized to NULL */
27unsigned long mmap_min_addr; /* 0 means no protection */
27 28
28static inline int verify(struct security_operations *ops) 29static inline int verify(struct security_operations *ops)
29{ 30{
@@ -176,4 +177,5 @@ EXPORT_SYMBOL_GPL(register_security);
176EXPORT_SYMBOL_GPL(unregister_security); 177EXPORT_SYMBOL_GPL(unregister_security);
177EXPORT_SYMBOL_GPL(mod_reg_security); 178EXPORT_SYMBOL_GPL(mod_reg_security);
178EXPORT_SYMBOL_GPL(mod_unreg_security); 179EXPORT_SYMBOL_GPL(mod_unreg_security);
180EXPORT_SYMBOL_GPL(mmap_min_addr);
179EXPORT_SYMBOL(security_ops); 181EXPORT_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
2571static int selinux_file_mmap(struct file *file, unsigned long reqprot, 2571static 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