• R/O
  • HTTP
  • SSH
  • HTTPS

linux-2.4.36: Commit

2.4.36-stable kernel tree


Commit MetaInfo

Revision97fdf52693285f9344973da3fa4e936068b3b4f3 (tree)
Zeit2007-09-09 02:41:48
AutorWilly Tarreau <w@1wt....>
CommiterWilly Tarreau

Log Message

[PATCH] sysctl to prevent normal processes from mapping NULL

After a patch proposal from Solar Designer, and discussions with
Alan Cox and Chris Wright, I modeled this patch which permits to
restrict mapping of lower virtual addresses to CAP_RAW_IO capable
processes only.

This makes it harder for processes to try to exploit NULL pointer
dereference bugs in the kernel.

In order to ease transition from 2.4 to 2.6, the patch has also
been inspired by Eric Paris's patch now present in 2.6, which
adds the sys/vm/mmap_min_addr sysctl by which the lowest mappable
address is set. This sysctl defaults to zero, meaning NULL is
allowed by default.

According to test ran by Solar Designer, both Xorg and Wine run
correctly as a normal user with the restriction enabled. There
should be very few regressions when enabling it, and it is
recommended to enable it on servers after the obviously needed
validation.

Alan points that some rare programs use a trick consisting in
mapping this page in order to reduce the number of NULL checks
in linked lists for instance.

Signed-off-by: Willy Tarreau <w@1wt.eu>

Ändern Zusammenfassung

Diff

--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -117,6 +117,7 @@ struct vm_area_struct {
117117 /* read ahead limits */
118118 extern int vm_min_readahead;
119119 extern int vm_max_readahead;
120+extern unsigned long mmap_min_addr;
120121
121122 /*
122123 * mapping from the currently active vm_flags protection bits (the
@@ -652,6 +653,11 @@ static inline int expand_stack(struct vm_area_struct * vma, unsigned long addres
652653 * page_table_lock lock to serialize against concurrent expand_stacks.
653654 */
654655 address &= PAGE_MASK;
656+
657+ /* ensure a non-privileged process is not trying to mmap lower pages */
658+ if (address < mmap_min_addr && !capable(CAP_SYS_RAWIO))
659+ return -EPERM;
660+
655661 spin_lock(&vma->vm_mm->page_table_lock);
656662
657663 /* already expanded while we were spinning? */
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -159,6 +159,7 @@ enum
159159 VM_LAPTOP_MODE=21, /* kernel in laptop flush mode */
160160 VM_BLOCK_DUMP=22, /* dump fs activity to log */
161161 VM_ANON_LRU=23, /* immediatly insert anon pages in the vm page lru */
162+ VM_MMAP_MIN_ADDR=24, /* prevent mapping of low addresses by mmap() */
162163 };
163164
164165
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -317,6 +317,8 @@ static ctl_table vm_table[] = {
317317 &laptop_mode, sizeof(int), 0644, NULL, &proc_dointvec},
318318 {VM_BLOCK_DUMP, "block_dump",
319319 &block_dump, sizeof(int), 0644, NULL, &proc_dointvec},
320+ {VM_MMAP_MIN_ADDR, "mmap_min_addr",
321+ &mmap_min_addr, sizeof(unsigned long), 0644, NULL, &proc_doulongvec_minmax},
320322 {0}
321323 };
322324
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -46,6 +46,8 @@ pgprot_t protection_map[16] = {
4646 };
4747
4848 int sysctl_overcommit_memory;
49+unsigned long mmap_min_addr; /* defaults to 0 = no protection */
50+
4951 int max_map_count = DEFAULT_MAX_MAP_COUNT;
5052
5153 /* Check that a process has enough memory to allocate a
@@ -654,13 +656,25 @@ unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned
654656 return -ENOMEM;
655657 if (addr & ~PAGE_MASK)
656658 return -EINVAL;
659+
660+ /* Ensure a non-privileged process is not trying to map
661+ * lower pages.
662+ */
663+ if (addr < mmap_min_addr && !capable(CAP_SYS_RAWIO))
664+ return -EPERM;
665+
657666 return addr;
658667 }
659668
660669 if (file && file->f_op && file->f_op->get_unmapped_area)
661- return file->f_op->get_unmapped_area(file, addr, len, pgoff, flags);
670+ addr = file->f_op->get_unmapped_area(file, addr, len, pgoff, flags);
671+ else
672+ addr = arch_get_unmapped_area(file, addr, len, pgoff, flags);
673+
674+ if (addr < mmap_min_addr && !capable(CAP_SYS_RAWIO))
675+ return -ENOMEM;
662676
663- return arch_get_unmapped_area(file, addr, len, pgoff, flags);
677+ return addr;
664678 }
665679
666680 /* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -273,6 +273,12 @@ unsigned long do_mremap(unsigned long addr,
273273 if ((addr <= new_addr) && (addr+old_len) > new_addr)
274274 goto out;
275275
276+ /* Ensure a non-privileged process is not trying to map
277+ * lower pages.
278+ */
279+ if (new_addr < mmap_min_addr && !capable(CAP_SYS_RAWIO))
280+ return -EPERM;
281+
276282 ret = do_munmap(current->mm, new_addr, new_len);
277283 if (ret && new_len)
278284 goto out;
Show on old repository browser