From: Sasha Levin Date: Tue, 3 Sep 2019 04:56:24 +0000 (-0400) Subject: fixes for 4.14 X-Git-Tag: v4.4.191~40 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d7f2f56ae1140d9f0856ecb3dd25e667e9185763;p=thirdparty%2Fkernel%2Fstable-queue.git fixes for 4.14 Signed-off-by: Sasha Levin --- diff --git a/queue-4.14/series b/queue-4.14/series index 3d008b1276f..0b8ddcce021 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -25,3 +25,4 @@ kvm-x86-skip-populating-logical-dest-map-if-apic-is-not-sw-enabled.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 +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..dadeabf81a8 --- /dev/null +++ b/queue-4.14/uprobes-x86-fix-detection-of-32-bit-user-mode.patch @@ -0,0 +1,130 @@ +From c63e9c2a9ecd90df7a073322a5d90ed9fad19196 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 +