diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2005-06-21 17:14:32 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-21 18:46:12 -0700 |
commit | 84929801e14d968caeb84795bfbb88f04283fbd9 (patch) | |
tree | 248fa9fd6cfb411a6df3b7f7fb42aa4f9ceca2bf /arch/x86_64/kernel | |
parent | 589777eab7360894b7ca1c4ba9d252e03b51225b (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/x86_64/kernel')
-rw-r--r-- | arch/x86_64/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/x86_64/kernel/ptrace.c | 17 | ||||
-rw-r--r-- | arch/x86_64/kernel/sys_x86_64.c | 14 |
3 files changed, 16 insertions, 19 deletions
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 761b6d35e33..dce8bab4306 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) switch (code) { case ARCH_SET_GS: - if (addr >= TASK_SIZE) + if (addr >= TASK_SIZE_OF(task)) return -EPERM; cpu = get_cpu(); /* 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) case ARCH_SET_FS: /* Not strictly needed for fs, but do it for symmetry with gs */ - if (addr >= TASK_SIZE) + if (addr >= TASK_SIZE_OF(task)) return -EPERM; cpu = get_cpu(); /* 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 525f6a128a2..bbf64b59a21 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, value &= 0xffff; return 0; case offsetof(struct user_regs_struct,fs_base): - if (value >= TASK_SIZE) + if (value >= TASK_SIZE_OF(child)) return -EIO; child->thread.fs = value; return 0; case offsetof(struct user_regs_struct,gs_base): - if (value >= TASK_SIZE) + if (value >= TASK_SIZE_OF(child)) return -EIO; child->thread.gs = value; return 0; @@ -279,7 +279,7 @@ static int putreg(struct task_struct *child, break; case offsetof(struct user_regs_struct, rip): /* Check if the new RIP address is canonical */ - if (value >= TASK_SIZE) + if (value >= TASK_SIZE_OF(child)) return -EIO; break; } @@ -419,6 +419,8 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + { + int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7; ret = -EIO; if ((addr & 7) || addr > sizeof(struct user) - 7) @@ -430,22 +432,22 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; /* Disallows to set a breakpoint into the vsyscall */ case offsetof(struct user, u_debugreg[0]): - if (data >= TASK_SIZE-7) break; + if (data >= TASK_SIZE_OF(child) - dsize) break; child->thread.debugreg0 = data; ret = 0; break; case offsetof(struct user, u_debugreg[1]): - if (data >= TASK_SIZE-7) break; + if (data >= TASK_SIZE_OF(child) - dsize) break; child->thread.debugreg1 = data; ret = 0; break; case offsetof(struct user, u_debugreg[2]): - if (data >= TASK_SIZE-7) break; + if (data >= TASK_SIZE_OF(child) - dsize) break; child->thread.debugreg2 = data; ret = 0; break; case offsetof(struct user, u_debugreg[3]): - if (data >= TASK_SIZE-7) break; + if (data >= TASK_SIZE_OF(child) - dsize) break; child->thread.debugreg3 = data; ret = 0; break; @@ -469,6 +471,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; } break; + } case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c index dbebd5ccba6..d9798dd433f 100644 --- a/arch/x86_64/kernel/sys_x86_64.c +++ b/arch/x86_64/kernel/sys_x86_64.c @@ -68,13 +68,7 @@ out: static void find_start_end(unsigned long flags, unsigned long *begin, unsigned long *end) { -#ifdef CONFIG_IA32_EMULATION - if (test_thread_flag(TIF_IA32)) { - *begin = TASK_UNMAPPED_32; - *end = IA32_PAGE_OFFSET; - } else -#endif - if (flags & MAP_32BIT) { + if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) { /* This is usually used needed to map code in small model, so it needs to be in the first 31bit. Limit 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, of playground for now. -AK */ *begin = 0x40000000; *end = 0x80000000; - } else { - *begin = TASK_UNMAPPED_64; + } else { + *begin = TASK_UNMAPPED_BASE; *end = TASK_SIZE; - } + } } unsigned long |