mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-15 02:57:49 +00:00
[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>
This commit is contained in:
parent
589777eab7
commit
84929801e1
7 changed files with 25 additions and 30 deletions
|
@ -46,7 +46,7 @@ struct elf_phdr;
|
||||||
|
|
||||||
#define IA32_EMULATOR 1
|
#define IA32_EMULATOR 1
|
||||||
|
|
||||||
#define ELF_ET_DYN_BASE (TASK_UNMAPPED_32 + 0x1000000)
|
#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000)
|
||||||
|
|
||||||
#undef ELF_ARCH
|
#undef ELF_ARCH
|
||||||
#define ELF_ARCH EM_386
|
#define ELF_ARCH EM_386
|
||||||
|
@ -307,9 +307,6 @@ MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
|
||||||
|
|
||||||
#define elf_addr_t __u32
|
#define elf_addr_t __u32
|
||||||
|
|
||||||
#undef TASK_SIZE
|
|
||||||
#define TASK_SIZE 0xffffffff
|
|
||||||
|
|
||||||
static void elf32_init(struct pt_regs *);
|
static void elf32_init(struct pt_regs *);
|
||||||
|
|
||||||
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
|
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
|
||||||
|
|
|
@ -656,7 +656,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case ARCH_SET_GS:
|
case ARCH_SET_GS:
|
||||||
if (addr >= TASK_SIZE)
|
if (addr >= TASK_SIZE_OF(task))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
cpu = get_cpu();
|
cpu = get_cpu();
|
||||||
/* handle small bases via the GDT because that's faster to
|
/* 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:
|
case ARCH_SET_FS:
|
||||||
/* Not strictly needed for fs, but do it for symmetry
|
/* Not strictly needed for fs, but do it for symmetry
|
||||||
with gs */
|
with gs */
|
||||||
if (addr >= TASK_SIZE)
|
if (addr >= TASK_SIZE_OF(task))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
cpu = get_cpu();
|
cpu = get_cpu();
|
||||||
/* handle small bases via the GDT because that's faster to
|
/* handle small bases via the GDT because that's faster to
|
||||||
|
|
|
@ -257,12 +257,12 @@ static int putreg(struct task_struct *child,
|
||||||
value &= 0xffff;
|
value &= 0xffff;
|
||||||
return 0;
|
return 0;
|
||||||
case offsetof(struct user_regs_struct,fs_base):
|
case offsetof(struct user_regs_struct,fs_base):
|
||||||
if (value >= TASK_SIZE)
|
if (value >= TASK_SIZE_OF(child))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
child->thread.fs = value;
|
child->thread.fs = value;
|
||||||
return 0;
|
return 0;
|
||||||
case offsetof(struct user_regs_struct,gs_base):
|
case offsetof(struct user_regs_struct,gs_base):
|
||||||
if (value >= TASK_SIZE)
|
if (value >= TASK_SIZE_OF(child))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
child->thread.gs = value;
|
child->thread.gs = value;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -279,7 +279,7 @@ static int putreg(struct task_struct *child,
|
||||||
break;
|
break;
|
||||||
case offsetof(struct user_regs_struct, rip):
|
case offsetof(struct user_regs_struct, rip):
|
||||||
/* Check if the new RIP address is canonical */
|
/* Check if the new RIP address is canonical */
|
||||||
if (value >= TASK_SIZE)
|
if (value >= TASK_SIZE_OF(child))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -419,6 +419,8 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
|
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;
|
ret = -EIO;
|
||||||
if ((addr & 7) ||
|
if ((addr & 7) ||
|
||||||
addr > sizeof(struct user) - 7)
|
addr > sizeof(struct user) - 7)
|
||||||
|
@ -430,22 +432,22 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
|
||||||
break;
|
break;
|
||||||
/* Disallows to set a breakpoint into the vsyscall */
|
/* Disallows to set a breakpoint into the vsyscall */
|
||||||
case offsetof(struct user, u_debugreg[0]):
|
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;
|
child->thread.debugreg0 = data;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
case offsetof(struct user, u_debugreg[1]):
|
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;
|
child->thread.debugreg1 = data;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
case offsetof(struct user, u_debugreg[2]):
|
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;
|
child->thread.debugreg2 = data;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
case offsetof(struct user, u_debugreg[3]):
|
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;
|
child->thread.debugreg3 = data;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -469,6 +471,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
|
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
|
||||||
case PTRACE_CONT: /* restart after signal. */
|
case PTRACE_CONT: /* restart after signal. */
|
||||||
|
|
||||||
|
|
|
@ -68,13 +68,7 @@ out:
|
||||||
static void find_start_end(unsigned long flags, unsigned long *begin,
|
static void find_start_end(unsigned long flags, unsigned long *begin,
|
||||||
unsigned long *end)
|
unsigned long *end)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_IA32_EMULATION
|
if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) {
|
||||||
if (test_thread_flag(TIF_IA32)) {
|
|
||||||
*begin = TASK_UNMAPPED_32;
|
|
||||||
*end = IA32_PAGE_OFFSET;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
if (flags & MAP_32BIT) {
|
|
||||||
/* This is usually used needed to map code in small
|
/* This is usually used needed to map code in small
|
||||||
model, so it needs to be in the first 31bit. Limit
|
model, so it needs to be in the first 31bit. Limit
|
||||||
it to that. This means we need to move the
|
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 */
|
of playground for now. -AK */
|
||||||
*begin = 0x40000000;
|
*begin = 0x40000000;
|
||||||
*end = 0x80000000;
|
*end = 0x80000000;
|
||||||
} else {
|
} else {
|
||||||
*begin = TASK_UNMAPPED_64;
|
*begin = TASK_UNMAPPED_BASE;
|
||||||
*end = TASK_SIZE;
|
*end = TASK_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long
|
unsigned long
|
||||||
|
|
|
@ -350,7 +350,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
|
||||||
* (error_code & 4) == 0, and that the fault was not a
|
* (error_code & 4) == 0, and that the fault was not a
|
||||||
* protection error (error_code & 1) == 0.
|
* protection error (error_code & 1) == 0.
|
||||||
*/
|
*/
|
||||||
if (unlikely(address >= TASK_SIZE)) {
|
if (unlikely(address >= TASK_SIZE64)) {
|
||||||
if (!(error_code & 5) &&
|
if (!(error_code & 5) &&
|
||||||
((address >= VMALLOC_START && address < VMALLOC_END) ||
|
((address >= VMALLOC_START && address < VMALLOC_END) ||
|
||||||
(address >= MODULES_VADDR && address < MODULES_END))) {
|
(address >= MODULES_VADDR && address < MODULES_END))) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ struct exec
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
#include <linux/thread_info.h>
|
#include <linux/thread_info.h>
|
||||||
#define STACK_TOP (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE)
|
#define STACK_TOP TASK_SIZE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __A_OUT_GNU_H__ */
|
#endif /* __A_OUT_GNU_H__ */
|
||||||
|
|
|
@ -160,16 +160,17 @@ static inline void clear_in_cr4 (unsigned long mask)
|
||||||
/*
|
/*
|
||||||
* User space process size. 47bits minus one guard page.
|
* User space process size. 47bits minus one guard page.
|
||||||
*/
|
*/
|
||||||
#define TASK_SIZE (0x800000000000UL - 4096)
|
#define TASK_SIZE64 (0x800000000000UL - 4096)
|
||||||
|
|
||||||
/* This decides where the kernel will search for a free chunk of vm
|
/* This decides where the kernel will search for a free chunk of vm
|
||||||
* space during mmap's.
|
* space during mmap's.
|
||||||
*/
|
*/
|
||||||
#define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? 0xc0000000 : 0xFFFFe000)
|
#define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? 0xc0000000 : 0xFFFFe000)
|
||||||
#define TASK_UNMAPPED_32 PAGE_ALIGN(IA32_PAGE_OFFSET/3)
|
|
||||||
#define TASK_UNMAPPED_64 PAGE_ALIGN(TASK_SIZE/3)
|
#define TASK_SIZE (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE64)
|
||||||
#define TASK_UNMAPPED_BASE \
|
#define TASK_SIZE_OF(child) ((test_tsk_thread_flag(child, TIF_IA32)) ? IA32_PAGE_OFFSET : TASK_SIZE64)
|
||||||
(test_thread_flag(TIF_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64)
|
|
||||||
|
#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE/3)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Size of io_bitmap.
|
* Size of io_bitmap.
|
||||||
|
|
Loading…
Add table
Reference in a new issue