| From adf9ae0d159d3dc94f58d788fc4757c8749ac0df Mon Sep 17 00:00:00 2001 |
| From: Johannes Berg <johannes.berg@intel.com> |
| Date: Tue, 13 Jul 2021 23:47:10 +0200 |
| Subject: um: fix stub location calculation |
| |
| From: Johannes Berg <johannes.berg@intel.com> |
| |
| commit adf9ae0d159d3dc94f58d788fc4757c8749ac0df upstream. |
| |
| In commit 9f0b4807a44f ("um: rework userspace stubs to not hard-code |
| stub location") I changed stub_segv_handler() to do a calculation with |
| a pointer to a stack variable to find the data page that we're using |
| for the stack and the rest of the data. This same commit was meant to |
| do it as well for stub_clone_handler(), but the change inadvertently |
| went into commit 84b2789d6115 ("um: separate child and parent errors |
| in clone stub") instead. |
| |
| This was reported to not be compiled correctly by gcc 5, causing the |
| code to crash here. I'm not sure why, perhaps it's UB because the var |
| isn't initialized? In any case, this trick always seemed bad, so just |
| create a new inline function that does the calculation in assembly. |
| |
| Reported-by: subashab@codeaurora.org |
| Fixes: 9f0b4807a44f ("um: rework userspace stubs to not hard-code stub location") |
| Fixes: 84b2789d6115 ("um: separate child and parent errors in clone stub") |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> |
| Signed-off-by: Richard Weinberger <richard@nod.at> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/um/kernel/skas/clone.c | 3 +-- |
| arch/x86/um/shared/sysdep/stub_32.h | 12 ++++++++++++ |
| arch/x86/um/shared/sysdep/stub_64.h | 12 ++++++++++++ |
| arch/x86/um/stub_segv.c | 3 +-- |
| 4 files changed, 26 insertions(+), 4 deletions(-) |
| |
| --- a/arch/um/kernel/skas/clone.c |
| +++ b/arch/um/kernel/skas/clone.c |
| @@ -24,8 +24,7 @@ |
| void __attribute__ ((__section__ (".__syscall_stub"))) |
| stub_clone_handler(void) |
| { |
| - int stack; |
| - struct stub_data *data = (void *) ((unsigned long)&stack & ~(UM_KERN_PAGE_SIZE - 1)); |
| + struct stub_data *data = get_stub_page(); |
| long err; |
| |
| err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, |
| --- a/arch/x86/um/shared/sysdep/stub_32.h |
| +++ b/arch/x86/um/shared/sysdep/stub_32.h |
| @@ -101,4 +101,16 @@ static inline void remap_stack_and_trap( |
| "memory"); |
| } |
| |
| +static __always_inline void *get_stub_page(void) |
| +{ |
| + unsigned long ret; |
| + |
| + asm volatile ( |
| + "movl %%esp,%0 ;" |
| + "andl %1,%0" |
| + : "=a" (ret) |
| + : "g" (~(UM_KERN_PAGE_SIZE - 1))); |
| + |
| + return (void *)ret; |
| +} |
| #endif |
| --- a/arch/x86/um/shared/sysdep/stub_64.h |
| +++ b/arch/x86/um/shared/sysdep/stub_64.h |
| @@ -108,4 +108,16 @@ static inline void remap_stack_and_trap( |
| __syscall_clobber, "r10", "r8", "r9"); |
| } |
| |
| +static __always_inline void *get_stub_page(void) |
| +{ |
| + unsigned long ret; |
| + |
| + asm volatile ( |
| + "movq %%rsp,%0 ;" |
| + "andq %1,%0" |
| + : "=a" (ret) |
| + : "g" (~(UM_KERN_PAGE_SIZE - 1))); |
| + |
| + return (void *)ret; |
| +} |
| #endif |
| --- a/arch/x86/um/stub_segv.c |
| +++ b/arch/x86/um/stub_segv.c |
| @@ -11,9 +11,8 @@ |
| void __attribute__ ((__section__ (".__syscall_stub"))) |
| stub_segv_handler(int sig, siginfo_t *info, void *p) |
| { |
| - int stack; |
| + struct faultinfo *f = get_stub_page(); |
| ucontext_t *uc = p; |
| - struct faultinfo *f = (void *)(((unsigned long)&stack) & ~(UM_KERN_PAGE_SIZE - 1)); |
| |
| GET_FAULTINFO_FROM_MC(*f, &uc->uc_mcontext); |
| trap_myself(); |