From: Sasha Levin Date: Tue, 3 Sep 2019 13:18:39 +0000 (-0400) Subject: re-add uprobes-x86-fix-detection-of-32-bit-user-mode.patch X-Git-Tag: v4.4.191~28^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1f736154acc62963c9b173e2b9ea960e512b07a1;p=thirdparty%2Fkernel%2Fstable-queue.git re-add uprobes-x86-fix-detection-of-32-bit-user-mode.patch Signed-off-by: Sasha Levin --- diff --git a/queue-4.14/series b/queue-4.14/series index eaf1bd9dcb4..00b93b98e08 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -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 index 00000000000..d95e8028b07 --- /dev/null +++ b/queue-4.14/uprobes-x86-fix-detection-of-32-bit-user-mode.patch @@ -0,0 +1,130 @@ +From ced967ce0097e755d65cf61aa01bf1236406be08 Mon Sep 17 00:00:00 2001 +From: Sebastian Mayr +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 +Signed-off-by: Thomas Gleixner +Cc: Masami Hiramatsu +Cc: Dmitry Safonov +Cc: Oleg Nesterov +Cc: Srikar Dronamraju +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/20190728152617.7308-1-me@sam.st +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..fbd0d97f275 --- /dev/null +++ b/queue-4.4/ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch @@ -0,0 +1,84 @@ +From 1cd43e020c39afd0379678c2c01869657911f6ee Mon Sep 17 00:00:00 2001 +From: Ricardo Neri +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 +Signed-off-by: Ricardo Neri +Signed-off-by: Thomas Gleixner +Reviewed-by: Borislav Petkov +Cc: "Michael S. Tsirkin" +Cc: Peter Zijlstra +Cc: Dave Hansen +Cc: ricardo.neri@intel.com +Cc: Adrian Hunter +Cc: Paul Gortmaker +Cc: Huang Rui +Cc: Qiaowei Ren +Cc: Shuah Khan +Cc: Kees Cook +Cc: Jonathan Corbet +Cc: Jiri Slaby +Cc: Dmitry Vyukov +Cc: "Ravi V. Shankar" +Cc: Chris Metcalf +Cc: Brian Gerst +Cc: Arnaldo Carvalho de Melo +Cc: Andy Lutomirski +Cc: Colin Ian King +Cc: Chen Yucong +Cc: Adam Buchbinder +Cc: Vlastimil Babka +Cc: Lorenzo Stoakes +Cc: Masami Hiramatsu +Cc: Paolo Bonzini +Cc: Andrew Morton +Cc: Thomas Garnier +Link: https://lkml.kernel.org/r/1509135945-13762-4-git-send-email-ricardo.neri-calderon@linux.intel.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.4/series b/queue-4.4/series index 7aa01522c0d..2e75efa7548 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -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 index 00000000000..9b4bf49b2ab --- /dev/null +++ b/queue-4.4/uprobes-x86-fix-detection-of-32-bit-user-mode.patch @@ -0,0 +1,130 @@ +From c016532f95355f95804209ea5e6efaf6ee8153af Mon Sep 17 00:00:00 2001 +From: Sebastian Mayr +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 +Signed-off-by: Thomas Gleixner +Cc: Masami Hiramatsu +Cc: Dmitry Safonov +Cc: Oleg Nesterov +Cc: Srikar Dronamraju +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/20190728152617.7308-1-me@sam.st +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..6358215765c --- /dev/null +++ b/queue-4.9/ptrace-x86-make-user_64bit_mode-available-to-32-bit-.patch @@ -0,0 +1,84 @@ +From bd4a82025f464406a80a4ad48fe3b13a6cfcfd78 Mon Sep 17 00:00:00 2001 +From: Ricardo Neri +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 +Signed-off-by: Ricardo Neri +Signed-off-by: Thomas Gleixner +Reviewed-by: Borislav Petkov +Cc: "Michael S. Tsirkin" +Cc: Peter Zijlstra +Cc: Dave Hansen +Cc: ricardo.neri@intel.com +Cc: Adrian Hunter +Cc: Paul Gortmaker +Cc: Huang Rui +Cc: Qiaowei Ren +Cc: Shuah Khan +Cc: Kees Cook +Cc: Jonathan Corbet +Cc: Jiri Slaby +Cc: Dmitry Vyukov +Cc: "Ravi V. Shankar" +Cc: Chris Metcalf +Cc: Brian Gerst +Cc: Arnaldo Carvalho de Melo +Cc: Andy Lutomirski +Cc: Colin Ian King +Cc: Chen Yucong +Cc: Adam Buchbinder +Cc: Vlastimil Babka +Cc: Lorenzo Stoakes +Cc: Masami Hiramatsu +Cc: Paolo Bonzini +Cc: Andrew Morton +Cc: Thomas Garnier +Link: https://lkml.kernel.org/r/1509135945-13762-4-git-send-email-ricardo.neri-calderon@linux.intel.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.9/series b/queue-4.9/series index 5084716cc89..8ac5b5c664d 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -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 index 00000000000..dff32e4f429 --- /dev/null +++ b/queue-4.9/uprobes-x86-fix-detection-of-32-bit-user-mode.patch @@ -0,0 +1,130 @@ +From 73185c5db135e2733c94cf57f392cee00b841c99 Mon Sep 17 00:00:00 2001 +From: Sebastian Mayr +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 +Signed-off-by: Thomas Gleixner +Cc: Masami Hiramatsu +Cc: Dmitry Safonov +Cc: Oleg Nesterov +Cc: Srikar Dronamraju +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/20190728152617.7308-1-me@sam.st +Signed-off-by: Sasha Levin +--- + 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 +