Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84929801 authored by Suresh Siddha's avatar Suresh Siddha Committed by Linus Torvalds
Browse files

[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: default avatarZou Nan hai <nanhai.zou@intel.com>
Signed-off-by: default avatarSuresh Siddha <suresh.b.siddha@intel.com>
Cc: Andi Kleen <ak@muc.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 589777ea
Loading
Loading
Loading
Loading
+1 −4
Original line number Original line Diff line number Diff line
@@ -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
+2 −2
Original line number Original line Diff line number Diff line
@@ -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 
+10 −7
Original line number Original line Diff line number Diff line
@@ -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. */


+4 −10
Original line number Original line Diff line number Diff line
@@ -68,13 +68,7 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long pr
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
@@ -85,7 +79,7 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
		*begin = 0x40000000; 
		*begin = 0x40000000; 
		*end = 0x80000000;		
		*end = 0x80000000;		
	} else {
	} else {
		*begin = TASK_UNMAPPED_64; 
		*begin = TASK_UNMAPPED_BASE;
		*end = TASK_SIZE; 
		*end = TASK_SIZE; 
	}
	}
} 
} 
+1 −1
Original line number Original line Diff line number Diff line
@@ -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))) {
Loading