]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
re-add uprobes-x86-fix-detection-of-32-bit-user-mode.patch
authorSasha Levin <sashal@kernel.org>
Tue, 3 Sep 2019 13:18:39 +0000 (09:18 -0400)
committerSasha Levin <sashal@kernel.org>
Tue, 3 Sep 2019 13:18:39 +0000 (09:18 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.14/series
queue-4.14/uprobes-x86-fix-detection-of-32-bit-user-mode.patch [new file with mode: 0644]
queue-4.4/ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/uprobes-x86-fix-detection-of-32-bit-user-mode.patch [new file with mode: 0644]
queue-4.9/ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch [new file with mode: 0644]
queue-4.9/series
queue-4.9/uprobes-x86-fix-detection-of-32-bit-user-mode.patch [new file with mode: 0644]

index eaf1bd9dcb458ee5dbd67ba69e4d16ff22c8b5ff..00b93b98e0853093ecacef83601b9723e129f93f 100644 (file)
@@ -28,3 +28,4 @@ x86-apic-include-the-ldr-when-clearing-out-apic-registers.patch
 ftrace-fix-null-pointer-dereference-in-t_probe_next.patch
 ftrace-check-for-successful-allocation-of-hash.patch
 ftrace-check-for-empty-hash-and-comment-the-race-with-registering-probes.patch
+uprobes-x86-fix-detection-of-32-bit-user-mode.patch
diff --git a/queue-4.14/uprobes-x86-fix-detection-of-32-bit-user-mode.patch b/queue-4.14/uprobes-x86-fix-detection-of-32-bit-user-mode.patch
new file mode 100644 (file)
index 0000000..d95e802
--- /dev/null
@@ -0,0 +1,130 @@
+From ced967ce0097e755d65cf61aa01bf1236406be08 Mon Sep 17 00:00:00 2001
+From: Sebastian Mayr <me@sam.st>
+Date: Sun, 28 Jul 2019 17:26:17 +0200
+Subject: uprobes/x86: Fix detection of 32-bit user mode
+
+[ Upstream commit 9212ec7d8357ea630031e89d0d399c761421c83b ]
+
+32-bit processes running on a 64-bit kernel are not always detected
+correctly, causing the process to crash when uretprobes are installed.
+
+The reason for the crash is that in_ia32_syscall() is used to determine the
+process's mode, which only works correctly when called from a syscall.
+
+In the case of uretprobes, however, the function is called from a exception
+and always returns 'false' on a 64-bit kernel. In consequence this leads to
+corruption of the process's return address.
+
+Fix this by using user_64bit_mode() instead of in_ia32_syscall(), which
+is correct in any situation.
+
+[ tglx: Add a comment and the following historical info ]
+
+This should have been detected by the rename which happened in commit
+
+  abfb9498ee13 ("x86/entry: Rename is_{ia32,x32}_task() to in_{ia32,x32}_syscall()")
+
+which states in the changelog:
+
+    The is_ia32_task()/is_x32_task() function names are a big misnomer: they
+    suggests that the compat-ness of a system call is a task property, which
+    is not true, the compatness of a system call purely depends on how it
+    was invoked through the system call layer.
+    .....
+
+and then it went and blindly renamed every call site.
+
+Sadly enough this was already mentioned here:
+
+   8faaed1b9f50 ("uprobes/x86: Introduce sizeof_long(), cleanup adjust_ret_addr() and
+arch_uretprobe_hijack_return_addr()")
+
+where the changelog says:
+
+    TODO: is_ia32_task() is not what we actually want, TS_COMPAT does
+    not necessarily mean 32bit. Fortunately syscall-like insns can't be
+    probed so it actually works, but it would be better to rename and
+    use is_ia32_frame().
+
+and goes all the way back to:
+
+    0326f5a94dde ("uprobes/core: Handle breakpoint and singlestep exceptions")
+
+Oh well. 7+ years until someone actually tried a uretprobe on a 32bit
+process on a 64bit kernel....
+
+Fixes: 0326f5a94dde ("uprobes/core: Handle breakpoint and singlestep exceptions")
+Signed-off-by: Sebastian Mayr <me@sam.st>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
+Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/20190728152617.7308-1-me@sam.st
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/uprobes.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
+index b9a8f34b5e5ab..7a87ef1f5b5e6 100644
+--- a/arch/x86/kernel/uprobes.c
++++ b/arch/x86/kernel/uprobes.c
+@@ -518,9 +518,12 @@ struct uprobe_xol_ops {
+       void    (*abort)(struct arch_uprobe *, struct pt_regs *);
+ };
+-static inline int sizeof_long(void)
++static inline int sizeof_long(struct pt_regs *regs)
+ {
+-      return in_ia32_syscall() ? 4 : 8;
++      /*
++       * Check registers for mode as in_xxx_syscall() does not apply here.
++       */
++      return user_64bit_mode(regs) ? 8 : 4;
+ }
+ static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+@@ -531,9 +534,9 @@ static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+ static int push_ret_address(struct pt_regs *regs, unsigned long ip)
+ {
+-      unsigned long new_sp = regs->sp - sizeof_long();
++      unsigned long new_sp = regs->sp - sizeof_long(regs);
+-      if (copy_to_user((void __user *)new_sp, &ip, sizeof_long()))
++      if (copy_to_user((void __user *)new_sp, &ip, sizeof_long(regs)))
+               return -EFAULT;
+       regs->sp = new_sp;
+@@ -566,7 +569,7 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs
+               long correction = utask->vaddr - utask->xol_vaddr;
+               regs->ip += correction;
+       } else if (auprobe->defparam.fixups & UPROBE_FIX_CALL) {
+-              regs->sp += sizeof_long(); /* Pop incorrect return address */
++              regs->sp += sizeof_long(regs); /* Pop incorrect return address */
+               if (push_ret_address(regs, utask->vaddr + auprobe->defparam.ilen))
+                       return -ERESTART;
+       }
+@@ -675,7 +678,7 @@ static int branch_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+        * "call" insn was executed out-of-line. Just restore ->sp and restart.
+        * We could also restore ->ip and try to call branch_emulate_op() again.
+        */
+-      regs->sp += sizeof_long();
++      regs->sp += sizeof_long(regs);
+       return -ERESTART;
+ }
+@@ -966,7 +969,7 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+ unsigned long
+ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
+ {
+-      int rasize = sizeof_long(), nleft;
++      int rasize = sizeof_long(regs), nleft;
+       unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */
+       if (copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize))
+-- 
+2.20.1
+
diff --git a/queue-4.4/ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch b/queue-4.4/ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch
new file mode 100644 (file)
index 0000000..fbd0d97
--- /dev/null
@@ -0,0 +1,84 @@
+From 1cd43e020c39afd0379678c2c01869657911f6ee Mon Sep 17 00:00:00 2001
+From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
+Date: Fri, 27 Oct 2017 13:25:30 -0700
+Subject: ptrace,x86: Make user_64bit_mode() available to 32-bit builds
+
+[ Upstream commit e27c310af5c05cf876d9cad006928076c27f54d4 ]
+
+In its current form, user_64bit_mode() can only be used when CONFIG_X86_64
+is selected. This implies that code built with CONFIG_X86_64=n cannot use
+it. If a piece of code needs to be built for both CONFIG_X86_64=y and
+CONFIG_X86_64=n and wants to use this function, it needs to wrap it in
+an #ifdef/#endif; potentially, in multiple places.
+
+This can be easily avoided with a single #ifdef/#endif pair within
+user_64bit_mode() itself.
+
+Suggested-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Borislav Petkov <bp@suse.de>
+Cc: "Michael S. Tsirkin" <mst@redhat.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: ricardo.neri@intel.com
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
+Cc: Huang Rui <ray.huang@amd.com>
+Cc: Qiaowei Ren <qiaowei.ren@intel.com>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Jiri Slaby <jslaby@suse.cz>
+Cc: Dmitry Vyukov <dvyukov@google.com>
+Cc: "Ravi V. Shankar" <ravi.v.shankar@intel.com>
+Cc: Chris Metcalf <cmetcalf@mellanox.com>
+Cc: Brian Gerst <brgerst@gmail.com>
+Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Colin Ian King <colin.king@canonical.com>
+Cc: Chen Yucong <slaoub@gmail.com>
+Cc: Adam Buchbinder <adam.buchbinder@gmail.com>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Cc: Lorenzo Stoakes <lstoakes@gmail.com>
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Paolo Bonzini <pbonzini@redhat.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Thomas Garnier <thgarnie@google.com>
+Link: https://lkml.kernel.org/r/1509135945-13762-4-git-send-email-ricardo.neri-calderon@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/ptrace.h | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
+index 6271281f947d8..0d8e0831b1a07 100644
+--- a/arch/x86/include/asm/ptrace.h
++++ b/arch/x86/include/asm/ptrace.h
+@@ -121,9 +121,9 @@ static inline int v8086_mode(struct pt_regs *regs)
+ #endif
+ }
+-#ifdef CONFIG_X86_64
+ static inline bool user_64bit_mode(struct pt_regs *regs)
+ {
++#ifdef CONFIG_X86_64
+ #ifndef CONFIG_PARAVIRT
+       /*
+        * On non-paravirt systems, this is the only long mode CPL 3
+@@ -134,8 +134,12 @@ static inline bool user_64bit_mode(struct pt_regs *regs)
+       /* Headers are too twisted for this to go in paravirt.h. */
+       return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs;
+ #endif
++#else /* !CONFIG_X86_64 */
++      return false;
++#endif
+ }
++#ifdef CONFIG_X86_64
+ #define current_user_stack_pointer()  current_pt_regs()->sp
+ #define compat_user_stack_pointer()   current_pt_regs()->sp
+ #endif
+-- 
+2.20.1
+
index 7aa01522c0d24850fca18b950ff9853d03974c78..2e75efa75484029baf171c58ba6ad188ef48b437 100644 (file)
@@ -61,3 +61,5 @@ alsa-seq-fix-potential-concurrent-access-to-the-deleted-pool.patch
 kvm-x86-don-t-update-rip-or-do-single-step-on-faulting-emulation.patch
 x86-apic-do-not-initialize-ldr-and-dfr-for-bigsmp.patch
 x86-apic-include-the-ldr-when-clearing-out-apic-registers.patch
+ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch
+uprobes-x86-fix-detection-of-32-bit-user-mode.patch
diff --git a/queue-4.4/uprobes-x86-fix-detection-of-32-bit-user-mode.patch b/queue-4.4/uprobes-x86-fix-detection-of-32-bit-user-mode.patch
new file mode 100644 (file)
index 0000000..9b4bf49
--- /dev/null
@@ -0,0 +1,130 @@
+From c016532f95355f95804209ea5e6efaf6ee8153af Mon Sep 17 00:00:00 2001
+From: Sebastian Mayr <me@sam.st>
+Date: Sun, 28 Jul 2019 17:26:17 +0200
+Subject: uprobes/x86: Fix detection of 32-bit user mode
+
+[ Upstream commit 9212ec7d8357ea630031e89d0d399c761421c83b ]
+
+32-bit processes running on a 64-bit kernel are not always detected
+correctly, causing the process to crash when uretprobes are installed.
+
+The reason for the crash is that in_ia32_syscall() is used to determine the
+process's mode, which only works correctly when called from a syscall.
+
+In the case of uretprobes, however, the function is called from a exception
+and always returns 'false' on a 64-bit kernel. In consequence this leads to
+corruption of the process's return address.
+
+Fix this by using user_64bit_mode() instead of in_ia32_syscall(), which
+is correct in any situation.
+
+[ tglx: Add a comment and the following historical info ]
+
+This should have been detected by the rename which happened in commit
+
+  abfb9498ee13 ("x86/entry: Rename is_{ia32,x32}_task() to in_{ia32,x32}_syscall()")
+
+which states in the changelog:
+
+    The is_ia32_task()/is_x32_task() function names are a big misnomer: they
+    suggests that the compat-ness of a system call is a task property, which
+    is not true, the compatness of a system call purely depends on how it
+    was invoked through the system call layer.
+    .....
+
+and then it went and blindly renamed every call site.
+
+Sadly enough this was already mentioned here:
+
+   8faaed1b9f50 ("uprobes/x86: Introduce sizeof_long(), cleanup adjust_ret_addr() and
+arch_uretprobe_hijack_return_addr()")
+
+where the changelog says:
+
+    TODO: is_ia32_task() is not what we actually want, TS_COMPAT does
+    not necessarily mean 32bit. Fortunately syscall-like insns can't be
+    probed so it actually works, but it would be better to rename and
+    use is_ia32_frame().
+
+and goes all the way back to:
+
+    0326f5a94dde ("uprobes/core: Handle breakpoint and singlestep exceptions")
+
+Oh well. 7+ years until someone actually tried a uretprobe on a 32bit
+process on a 64bit kernel....
+
+Fixes: 0326f5a94dde ("uprobes/core: Handle breakpoint and singlestep exceptions")
+Signed-off-by: Sebastian Mayr <me@sam.st>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
+Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/20190728152617.7308-1-me@sam.st
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/uprobes.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
+index b8105289c60b6..178d63cac321b 100644
+--- a/arch/x86/kernel/uprobes.c
++++ b/arch/x86/kernel/uprobes.c
+@@ -514,9 +514,12 @@ struct uprobe_xol_ops {
+       void    (*abort)(struct arch_uprobe *, struct pt_regs *);
+ };
+-static inline int sizeof_long(void)
++static inline int sizeof_long(struct pt_regs *regs)
+ {
+-      return is_ia32_task() ? 4 : 8;
++      /*
++       * Check registers for mode as in_xxx_syscall() does not apply here.
++       */
++      return user_64bit_mode(regs) ? 8 : 4;
+ }
+ static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+@@ -527,9 +530,9 @@ static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+ static int push_ret_address(struct pt_regs *regs, unsigned long ip)
+ {
+-      unsigned long new_sp = regs->sp - sizeof_long();
++      unsigned long new_sp = regs->sp - sizeof_long(regs);
+-      if (copy_to_user((void __user *)new_sp, &ip, sizeof_long()))
++      if (copy_to_user((void __user *)new_sp, &ip, sizeof_long(regs)))
+               return -EFAULT;
+       regs->sp = new_sp;
+@@ -562,7 +565,7 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs
+               long correction = utask->vaddr - utask->xol_vaddr;
+               regs->ip += correction;
+       } else if (auprobe->defparam.fixups & UPROBE_FIX_CALL) {
+-              regs->sp += sizeof_long(); /* Pop incorrect return address */
++              regs->sp += sizeof_long(regs); /* Pop incorrect return address */
+               if (push_ret_address(regs, utask->vaddr + auprobe->defparam.ilen))
+                       return -ERESTART;
+       }
+@@ -671,7 +674,7 @@ static int branch_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+        * "call" insn was executed out-of-line. Just restore ->sp and restart.
+        * We could also restore ->ip and try to call branch_emulate_op() again.
+        */
+-      regs->sp += sizeof_long();
++      regs->sp += sizeof_long(regs);
+       return -ERESTART;
+ }
+@@ -962,7 +965,7 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+ unsigned long
+ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
+ {
+-      int rasize = sizeof_long(), nleft;
++      int rasize = sizeof_long(regs), nleft;
+       unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */
+       if (copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize))
+-- 
+2.20.1
+
diff --git a/queue-4.9/ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch b/queue-4.9/ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch
new file mode 100644 (file)
index 0000000..6358215
--- /dev/null
@@ -0,0 +1,84 @@
+From bd4a82025f464406a80a4ad48fe3b13a6cfcfd78 Mon Sep 17 00:00:00 2001
+From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
+Date: Fri, 27 Oct 2017 13:25:30 -0700
+Subject: ptrace,x86: Make user_64bit_mode() available to 32-bit builds
+
+[ Upstream commit e27c310af5c05cf876d9cad006928076c27f54d4 ]
+
+In its current form, user_64bit_mode() can only be used when CONFIG_X86_64
+is selected. This implies that code built with CONFIG_X86_64=n cannot use
+it. If a piece of code needs to be built for both CONFIG_X86_64=y and
+CONFIG_X86_64=n and wants to use this function, it needs to wrap it in
+an #ifdef/#endif; potentially, in multiple places.
+
+This can be easily avoided with a single #ifdef/#endif pair within
+user_64bit_mode() itself.
+
+Suggested-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Borislav Petkov <bp@suse.de>
+Cc: "Michael S. Tsirkin" <mst@redhat.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: ricardo.neri@intel.com
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
+Cc: Huang Rui <ray.huang@amd.com>
+Cc: Qiaowei Ren <qiaowei.ren@intel.com>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Jiri Slaby <jslaby@suse.cz>
+Cc: Dmitry Vyukov <dvyukov@google.com>
+Cc: "Ravi V. Shankar" <ravi.v.shankar@intel.com>
+Cc: Chris Metcalf <cmetcalf@mellanox.com>
+Cc: Brian Gerst <brgerst@gmail.com>
+Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Colin Ian King <colin.king@canonical.com>
+Cc: Chen Yucong <slaoub@gmail.com>
+Cc: Adam Buchbinder <adam.buchbinder@gmail.com>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Cc: Lorenzo Stoakes <lstoakes@gmail.com>
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Paolo Bonzini <pbonzini@redhat.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Thomas Garnier <thgarnie@google.com>
+Link: https://lkml.kernel.org/r/1509135945-13762-4-git-send-email-ricardo.neri-calderon@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/ptrace.h | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
+index 2b5d686ea9f37..ea78a8438a8af 100644
+--- a/arch/x86/include/asm/ptrace.h
++++ b/arch/x86/include/asm/ptrace.h
+@@ -115,9 +115,9 @@ static inline int v8086_mode(struct pt_regs *regs)
+ #endif
+ }
+-#ifdef CONFIG_X86_64
+ static inline bool user_64bit_mode(struct pt_regs *regs)
+ {
++#ifdef CONFIG_X86_64
+ #ifndef CONFIG_PARAVIRT
+       /*
+        * On non-paravirt systems, this is the only long mode CPL 3
+@@ -128,8 +128,12 @@ static inline bool user_64bit_mode(struct pt_regs *regs)
+       /* Headers are too twisted for this to go in paravirt.h. */
+       return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs;
+ #endif
++#else /* !CONFIG_X86_64 */
++      return false;
++#endif
+ }
++#ifdef CONFIG_X86_64
+ #define current_user_stack_pointer()  current_pt_regs()->sp
+ #define compat_user_stack_pointer()   current_pt_regs()->sp
+ #endif
+-- 
+2.20.1
+
index 5084716cc89fb15f0edf3cb2e1904f6553fa5b89..8ac5b5c664dc4533b3e8bdb4d1eb839e2c04978e 100644 (file)
@@ -62,3 +62,5 @@ kvm-x86-don-t-update-rip-or-do-single-step-on-faulting-emulation.patch
 x86-apic-do-not-initialize-ldr-and-dfr-for-bigsmp.patch
 x86-apic-include-the-ldr-when-clearing-out-apic-registers.patch
 mm-zsmalloc.c-fix-race-condition-in-zs_destroy_pool.patch
+ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch
+uprobes-x86-fix-detection-of-32-bit-user-mode.patch
diff --git a/queue-4.9/uprobes-x86-fix-detection-of-32-bit-user-mode.patch b/queue-4.9/uprobes-x86-fix-detection-of-32-bit-user-mode.patch
new file mode 100644 (file)
index 0000000..dff32e4
--- /dev/null
@@ -0,0 +1,130 @@
+From 73185c5db135e2733c94cf57f392cee00b841c99 Mon Sep 17 00:00:00 2001
+From: Sebastian Mayr <me@sam.st>
+Date: Sun, 28 Jul 2019 17:26:17 +0200
+Subject: uprobes/x86: Fix detection of 32-bit user mode
+
+[ Upstream commit 9212ec7d8357ea630031e89d0d399c761421c83b ]
+
+32-bit processes running on a 64-bit kernel are not always detected
+correctly, causing the process to crash when uretprobes are installed.
+
+The reason for the crash is that in_ia32_syscall() is used to determine the
+process's mode, which only works correctly when called from a syscall.
+
+In the case of uretprobes, however, the function is called from a exception
+and always returns 'false' on a 64-bit kernel. In consequence this leads to
+corruption of the process's return address.
+
+Fix this by using user_64bit_mode() instead of in_ia32_syscall(), which
+is correct in any situation.
+
+[ tglx: Add a comment and the following historical info ]
+
+This should have been detected by the rename which happened in commit
+
+  abfb9498ee13 ("x86/entry: Rename is_{ia32,x32}_task() to in_{ia32,x32}_syscall()")
+
+which states in the changelog:
+
+    The is_ia32_task()/is_x32_task() function names are a big misnomer: they
+    suggests that the compat-ness of a system call is a task property, which
+    is not true, the compatness of a system call purely depends on how it
+    was invoked through the system call layer.
+    .....
+
+and then it went and blindly renamed every call site.
+
+Sadly enough this was already mentioned here:
+
+   8faaed1b9f50 ("uprobes/x86: Introduce sizeof_long(), cleanup adjust_ret_addr() and
+arch_uretprobe_hijack_return_addr()")
+
+where the changelog says:
+
+    TODO: is_ia32_task() is not what we actually want, TS_COMPAT does
+    not necessarily mean 32bit. Fortunately syscall-like insns can't be
+    probed so it actually works, but it would be better to rename and
+    use is_ia32_frame().
+
+and goes all the way back to:
+
+    0326f5a94dde ("uprobes/core: Handle breakpoint and singlestep exceptions")
+
+Oh well. 7+ years until someone actually tried a uretprobe on a 32bit
+process on a 64bit kernel....
+
+Fixes: 0326f5a94dde ("uprobes/core: Handle breakpoint and singlestep exceptions")
+Signed-off-by: Sebastian Mayr <me@sam.st>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
+Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/20190728152617.7308-1-me@sam.st
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/uprobes.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
+index e78a6b1db74b0..e35466afe989d 100644
+--- a/arch/x86/kernel/uprobes.c
++++ b/arch/x86/kernel/uprobes.c
+@@ -514,9 +514,12 @@ struct uprobe_xol_ops {
+       void    (*abort)(struct arch_uprobe *, struct pt_regs *);
+ };
+-static inline int sizeof_long(void)
++static inline int sizeof_long(struct pt_regs *regs)
+ {
+-      return in_ia32_syscall() ? 4 : 8;
++      /*
++       * Check registers for mode as in_xxx_syscall() does not apply here.
++       */
++      return user_64bit_mode(regs) ? 8 : 4;
+ }
+ static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+@@ -527,9 +530,9 @@ static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+ static int push_ret_address(struct pt_regs *regs, unsigned long ip)
+ {
+-      unsigned long new_sp = regs->sp - sizeof_long();
++      unsigned long new_sp = regs->sp - sizeof_long(regs);
+-      if (copy_to_user((void __user *)new_sp, &ip, sizeof_long()))
++      if (copy_to_user((void __user *)new_sp, &ip, sizeof_long(regs)))
+               return -EFAULT;
+       regs->sp = new_sp;
+@@ -562,7 +565,7 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs
+               long correction = utask->vaddr - utask->xol_vaddr;
+               regs->ip += correction;
+       } else if (auprobe->defparam.fixups & UPROBE_FIX_CALL) {
+-              regs->sp += sizeof_long(); /* Pop incorrect return address */
++              regs->sp += sizeof_long(regs); /* Pop incorrect return address */
+               if (push_ret_address(regs, utask->vaddr + auprobe->defparam.ilen))
+                       return -ERESTART;
+       }
+@@ -671,7 +674,7 @@ static int branch_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+        * "call" insn was executed out-of-line. Just restore ->sp and restart.
+        * We could also restore ->ip and try to call branch_emulate_op() again.
+        */
+-      regs->sp += sizeof_long();
++      regs->sp += sizeof_long(regs);
+       return -ERESTART;
+ }
+@@ -962,7 +965,7 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+ unsigned long
+ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
+ {
+-      int rasize = sizeof_long(), nleft;
++      int rasize = sizeof_long(regs), nleft;
+       unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */
+       if (copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize))
+-- 
+2.20.1
+