Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

um: fix stub location calculation

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>

authored by

Johannes Berg and committed by
Richard Weinberger
adf9ae0d 6a241d29

+26 -4
+1 -2
arch/um/kernel/skas/clone.c
··· 24 24 void __attribute__ ((__section__ (".__syscall_stub"))) 25 25 stub_clone_handler(void) 26 26 { 27 - int stack; 28 - struct stub_data *data = (void *) ((unsigned long)&stack & ~(UM_KERN_PAGE_SIZE - 1)); 27 + struct stub_data *data = get_stub_page(); 29 28 long err; 30 29 31 30 err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
+12
arch/x86/um/shared/sysdep/stub_32.h
··· 101 101 "memory"); 102 102 } 103 103 104 + static __always_inline void *get_stub_page(void) 105 + { 106 + unsigned long ret; 107 + 108 + asm volatile ( 109 + "movl %%esp,%0 ;" 110 + "andl %1,%0" 111 + : "=a" (ret) 112 + : "g" (~(UM_KERN_PAGE_SIZE - 1))); 113 + 114 + return (void *)ret; 115 + } 104 116 #endif
+12
arch/x86/um/shared/sysdep/stub_64.h
··· 108 108 __syscall_clobber, "r10", "r8", "r9"); 109 109 } 110 110 111 + static __always_inline void *get_stub_page(void) 112 + { 113 + unsigned long ret; 114 + 115 + asm volatile ( 116 + "movq %%rsp,%0 ;" 117 + "andq %1,%0" 118 + : "=a" (ret) 119 + : "g" (~(UM_KERN_PAGE_SIZE - 1))); 120 + 121 + return (void *)ret; 122 + } 111 123 #endif
+1 -2
arch/x86/um/stub_segv.c
··· 11 11 void __attribute__ ((__section__ (".__syscall_stub"))) 12 12 stub_segv_handler(int sig, siginfo_t *info, void *p) 13 13 { 14 - int stack; 14 + struct faultinfo *f = get_stub_page(); 15 15 ucontext_t *uc = p; 16 - struct faultinfo *f = (void *)(((unsigned long)&stack) & ~(UM_KERN_PAGE_SIZE - 1)); 17 16 18 17 GET_FAULTINFO_FROM_MC(*f, &uc->uc_mcontext); 19 18 trap_myself();