aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2005-06-21 20:14:32 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-21 21:46:12 -0400
commit84929801e14d968caeb84795bfbb88f04283fbd9 (patch)
tree248fa9fd6cfb411a6df3b7f7fb42aa4f9ceca2bf /arch
parent589777eab7360894b7ca1c4ba9d252e03b51225b (diff)
[PATCH] x86_64: TASK_SIZE fixes for compatibility mode processes
Appended patch will setup compatibility mode TASK_SIZE properly. This will fix atleast three known bugs that can be encountered while running compatibility mode apps. a) A malicious 32bit app can have an elf section at 0xffffe000. During exec of this app, we will have a memory leak as insert_vm_struct() is not checking for return value in syscall32_setup_pages() and thus not freeing the vma allocated for the vsyscall page. And instead of exec failing (as it has addresses > TASK_SIZE), we were allowing it to succeed previously. b) With a 32bit app, hugetlb_get_unmapped_area/arch_get_unmapped_area may return addresses beyond 32bits, ultimately causing corruption because of wrap-around and resulting in SEGFAULT, instead of returning ENOMEM. c) 32bit app doing this below mmap will now fail. mmap((void *)(0xFFFFE000UL), 0x10000UL, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANON, 0, 0); Signed-off-by: Zou Nan hai <nanhai.zou@intel.com> Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: Andi Kleen <ak@muc.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c5
-rw-r--r--arch/x86_64/kernel/process.c4
-rw-r--r--arch/x86_64/kernel/ptrace.c17
-rw-r--r--arch/x86_64/kernel/sys_x86_64.c14
-rw-r--r--arch/x86_64/mm/fault.c2
5 files changed, 18 insertions, 24 deletions
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 99b522052d16..c8131f342cfc 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -46,7 +46,7 @@ struct elf_phdr;
46 46
47#define IA32_EMULATOR 1 47#define IA32_EMULATOR 1
48 48
49#define ELF_ET_DYN_BASE (TASK_UNMAPPED_32 + 0x1000000) 49#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000)
50 50
51#undef ELF_ARCH 51#undef ELF_ARCH
52#define ELF_ARCH EM_386 52#define ELF_ARCH EM_386
@@ -307,9 +307,6 @@ MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
307 307
308#define elf_addr_t __u32 308#define elf_addr_t __u32
309 309
310#undef TASK_SIZE
311#define TASK_SIZE 0xffffffff
312
313static void elf32_init(struct pt_regs *); 310static void elf32_init(struct pt_regs *);
314 311
315#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 312#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 761b6d35e338..dce8bab4306c 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -656,7 +656,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
656 656
657 switch (code) { 657 switch (code) {
658 case ARCH_SET_GS: 658 case ARCH_SET_GS:
659 if (addr >= TASK_SIZE) 659 if (addr >= TASK_SIZE_OF(task))
660 return -EPERM; 660 return -EPERM;
661 cpu = get_cpu(); 661 cpu = get_cpu();
662 /* handle small bases via the GDT because that's faster to 662 /* handle small bases via the GDT because that's faster to
@@ -682,7 +682,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
682 case ARCH_SET_FS: 682 case ARCH_SET_FS:
683 /* Not strictly needed for fs, but do it for symmetry 683 /* Not strictly needed for fs, but do it for symmetry
684 with gs */ 684 with gs */
685 if (addr >= TASK_SIZE) 685 if (addr >= TASK_SIZE_OF(task))
686 return -EPERM; 686 return -EPERM;
687 cpu = get_cpu(); 687 cpu = get_cpu();
688 /* handle small bases via the GDT because that's faster to 688 /* handle small bases via the GDT because that's faster to
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index 525f6a128a27..bbf64b59a21e 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -257,12 +257,12 @@ static int putreg(struct task_struct *child,
257 value &= 0xffff; 257 value &= 0xffff;
258 return 0; 258 return 0;
259 case offsetof(struct user_regs_struct,fs_base): 259 case offsetof(struct user_regs_struct,fs_base):
260 if (value >= TASK_SIZE) 260 if (value >= TASK_SIZE_OF(child))
261 return -EIO; 261 return -EIO;
262 child->thread.fs = value; 262 child->thread.fs = value;
263 return 0; 263 return 0;
264 case offsetof(struct user_regs_struct,gs_base): 264 case offsetof(struct user_regs_struct,gs_base):
265 if (value >= TASK_SIZE) 265 if (value >= TASK_SIZE_OF(child))
266 return -EIO; 266 return -EIO;
267 child->thread.gs = value; 267 child->thread.gs = value;
268 return 0; 268 return 0;
@@ -279,7 +279,7 @@ static int putreg(struct task_struct *child,
279 break; 279 break;
280 case offsetof(struct user_regs_struct, rip): 280 case offsetof(struct user_regs_struct, rip):
281 /* Check if the new RIP address is canonical */ 281 /* Check if the new RIP address is canonical */
282 if (value >= TASK_SIZE) 282 if (value >= TASK_SIZE_OF(child))
283 return -EIO; 283 return -EIO;
284 break; 284 break;
285 } 285 }
@@ -419,6 +419,8 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
419 break; 419 break;
420 420
421 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 421 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
422 {
423 int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
422 ret = -EIO; 424 ret = -EIO;
423 if ((addr & 7) || 425 if ((addr & 7) ||
424 addr > sizeof(struct user) - 7) 426 addr > sizeof(struct user) - 7)
@@ -430,22 +432,22 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
430 break; 432 break;
431 /* Disallows to set a breakpoint into the vsyscall */ 433 /* Disallows to set a breakpoint into the vsyscall */
432 case offsetof(struct user, u_debugreg[0]): 434 case offsetof(struct user, u_debugreg[0]):
433 if (data >= TASK_SIZE-7) break; 435 if (data >= TASK_SIZE_OF(child) - dsize) break;
434 child->thread.debugreg0 = data; 436 child->thread.debugreg0 = data;
435 ret = 0; 437 ret = 0;
436 break; 438 break;
437 case offsetof(struct user, u_debugreg[1]): 439 case offsetof(struct user, u_debugreg[1]):
438 if (data >= TASK_SIZE-7) break; 440 if (data >= TASK_SIZE_OF(child) - dsize) break;
439 child->thread.debugreg1 = data; 441 child->thread.debugreg1 = data;
440 ret = 0; 442 ret = 0;
441 break; 443 break;
442 case offsetof(struct user, u_debugreg[2]): 444 case offsetof(struct user, u_debugreg[2]):
443 if (data >= TASK_SIZE-7) break; 445 if (data >= TASK_SIZE_OF(child) - dsize) break;
444 child->thread.debugreg2 = data; 446 child->thread.debugreg2 = data;
445 ret = 0; 447 ret = 0;
446 break; 448 break;
447 case offsetof(struct user, u_debugreg[3]): 449 case offsetof(struct user, u_debugreg[3]):
448 if (data >= TASK_SIZE-7) break; 450 if (data >= TASK_SIZE_OF(child) - dsize) break;
449 child->thread.debugreg3 = data; 451 child->thread.debugreg3 = data;
450 ret = 0; 452 ret = 0;
451 break; 453 break;
@@ -469,6 +471,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
469 break; 471 break;
470 } 472 }
471 break; 473 break;
474 }
472 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 475 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
473 case PTRACE_CONT: /* restart after signal. */ 476 case PTRACE_CONT: /* restart after signal. */
474 477
diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c
index dbebd5ccba6b..d9798dd433fc 100644
--- a/arch/x86_64/kernel/sys_x86_64.c
+++ b/arch/x86_64/kernel/sys_x86_64.c
@@ -68,13 +68,7 @@ out:
68static void find_start_end(unsigned long flags, unsigned long *begin, 68static void find_start_end(unsigned long flags, unsigned long *begin,
69 unsigned long *end) 69 unsigned long *end)
70{ 70{
71#ifdef CONFIG_IA32_EMULATION 71 if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) {
72 if (test_thread_flag(TIF_IA32)) {
73 *begin = TASK_UNMAPPED_32;
74 *end = IA32_PAGE_OFFSET;
75 } else
76#endif
77 if (flags & MAP_32BIT) {
78 /* This is usually used needed to map code in small 72 /* This is usually used needed to map code in small
79 model, so it needs to be in the first 31bit. Limit 73 model, so it needs to be in the first 31bit. Limit
80 it to that. This means we need to move the 74 it to that. This means we need to move the
@@ -84,10 +78,10 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
84 of playground for now. -AK */ 78 of playground for now. -AK */
85 *begin = 0x40000000; 79 *begin = 0x40000000;
86 *end = 0x80000000; 80 *end = 0x80000000;
87 } else { 81 } else {
88 *begin = TASK_UNMAPPED_64; 82 *begin = TASK_UNMAPPED_BASE;
89 *end = TASK_SIZE; 83 *end = TASK_SIZE;
90 } 84 }
91} 85}
92 86
93unsigned long 87unsigned long
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 5d6b2114cc9a..57d3ab15a5c7 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -350,7 +350,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
350 * (error_code & 4) == 0, and that the fault was not a 350 * (error_code & 4) == 0, and that the fault was not a
351 * protection error (error_code & 1) == 0. 351 * protection error (error_code & 1) == 0.
352 */ 352 */
353 if (unlikely(address >= TASK_SIZE)) { 353 if (unlikely(address >= TASK_SIZE64)) {
354 if (!(error_code & 5) && 354 if (!(error_code & 5) &&
355 ((address >= VMALLOC_START && address < VMALLOC_END) || 355 ((address >= VMALLOC_START && address < VMALLOC_END) ||
356 (address >= MODULES_VADDR && address < MODULES_END))) { 356 (address >= MODULES_VADDR && address < MODULES_END))) {