The following commit has been merged into the x86/cleanups branch of tip:

Commit-ID:     ff170cd0595398a7b66cb40f249eb2f10c29b66d
Gitweb:        
https://git.kernel.org/tip/ff170cd0595398a7b66cb40f249eb2f10c29b66d
Author:        Gabriel Krisman Bertazi <kris...@collabora.com>
AuthorDate:    Sat, 03 Oct 2020 23:25:35 -04:00
Committer:     Thomas Gleixner <t...@linutronix.de>
CommitterDate: Mon, 26 Oct 2020 13:46:47 +01:00

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 <kris...@collabora.com>
Signed-off-by: Thomas Gleixner <t...@linutronix.de>
Acked-by: Andy Lutomirski<l...@kernel.org>
Link: https://lore.kernel.org/r/20201004032536.1229030-10-kris...@collabora.com
---
 arch/x86/entry/vsyscall/vsyscall_64.c |  2 +-
 arch/x86/include/asm/mmu.h            |  9 +++++++--
 arch/x86/include/asm/mmu_context.h    |  2 +-
 arch/x86/kernel/process_64.c          | 17 +++++++++++------
 4 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c 
b/arch/x86/entry/vsyscall/vsyscall_64.c
index 44c3310..1b40b92 100644
--- a/arch/x86/entry/vsyscall/vsyscall_64.c
+++ b/arch/x86/entry/vsyscall/vsyscall_64.c
@@ -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)
diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h
index 9257667..5d74946 100644
--- a/arch/x86/include/asm/mmu.h
+++ b/arch/x86/include/asm/mmu.h
@@ -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;
diff --git a/arch/x86/include/asm/mmu_context.h 
b/arch/x86/include/asm/mmu_context.h
index d98016b..054a791 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -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)
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 5fb4103..d6efaf6 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -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;

Reply via email to