fix NULL pointer dereference in __vm_enough_memory()
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Wed, 22 Aug 2007 21:01:28 +0000 (14:01 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 23 Aug 2007 02:52:45 +0000 (19:52 -0700)
The new exec code inserts an accounted vma into an mm struct which is not
current->mm.  The existing memory check code has a hard coded assumption
that this does not happen as does the security code.

As the correct mm is known we pass the mm to the security method and the
helper function.  A new security test is added for the case where we need
to pass the mm and the existing one is modified to pass current->mm to
avoid the need to change large amounts of code.

(Thanks to Tobias for fixing rejects and testing)

Signed-off-by: Alan Cox <alan@redhat.com>
Cc: WU Fengguang <wfg@mail.ustc.edu.cn>
Cc: James Morris <jmorris@redhat.com>
Cc: Tobias Diedrich <ranma+kernel@tdiedrich.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/mm.h
include/linux/security.h
mm/mmap.c
mm/nommu.c
security/commoncap.c
security/dummy.c
security/selinux/hooks.c

index 655094dc9440fd5e8fdce2ab4f0380b83d72dd0e..1692dd6cb9153bd6fa2fcdf13f2352e84500eeae 100644 (file)
@@ -1042,7 +1042,7 @@ static inline void vma_nonlinear_insert(struct vm_area_struct *vma,
 }
 
 /* mmap.c */
-extern int __vm_enough_memory(long pages, int cap_sys_admin);
+extern int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin);
 extern void vma_adjust(struct vm_area_struct *vma, unsigned long start,
        unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert);
 extern struct vm_area_struct *vma_merge(struct mm_struct *,
index c11dc8aa0351e25be90e967a59d4f93b0f5e73b0..1a15526e9f677ce6bb402234cc4d000d5c7f7ad0 100644 (file)
@@ -54,7 +54,7 @@ extern int cap_inode_removexattr(struct dentry *dentry, char *name);
 extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
 extern void cap_task_reparent_to_init (struct task_struct *p);
 extern int cap_syslog (int type);
-extern int cap_vm_enough_memory (long pages);
+extern int cap_vm_enough_memory (struct mm_struct *mm, long pages);
 
 struct msghdr;
 struct sk_buff;
@@ -1125,6 +1125,7 @@ struct request_sock;
  *     Return 0 if permission is granted.
  * @vm_enough_memory:
  *     Check permissions for allocating a new virtual mapping.
+ *     @mm contains the mm struct it is being added to.
  *      @pages contains the number of pages.
  *     Return 0 if permission is granted.
  *
@@ -1169,7 +1170,7 @@ struct security_operations {
        int (*quota_on) (struct dentry * dentry);
        int (*syslog) (int type);
        int (*settime) (struct timespec *ts, struct timezone *tz);
-       int (*vm_enough_memory) (long pages);
+       int (*vm_enough_memory) (struct mm_struct *mm, long pages);
 
        int (*bprm_alloc_security) (struct linux_binprm * bprm);
        void (*bprm_free_security) (struct linux_binprm * bprm);
@@ -1469,10 +1470,14 @@ static inline int security_settime(struct timespec *ts, struct timezone *tz)
        return security_ops->settime(ts, tz);
 }
 
-
 static inline int security_vm_enough_memory(long pages)
 {
-       return security_ops->vm_enough_memory(pages);
+       return security_ops->vm_enough_memory(current->mm, pages);
+}
+
+static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
+{
+       return security_ops->vm_enough_memory(mm, pages);
 }
 
 static inline int security_bprm_alloc (struct linux_binprm *bprm)
@@ -2219,7 +2224,12 @@ static inline int security_settime(struct timespec *ts, struct timezone *tz)
 
 static inline int security_vm_enough_memory(long pages)
 {
-       return cap_vm_enough_memory(pages);
+       return cap_vm_enough_memory(current->mm, pages);
+}
+
+static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
+{
+       return cap_vm_enough_memory(mm, pages);
 }
 
 static inline int security_bprm_alloc (struct linux_binprm *bprm)
index b6537211b9ccfdfcf1f7d9d63c5891ba89e483e7..0d40e66c841b2d2cad8e03ebc6d5e16491b0774b 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -93,7 +93,7 @@ atomic_t vm_committed_space = ATOMIC_INIT(0);
  * Note this is a helper function intended to be used by LSMs which
  * wish to use this logic.
  */
-int __vm_enough_memory(long pages, int cap_sys_admin)
+int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
 {
        unsigned long free, allowed;
 
@@ -166,7 +166,7 @@ int __vm_enough_memory(long pages, int cap_sys_admin)
 
        /* Don't let a single process grow too big:
           leave 3% of the size of this process for other processes */
-       allowed -= current->mm->total_vm / 32;
+       allowed -= mm->total_vm / 32;
 
        /*
         * cast `allowed' as a signed long because vm_committed_space
@@ -2077,7 +2077,7 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
        if (__vma && __vma->vm_start < vma->vm_end)
                return -ENOMEM;
        if ((vma->vm_flags & VM_ACCOUNT) &&
-            security_vm_enough_memory(vma_pages(vma)))
+            security_vm_enough_memory_mm(mm, vma_pages(vma)))
                return -ENOMEM;
        vma_link(mm, vma, prev, rb_link, rb_parent);
        return 0;
index 9eef6a3985554fa9b69c54a0334865e54247e478..8ed0cb43118a1fc0586b165b49e6ad8e7c8a8efb 100644 (file)
@@ -1270,7 +1270,7 @@ EXPORT_SYMBOL(get_unmapped_area);
  * Note this is a helper function intended to be used by LSMs which
  * wish to use this logic.
  */
-int __vm_enough_memory(long pages, int cap_sys_admin)
+int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
 {
        unsigned long free, allowed;
 
index 338606eb7238007ea058e4c542d6fd68fb354c51..7520361663e88eef2dc96cf42e3c62571fe7a4d7 100644 (file)
@@ -315,13 +315,13 @@ int cap_syslog (int type)
        return 0;
 }
 
-int cap_vm_enough_memory(long pages)
+int cap_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int cap_sys_admin = 0;
 
        if (cap_capable(current, CAP_SYS_ADMIN) == 0)
                cap_sys_admin = 1;
-       return __vm_enough_memory(pages, cap_sys_admin);
+       return __vm_enough_memory(mm, pages, cap_sys_admin);
 }
 
 EXPORT_SYMBOL(cap_capable);
index 19d813d5e0837beaa6c332254c8538ff1d2b63d8..853ec2292798261bc675642e685cb27d84469919 100644 (file)
@@ -108,13 +108,13 @@ static int dummy_settime(struct timespec *ts, struct timezone *tz)
        return 0;
 }
 
-static int dummy_vm_enough_memory(long pages)
+static int dummy_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int cap_sys_admin = 0;
 
        if (dummy_capable(current, CAP_SYS_ADMIN) == 0)
                cap_sys_admin = 1;
-       return __vm_enough_memory(pages, cap_sys_admin);
+       return __vm_enough_memory(mm, pages, cap_sys_admin);
 }
 
 static int dummy_bprm_alloc_security (struct linux_binprm *bprm)
index 6237933f7d82c3454c4409a00a1aa779ef5ceee3..d8bc4172819c96bcefc49d69bf42f6619d6e4f04 100644 (file)
@@ -1584,7 +1584,7 @@ static int selinux_syslog(int type)
  * Do not audit the selinux permission check, as this is applied to all
  * processes that allocate mappings.
  */
-static int selinux_vm_enough_memory(long pages)
+static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int rc, cap_sys_admin = 0;
        struct task_security_struct *tsec = current->security;
@@ -1600,7 +1600,7 @@ static int selinux_vm_enough_memory(long pages)
        if (rc == 0)
                cap_sys_admin = 1;
 
-       return __vm_enough_memory(pages, cap_sys_admin);
+       return __vm_enough_memory(mm, pages, cap_sys_admin);
 }
 
 /* binprm security operations */