Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752698AbbDDSz2 (ORCPT ); Sat, 4 Apr 2015 14:55:28 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49278 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752463AbbDDSz1 (ORCPT ); Sat, 4 Apr 2015 14:55:27 -0400 From: Denys Vlasenko To: Ingo Molnar Cc: Denys Vlasenko , Linus Torvalds , Steven Rostedt , Borislav Petkov , "H. Peter Anvin" , Andy Lutomirski , Oleg Nesterov , Frederic Weisbecker , Alexei Starovoitov , Will Drewry , Kees Cook , x86@kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] x86: clear EXTRA_REGS for all executable formats Date: Sat, 4 Apr 2015 20:55:19 +0200 Message-Id: <1428173719-7637-1-git-send-email-dvlasenk@redhat.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4782 Lines: 166 On failure, sys_execve does not clobber EXTRA_REGS, so we can just return to userpsace without saving/restoring them. On success, ELF_PLAT_INIT in sys_execve clears all these registers. On other executable formats: binfmt_flat.c has similar FLAT_PLAT_INIT, but x86 (and everyone else except sh) doesn't define it. binfmt_elf_fdpic.c has ELF_FDPIC_PLAT_INIT, but x86 (and most others) doesn't define it. There are no such hooks in binfmt_aout.c et al. We inherit EXTRA_REGS from the prior executable. This was not intended. This change removes SAVE/RESTORE_EXTRA_REGS in stub_execve, removes register clearing in ELF_PLAT_INIT, and instead simply clears them on success in stub_execve. Run-tested. Signed-off-by: Denys Vlasenko CC: Linus Torvalds CC: Steven Rostedt CC: Ingo Molnar CC: Borislav Petkov CC: "H. Peter Anvin" CC: Andy Lutomirski CC: Oleg Nesterov CC: Frederic Weisbecker CC: Alexei Starovoitov CC: Will Drewry CC: Kees Cook CC: x86@kernel.org CC: linux-kernel@vger.kernel.org --- arch/x86/include/asm/calling.h | 9 ++++++++ arch/x86/include/asm/elf.h | 7 +++--- arch/x86/kernel/entry_64.S | 50 +++++++++++++++++++----------------------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/arch/x86/include/asm/calling.h b/arch/x86/include/asm/calling.h index 4b5f7bf..1c8b50e 100644 --- a/arch/x86/include/asm/calling.h +++ b/arch/x86/include/asm/calling.h @@ -151,6 +151,15 @@ For 32-bit we have the following conventions - kernel is built with movq_cfi_restore 5*8+\offset, rbx .endm + .macro ZERO_EXTRA_REGS + xorl %r15d, %r15d + xorl %r14d, %r14d + xorl %r13d, %r13d + xorl %r12d, %r12d + xorl %ebp, %ebp + xorl %ebx, %ebx + .endm + .macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1 .if \rstor_r11 movq_cfi_restore 6*8, r11 diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index bd292ce..935588d9 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -171,10 +171,11 @@ do { \ static inline void elf_common_init(struct thread_struct *t, struct pt_regs *regs, const u16 ds) { - regs->ax = regs->bx = regs->cx = regs->dx = 0; - regs->si = regs->di = regs->bp = 0; + /* Commented-out registers are cleared in stub_execve */ + /*regs->ax = regs->bx =*/ regs->cx = regs->dx = 0; + regs->si = regs->di /*= regs->bp*/ = 0; regs->r8 = regs->r9 = regs->r10 = regs->r11 = 0; - regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0; + /*regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0;*/ t->fs = t->gs = 0; t->fsindex = t->gsindex = 0; t->ds = t->es = ds; diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 13185c5..65485b3 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -419,25 +419,27 @@ END(stub_\func) ENTRY(stub_execve) CFI_STARTPROC - addq $8, %rsp - DEFAULT_FRAME 0 - SAVE_EXTRA_REGS - call sys_execve - movq %rax,RAX(%rsp) - RESTORE_EXTRA_REGS - jmp int_ret_from_sys_call + DEFAULT_FRAME 0, 8 + call sys_execve +return_from_execve: + testl %eax, %eax + jz 1f + /* exec failed, can use fast SYSRET code path in this case */ + ret +1: + /* must use IRET code path (pt_regs->cs may have changed) */ + addq $8, %rsp + ZERO_EXTRA_REGS + movq %rax,RAX(%rsp) + jmp int_ret_from_sys_call CFI_ENDPROC END(stub_execve) ENTRY(stub_execveat) CFI_STARTPROC - addq $8, %rsp - DEFAULT_FRAME 0 - SAVE_EXTRA_REGS - call sys_execveat - movq %rax,RAX(%rsp) - RESTORE_EXTRA_REGS - jmp int_ret_from_sys_call + DEFAULT_FRAME 0, 8 + call sys_execveat + jmp return_from_execve CFI_ENDPROC END(stub_execveat) @@ -472,25 +474,17 @@ END(stub_x32_rt_sigreturn) ENTRY(stub_x32_execve) CFI_STARTPROC - addq $8, %rsp - DEFAULT_FRAME 0 - SAVE_EXTRA_REGS - call compat_sys_execve - movq %rax,RAX(%rsp) - RESTORE_EXTRA_REGS - jmp int_ret_from_sys_call + DEFAULT_FRAME 0, 8 + call compat_sys_execve + jmp return_from_execve CFI_ENDPROC END(stub_x32_execve) ENTRY(stub_x32_execveat) CFI_STARTPROC - addq $8, %rsp - DEFAULT_FRAME 0 - SAVE_EXTRA_REGS - call compat_sys_execveat - movq %rax,RAX(%rsp) - RESTORE_EXTRA_REGS - jmp int_ret_from_sys_call + DEFAULT_FRAME 0, 8 + call compat_sys_execveat + jmp return_from_execve CFI_ENDPROC END(stub_x32_execveat) -- 1.8.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/