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

x86/asm/entry/64: Save user RSP in pt_regs->sp on SYSCALL64 fastpath

Prepare for the removal of 'usersp', by simplifying PER_CPU(old_rsp) usage:

- use it only as temp storage

- store the userspace stack pointer immediately in pt_regs->sp
on syscall entry, instead of using it later, on syscall exit.

- change C code to use pt_regs->sp only, instead of PER_CPU(old_rsp)
and task->thread.usersp.

FIXUP/RESTORE_TOP_OF_STACK are simplified as well.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Alexei Starovoitov <ast@plumgrid.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Will Drewry <wad@chromium.org>
Link: http://lkml.kernel.org/r/1425926364-9526-4-git-send-email-dvlasenk@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Denys Vlasenko and committed by
Ingo Molnar
263042e4 616ab249

+12 -21
+1 -1
arch/x86/include/asm/compat.h
··· 301 301 sp = task_pt_regs(current)->sp; 302 302 } else { 303 303 /* -128 for the x32 ABI redzone */ 304 - sp = this_cpu_read(old_rsp) - 128; 304 + sp = task_pt_regs(current)->sp - 128; 305 305 } 306 306 307 307 return (void __user *)round_down(sp - len, 16);
+2 -6
arch/x86/include/asm/ptrace.h
··· 145 145 #endif 146 146 } 147 147 148 - #define current_user_stack_pointer() this_cpu_read(old_rsp) 149 - /* ia32 vs. x32 difference */ 150 - #define compat_user_stack_pointer() \ 151 - (test_thread_flag(TIF_IA32) \ 152 - ? current_pt_regs()->sp \ 153 - : this_cpu_read(old_rsp)) 148 + #define current_user_stack_pointer() current_pt_regs()->sp 149 + #define compat_user_stack_pointer() current_pt_regs()->sp 154 150 #endif 155 151 156 152 #ifdef CONFIG_X86_32
+7 -11
arch/x86/kernel/entry_64.S
··· 128 128 * manipulation. 129 129 */ 130 130 .macro FIXUP_TOP_OF_STACK tmp offset=0 131 - movq PER_CPU_VAR(old_rsp),\tmp 132 - movq \tmp,RSP+\offset(%rsp) 133 131 movq $__USER_DS,SS+\offset(%rsp) 134 132 movq $__USER_CS,CS+\offset(%rsp) 135 133 movq RIP+\offset(%rsp),\tmp /* get rip */ ··· 137 139 .endm 138 140 139 141 .macro RESTORE_TOP_OF_STACK tmp offset=0 140 - movq RSP+\offset(%rsp),\tmp 141 - movq \tmp,PER_CPU_VAR(old_rsp) 142 + /* nothing to do */ 142 143 .endm 143 144 144 145 /* ··· 219 222 * Interrupts are off on entry. 220 223 * Only called from user space. 221 224 * 222 - * XXX if we had a free scratch register we could save the RSP into the stack frame 223 - * and report it properly in ps. Unfortunately we haven't. 224 - * 225 225 * When user can change the frames always force IRET. That is because 226 226 * it deals with uncanonical addresses better. SYSRET has trouble 227 227 * with them due to bugs in both AMD and Intel CPUs. ··· 247 253 */ 248 254 ENABLE_INTERRUPTS(CLBR_NONE) 249 255 ALLOC_PT_GPREGS_ON_STACK 8 /* +8: space for orig_ax */ 256 + movq %rcx,RIP(%rsp) 257 + movq PER_CPU_VAR(old_rsp),%rcx 258 + movq %r11,EFLAGS(%rsp) 259 + movq %rcx,RSP(%rsp) 260 + movq_cfi rax,ORIG_RAX 250 261 SAVE_C_REGS_EXCEPT_RAX_RCX_R11 251 262 movq $-ENOSYS,RAX(%rsp) 252 - movq_cfi rax,ORIG_RAX 253 - movq %r11,EFLAGS(%rsp) 254 - movq %rcx,RIP(%rsp) 255 263 CFI_REL_OFFSET rip,RIP 256 264 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP) 257 265 jnz tracesys ··· 289 293 CFI_REGISTER rip,rcx 290 294 movq EFLAGS(%rsp),%r11 291 295 /*CFI_REGISTER rflags,r11*/ 292 - movq PER_CPU_VAR(old_rsp), %rsp 296 + movq RSP(%rsp),%rsp 293 297 /* 294 298 * 64bit SYSRET restores rip from rcx, 295 299 * rflags from r11 (but RF and VM bits are forced to 0),
+1 -1
arch/x86/kernel/perf_regs.c
··· 177 177 * than just blindly copying user_regs. 178 178 */ 179 179 regs_user->abi = PERF_SAMPLE_REGS_ABI_64; 180 - regs_user_copy->sp = this_cpu_read(old_rsp); 180 + regs_user_copy->sp = user_regs->sp; 181 181 regs_user_copy->cs = __USER_CS; 182 182 regs_user_copy->ss = __USER_DS; 183 183 regs_user_copy->cx = -1; /* usually contains garbage */
+1 -2
arch/x86/kernel/process_64.c
··· 602 602 603 603 unsigned long KSTK_ESP(struct task_struct *task) 604 604 { 605 - return (test_tsk_thread_flag(task, TIF_IA32)) ? 606 - (task_pt_regs(task)->sp) : ((task)->thread.usersp); 605 + return task_pt_regs(task)->sp; 607 606 }