diff options
Diffstat (limited to 'arch/x86/kernel/process_64.c')
| -rw-r--r-- | arch/x86/kernel/process_64.c | 27 | 
1 files changed, 21 insertions, 6 deletions
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index cfa5c90c01d..550e77b1b94 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -365,7 +365,9 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)  void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp)  {  	start_thread_common(regs, new_ip, new_sp, -			    __USER32_CS, __USER32_DS, __USER32_DS); +			    test_thread_flag(TIF_X32) +			    ? __USER_CS : __USER32_CS, +			    __USER_DS, __USER_DS);  }  #endif @@ -488,6 +490,8 @@ void set_personality_64bit(void)  	/* Make sure to be in 64bit mode */  	clear_thread_flag(TIF_IA32); +	clear_thread_flag(TIF_ADDR32); +	clear_thread_flag(TIF_X32);  	/* Ensure the corresponding mm is not marked. */  	if (current->mm) @@ -500,20 +504,31 @@ void set_personality_64bit(void)  	current->personality &= ~READ_IMPLIES_EXEC;  } -void set_personality_ia32(void) +void set_personality_ia32(bool x32)  {  	/* inherit personality from parent */  	/* Make sure to be in 32bit mode */ -	set_thread_flag(TIF_IA32); -	current->personality |= force_personality32; +	set_thread_flag(TIF_ADDR32);  	/* Mark the associated mm as containing 32-bit tasks. */  	if (current->mm)  		current->mm->context.ia32_compat = 1; -	/* Prepare the first "return" to user space */ -	current_thread_info()->status |= TS_COMPAT; +	if (x32) { +		clear_thread_flag(TIF_IA32); +		set_thread_flag(TIF_X32); +		current->personality &= ~READ_IMPLIES_EXEC; +		/* is_compat_task() uses the presence of the x32 +		   syscall bit flag to determine compat status */ +		current_thread_info()->status &= ~TS_COMPAT; +	} else { +		set_thread_flag(TIF_IA32); +		clear_thread_flag(TIF_X32); +		current->personality |= force_personality32; +		/* Prepare the first "return" to user space */ +		current_thread_info()->status |= TS_COMPAT; +	}  }  unsigned long get_wchan(struct task_struct *p)  |