x86/mm: Convert mmu context ia32_compat into a proper flags field
The ia32_compat attribute is a weird thing. It mirrors TIF_IA32 and TIF_X32 and is used only in two very unrelated places: (1) to decide if the vsyscall page is accessible (2) for uprobes to find whether the patched instruction is 32 or 64 bit. In preparation to remove the TIF flags, a new mechanism is required for ia32_compat, but given its odd semantics, adding a real flags field which configures these specific behaviours is the best option. So, set_personality_x64() can ask for the vsyscall page, which is not available in x32/ia32 and set_personality_ia32() can configure the uprobe code as needed. uprobe cannot rely on other methods like user_64bit_mode() to decide how to patch, so it needs some specific flag like this. Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Andy Lutomirski<luto@kernel.org> Link: https://lore.kernel.org/r/20201004032536.1229030-10-krisman@collabora.com
This commit is contained in:
parent
3316ec8ccd
commit
ff170cd059
|
@ -316,7 +316,7 @@ static struct vm_area_struct gate_vma __ro_after_init = {
|
|||
struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
|
||||
{
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (!mm || mm->context.ia32_compat)
|
||||
if (!mm || !(mm->context.flags & MM_CONTEXT_HAS_VSYSCALL))
|
||||
return NULL;
|
||||
#endif
|
||||
if (vsyscall_mode == NONE)
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
#include <linux/rwsem.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/bits.h>
|
||||
|
||||
/* Uprobes on this MM assume 32-bit code */
|
||||
#define MM_CONTEXT_UPROBE_IA32 BIT(0)
|
||||
/* vsyscall page is accessible on this MM */
|
||||
#define MM_CONTEXT_HAS_VSYSCALL BIT(1)
|
||||
|
||||
/*
|
||||
* x86 has arch-specific MMU state beyond what lives in mm_struct.
|
||||
|
@ -33,8 +39,7 @@ typedef struct {
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/* True if mm supports a task running in 32 bit compatibility mode. */
|
||||
unsigned short ia32_compat;
|
||||
unsigned short flags;
|
||||
#endif
|
||||
|
||||
struct mutex lock;
|
||||
|
|
|
@ -177,7 +177,7 @@ static inline void arch_exit_mmap(struct mm_struct *mm)
|
|||
static inline bool is_64bit_mm(struct mm_struct *mm)
|
||||
{
|
||||
return !IS_ENABLED(CONFIG_IA32_EMULATION) ||
|
||||
!(mm->context.ia32_compat == TIF_IA32);
|
||||
!(mm->context.flags & MM_CONTEXT_UPROBE_IA32);
|
||||
}
|
||||
#else
|
||||
static inline bool is_64bit_mm(struct mm_struct *mm)
|
||||
|
|
|
@ -646,10 +646,8 @@ void set_personality_64bit(void)
|
|||
/* Pretend that this comes from a 64bit execve */
|
||||
task_pt_regs(current)->orig_ax = __NR_execve;
|
||||
current_thread_info()->status &= ~TS_COMPAT;
|
||||
|
||||
/* Ensure the corresponding mm is not marked. */
|
||||
if (current->mm)
|
||||
current->mm->context.ia32_compat = 0;
|
||||
current->mm->context.flags = MM_CONTEXT_HAS_VSYSCALL;
|
||||
|
||||
/* TBD: overwrites user setup. Should have two bits.
|
||||
But 64bit processes have always behaved this way,
|
||||
|
@ -664,7 +662,8 @@ static void __set_personality_x32(void)
|
|||
clear_thread_flag(TIF_IA32);
|
||||
set_thread_flag(TIF_X32);
|
||||
if (current->mm)
|
||||
current->mm->context.ia32_compat = TIF_X32;
|
||||
current->mm->context.flags = 0;
|
||||
|
||||
current->personality &= ~READ_IMPLIES_EXEC;
|
||||
/*
|
||||
* in_32bit_syscall() uses the presence of the x32 syscall bit
|
||||
|
@ -684,8 +683,14 @@ static void __set_personality_ia32(void)
|
|||
#ifdef CONFIG_IA32_EMULATION
|
||||
set_thread_flag(TIF_IA32);
|
||||
clear_thread_flag(TIF_X32);
|
||||
if (current->mm)
|
||||
current->mm->context.ia32_compat = TIF_IA32;
|
||||
if (current->mm) {
|
||||
/*
|
||||
* uprobes applied to this MM need to know this and
|
||||
* cannot use user_64bit_mode() at that time.
|
||||
*/
|
||||
current->mm->context.flags = MM_CONTEXT_UPROBE_IA32;
|
||||
}
|
||||
|
||||
current->personality |= force_personality32;
|
||||
/* Prepare the first "return" to user space */
|
||||
task_pt_regs(current)->orig_ax = __NR_ia32_execve;
|
||||
|
|
Loading…
Reference in New Issue