diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/kernel/sys_sparc.c | 90 |
1 files changed, 68 insertions, 22 deletions
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 5f8c822a2b4a..095db723bb8a 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c | |||
@@ -33,14 +33,55 @@ | |||
33 | 33 | ||
34 | /* #define DEBUG_UNIMP_SYSCALL */ | 34 | /* #define DEBUG_UNIMP_SYSCALL */ |
35 | 35 | ||
36 | /* XXX Make this per-binary type, this way we can detect the type of | ||
37 | * XXX a binary. Every Sparc executable calls this very early on. | ||
38 | */ | ||
39 | asmlinkage unsigned long sys_getpagesize(void) | 36 | asmlinkage unsigned long sys_getpagesize(void) |
40 | { | 37 | { |
41 | return PAGE_SIZE; | 38 | return PAGE_SIZE; |
42 | } | 39 | } |
43 | 40 | ||
41 | #define VA_EXCLUDE_START (0x0000080000000000UL - (1UL << 32UL)) | ||
42 | #define VA_EXCLUDE_END (0xfffff80000000000UL + (1UL << 32UL)) | ||
43 | |||
44 | /* Does addr --> addr+len fall within 4GB of the VA-space hole or | ||
45 | * overflow past the end of the 64-bit address space? | ||
46 | */ | ||
47 | static inline int invalid_64bit_range(unsigned long addr, unsigned long len) | ||
48 | { | ||
49 | unsigned long va_exclude_start, va_exclude_end; | ||
50 | |||
51 | va_exclude_start = VA_EXCLUDE_START; | ||
52 | va_exclude_end = VA_EXCLUDE_END; | ||
53 | |||
54 | if (unlikely(len >= va_exclude_start)) | ||
55 | return 1; | ||
56 | |||
57 | if (unlikely((addr + len) < addr)) | ||
58 | return 1; | ||
59 | |||
60 | if (unlikely((addr >= va_exclude_start && addr < va_exclude_end) || | ||
61 | ((addr + len) >= va_exclude_start && | ||
62 | (addr + len) < va_exclude_end))) | ||
63 | return 1; | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /* Does start,end straddle the VA-space hole? */ | ||
69 | static inline int straddles_64bit_va_hole(unsigned long start, unsigned long end) | ||
70 | { | ||
71 | unsigned long va_exclude_start, va_exclude_end; | ||
72 | |||
73 | va_exclude_start = VA_EXCLUDE_START; | ||
74 | va_exclude_end = VA_EXCLUDE_END; | ||
75 | |||
76 | if (likely(start < va_exclude_start && end < va_exclude_start)) | ||
77 | return 0; | ||
78 | |||
79 | if (likely(start >= va_exclude_end && end >= va_exclude_end)) | ||
80 | return 0; | ||
81 | |||
82 | return 1; | ||
83 | } | ||
84 | |||
44 | #define COLOUR_ALIGN(addr,pgoff) \ | 85 | #define COLOUR_ALIGN(addr,pgoff) \ |
45 | ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ | 86 | ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ |
46 | (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) | 87 | (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) |
@@ -65,7 +106,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi | |||
65 | 106 | ||
66 | if (test_thread_flag(TIF_32BIT)) | 107 | if (test_thread_flag(TIF_32BIT)) |
67 | task_size = 0xf0000000UL; | 108 | task_size = 0xf0000000UL; |
68 | if (len > task_size || len > -PAGE_OFFSET) | 109 | if (len > task_size || len >= VA_EXCLUDE_START) |
69 | return -ENOMEM; | 110 | return -ENOMEM; |
70 | 111 | ||
71 | do_color_align = 0; | 112 | do_color_align = 0; |
@@ -100,9 +141,10 @@ full_search: | |||
100 | 141 | ||
101 | for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { | 142 | for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { |
102 | /* At this point: (!vma || addr < vma->vm_end). */ | 143 | /* At this point: (!vma || addr < vma->vm_end). */ |
103 | if (addr < PAGE_OFFSET && -PAGE_OFFSET - len < addr) { | 144 | if (addr < VA_EXCLUDE_START && |
104 | addr = PAGE_OFFSET; | 145 | (addr + len) >= VA_EXCLUDE_START) { |
105 | vma = find_vma(mm, PAGE_OFFSET); | 146 | addr = VA_EXCLUDE_END; |
147 | vma = find_vma(mm, VA_EXCLUDE_END); | ||
106 | } | 148 | } |
107 | if (task_size < addr) { | 149 | if (task_size < addr) { |
108 | if (start_addr != TASK_UNMAPPED_BASE) { | 150 | if (start_addr != TASK_UNMAPPED_BASE) { |
@@ -174,12 +216,12 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u | |||
174 | asmlinkage unsigned long sparc_brk(unsigned long brk) | 216 | asmlinkage unsigned long sparc_brk(unsigned long brk) |
175 | { | 217 | { |
176 | /* People could try to be nasty and use ta 0x6d in 32bit programs */ | 218 | /* People could try to be nasty and use ta 0x6d in 32bit programs */ |
177 | if (test_thread_flag(TIF_32BIT) && | 219 | if (test_thread_flag(TIF_32BIT) && brk >= 0xf0000000UL) |
178 | brk >= 0xf0000000UL) | ||
179 | return current->mm->brk; | 220 | return current->mm->brk; |
180 | 221 | ||
181 | if ((current->mm->brk & PAGE_OFFSET) != (brk & PAGE_OFFSET)) | 222 | if (unlikely(straddles_64bit_va_hole(current->mm->brk, brk))) |
182 | return current->mm->brk; | 223 | return current->mm->brk; |
224 | |||
183 | return sys_brk(brk); | 225 | return sys_brk(brk); |
184 | } | 226 | } |
185 | 227 | ||
@@ -340,13 +382,16 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, | |||
340 | retval = -EINVAL; | 382 | retval = -EINVAL; |
341 | 383 | ||
342 | if (test_thread_flag(TIF_32BIT)) { | 384 | if (test_thread_flag(TIF_32BIT)) { |
343 | if (len > 0xf0000000UL || | 385 | if (len >= 0xf0000000UL) |
344 | ((flags & MAP_FIXED) && addr > 0xf0000000UL - len)) | 386 | goto out_putf; |
387 | |||
388 | if ((flags & MAP_FIXED) && addr > 0xf0000000UL - len) | ||
345 | goto out_putf; | 389 | goto out_putf; |
346 | } else { | 390 | } else { |
347 | if (len > -PAGE_OFFSET || | 391 | if (len >= VA_EXCLUDE_START) |
348 | ((flags & MAP_FIXED) && | 392 | goto out_putf; |
349 | addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) | 393 | |
394 | if ((flags & MAP_FIXED) && invalid_64bit_range(addr, len)) | ||
350 | goto out_putf; | 395 | goto out_putf; |
351 | } | 396 | } |
352 | 397 | ||
@@ -365,9 +410,9 @@ asmlinkage long sys64_munmap(unsigned long addr, size_t len) | |||
365 | { | 410 | { |
366 | long ret; | 411 | long ret; |
367 | 412 | ||
368 | if (len > -PAGE_OFFSET || | 413 | if (invalid_64bit_range(addr, len)) |
369 | (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) | ||
370 | return -EINVAL; | 414 | return -EINVAL; |
415 | |||
371 | down_write(¤t->mm->mmap_sem); | 416 | down_write(¤t->mm->mmap_sem); |
372 | ret = do_munmap(current->mm, addr, len); | 417 | ret = do_munmap(current->mm, addr, len); |
373 | up_write(¤t->mm->mmap_sem); | 418 | up_write(¤t->mm->mmap_sem); |
@@ -384,18 +429,19 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr, | |||
384 | { | 429 | { |
385 | struct vm_area_struct *vma; | 430 | struct vm_area_struct *vma; |
386 | unsigned long ret = -EINVAL; | 431 | unsigned long ret = -EINVAL; |
432 | |||
387 | if (test_thread_flag(TIF_32BIT)) | 433 | if (test_thread_flag(TIF_32BIT)) |
388 | goto out; | 434 | goto out; |
389 | if (old_len > -PAGE_OFFSET || new_len > -PAGE_OFFSET) | 435 | if (unlikely(new_len >= VA_EXCLUDE_START)) |
390 | goto out; | 436 | goto out; |
391 | if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) | 437 | if (unlikely(invalid_64bit_range(addr, old_len))) |
392 | goto out; | 438 | goto out; |
439 | |||
393 | down_write(¤t->mm->mmap_sem); | 440 | down_write(¤t->mm->mmap_sem); |
394 | if (flags & MREMAP_FIXED) { | 441 | if (flags & MREMAP_FIXED) { |
395 | if (new_addr < PAGE_OFFSET && | 442 | if (invalid_64bit_range(new_addr, new_len)) |
396 | new_addr + new_len > -PAGE_OFFSET) | ||
397 | goto out_sem; | 443 | goto out_sem; |
398 | } else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) { | 444 | } else if (invalid_64bit_range(addr, new_len)) { |
399 | unsigned long map_flags = 0; | 445 | unsigned long map_flags = 0; |
400 | struct file *file = NULL; | 446 | struct file *file = NULL; |
401 | 447 | ||