diff options
author | Kirill Korotaev <dev@openvz.org> | 2006-09-07 06:17:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-08 11:40:46 -0400 |
commit | 3a459756810912d2c2bf188cef566af255936b4d (patch) | |
tree | 1b52d90a2412811ebf5078b4f55112864e1890df /mm | |
parent | 10387e5eb45c6e48d67102b88229f5bc6037461c (diff) |
[PATCH] IA64,sparc: local DoS with corrupted ELFs
This prevents cross-region mappings on IA64 and SPARC which could lead
to system crash. They were correctly trapped for normal mmap() calls,
but not for the kernel internal calls generated by executable loading.
This code just moves the architecture-specific cross-region checks into
an arch-specific "arch_mmap_check()" macro, and defines that for the
architectures that needed it (ia64, sparc and sparc64).
Architectures that don't have any special requirements can just ignore
the new cross-region check, since the mmap() code will just notice on
its own when the macro isn't defined.
Signed-off-by: Pavel Emelianov <xemul@openvz.org>
Signed-off-by: Kirill Korotaev <dev@openvz.org>
Acked-by: David Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
[ Cleaned up to not affect architectures that don't need it ]
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/mmap.c | 17 |
1 files changed, 15 insertions, 2 deletions
@@ -30,6 +30,10 @@ | |||
30 | #include <asm/cacheflush.h> | 30 | #include <asm/cacheflush.h> |
31 | #include <asm/tlb.h> | 31 | #include <asm/tlb.h> |
32 | 32 | ||
33 | #ifndef arch_mmap_check | ||
34 | #define arch_mmap_check(addr, len, flags) (0) | ||
35 | #endif | ||
36 | |||
33 | static void unmap_region(struct mm_struct *mm, | 37 | static void unmap_region(struct mm_struct *mm, |
34 | struct vm_area_struct *vma, struct vm_area_struct *prev, | 38 | struct vm_area_struct *vma, struct vm_area_struct *prev, |
35 | unsigned long start, unsigned long end); | 39 | unsigned long start, unsigned long end); |
@@ -913,6 +917,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, | |||
913 | if (!len) | 917 | if (!len) |
914 | return -EINVAL; | 918 | return -EINVAL; |
915 | 919 | ||
920 | error = arch_mmap_check(addr, len, flags); | ||
921 | if (error) | ||
922 | return error; | ||
923 | |||
916 | /* Careful about overflows.. */ | 924 | /* Careful about overflows.. */ |
917 | len = PAGE_ALIGN(len); | 925 | len = PAGE_ALIGN(len); |
918 | if (!len || len > TASK_SIZE) | 926 | if (!len || len > TASK_SIZE) |
@@ -1859,6 +1867,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len) | |||
1859 | unsigned long flags; | 1867 | unsigned long flags; |
1860 | struct rb_node ** rb_link, * rb_parent; | 1868 | struct rb_node ** rb_link, * rb_parent; |
1861 | pgoff_t pgoff = addr >> PAGE_SHIFT; | 1869 | pgoff_t pgoff = addr >> PAGE_SHIFT; |
1870 | int error; | ||
1862 | 1871 | ||
1863 | len = PAGE_ALIGN(len); | 1872 | len = PAGE_ALIGN(len); |
1864 | if (!len) | 1873 | if (!len) |
@@ -1867,6 +1876,12 @@ unsigned long do_brk(unsigned long addr, unsigned long len) | |||
1867 | if ((addr + len) > TASK_SIZE || (addr + len) < addr) | 1876 | if ((addr + len) > TASK_SIZE || (addr + len) < addr) |
1868 | return -EINVAL; | 1877 | return -EINVAL; |
1869 | 1878 | ||
1879 | flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; | ||
1880 | |||
1881 | error = arch_mmap_check(addr, len, flags); | ||
1882 | if (error) | ||
1883 | return error; | ||
1884 | |||
1870 | /* | 1885 | /* |
1871 | * mlock MCL_FUTURE? | 1886 | * mlock MCL_FUTURE? |
1872 | */ | 1887 | */ |
@@ -1907,8 +1922,6 @@ unsigned long do_brk(unsigned long addr, unsigned long len) | |||
1907 | if (security_vm_enough_memory(len >> PAGE_SHIFT)) | 1922 | if (security_vm_enough_memory(len >> PAGE_SHIFT)) |
1908 | return -ENOMEM; | 1923 | return -ENOMEM; |
1909 | 1924 | ||
1910 | flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; | ||
1911 | |||
1912 | /* Can we just expand an old private anonymous mapping? */ | 1925 | /* Can we just expand an old private anonymous mapping? */ |
1913 | if (vma_merge(mm, prev, addr, addr + len, flags, | 1926 | if (vma_merge(mm, prev, addr, addr + len, flags, |
1914 | NULL, NULL, pgoff, NULL)) | 1927 | NULL, NULL, pgoff, NULL)) |