Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754223AbbFISyx (ORCPT ); Tue, 9 Jun 2015 14:54:53 -0400 Received: from mx1.redhat.com ([209.132.183.28]:56006 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754194AbbFISyf (ORCPT ); Tue, 9 Jun 2015 14:54:35 -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 5/5] x86/asm/entry/32: Simplify ptrace register shuffling Date: Tue, 9 Jun 2015 20:54:11 +0200 Message-Id: <1433876051-26604-5-git-send-email-dvlasenk@redhat.com> In-Reply-To: <1433876051-26604-1-git-send-email-dvlasenk@redhat.com> References: <1433876051-26604-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: 7516 Lines: 221 Before this patch, we were clearing pt_regs->r8..r11 on stack. We can as well just store actual r8..r11 registers there: they came from userspace, we leak no information by showing them to ptrace. This allows to get rid of one insn ("xor %eax,%eax"). Not a big deal, but still... After call to syscall_trace_enter(), before this patch we were restoring clobbered registers and jump to code which converts 32-bit syscall ABI to 64-bit C ABI. This is unnecessary work, we can combine both steps into one (similar to what audit code does already). Also, we do not need "_do_call" labels anymore. text data bss dec hex filename 1391 0 0 1391 56f entry_64_compat.o.before 1327 0 0 1327 52f entry_64_compat.o.after 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/entry/entry_64_compat.S | 121 ++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 51 deletions(-) diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index d83e7e3..9d40cae 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S @@ -110,7 +110,6 @@ sysenter_flags_fixed: testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) jnz sysenter_tracesys -sysenter_do_call: /* 32-bit syscall -> 64-bit C ABI argument conversion */ movl %edi, %r8d /* arg5 */ movl %ebp, %r9d /* arg6 */ @@ -248,24 +247,31 @@ sysenter_tracesys: testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) jz sysenter_auditsys #endif - SAVE_EXTRA_REGS - xorl %eax, %eax /* Do not leak kernel information */ - movq %rax, R11(%rsp) - movq %rax, R10(%rsp) - movq %rax, R9(%rsp) - movq %rax, R8(%rsp) + /* + * Ptrace needs complete pt_regs. Fill members we didn't save earlier. + * r8..r15 are not really meaningful, but leaving uninitialized data + * there may leak kernel data to ptrace. + */ + movq %r11, R11(%rsp) + movq %r10, R10(%rsp) + movq %r9, R9(%rsp) + movq %r8, R8(%rsp) + SAVE_EXTRA_REGS /* pt_regs->bp, bx, r12-15 */ movq %rsp, %rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - - /* Reload arg registers from stack. (see sysenter_tracesys) */ - movl RCX(%rsp), %ecx - movl RDX(%rsp), %edx - movl RSI(%rsp), %esi - movl RDI(%rsp), %edi - movl %eax, %eax /* zero extension */ - - RESTORE_EXTRA_REGS - jmp sysenter_do_call + /* + * We are going to jump back to syscall dispatch. + * Prepare syscall args as required by 64-bit C ABI. + * We must read data from pt_regs: ptrace could have changed it. + */ + movl %eax, %eax /* syscall number: zero extend it */ + movl RBX(%rsp), %edi /* arg1 */ + movl RCX(%rsp), %esi /* arg2 */ + movl RDX(%rsp), %edx /* arg3 */ + movl RSI(%rsp), %ecx /* arg4 */ + movl RDI(%rsp), %r8d /* arg5 */ + movl RBP(%rsp), %r9d /* arg6 */ + jmp sysenter_dispatch ENDPROC(entry_SYSENTER_compat) /* @@ -339,7 +348,6 @@ ENTRY(entry_SYSCALL_compat) testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) jnz cstar_tracesys -cstar_do_call: /* 32-bit syscall -> 64-bit C ABI argument conversion */ movl %edi, %r8d /* arg5 */ movl %ebp, %r9d /* arg6 */ @@ -402,24 +410,31 @@ cstar_tracesys: testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) jz cstar_auditsys #endif - SAVE_EXTRA_REGS - xorl %eax, %eax /* Do not leak kernel information */ - movq %rax, R11(%rsp) - movq %rax, R10(%rsp) - movq %rax, R9(%rsp) - movq %rax, R8(%rsp) + /* + * Ptrace needs complete pt_regs. Fill members we didn't save earlier. + * r8..r15 are not really meaningful, but leaving uninitialized data + * there may leak kernel data to ptrace. + */ + movq %r11, R11(%rsp) + movq %r10, R10(%rsp) + movq %r9, R9(%rsp) + movq %r8, R8(%rsp) + SAVE_EXTRA_REGS /* pt_regs->bp, bx, r12-15 */ movq %rsp, %rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - - /* Reload arg registers from stack. (see sysenter_tracesys) */ - movl RCX(%rsp), %ecx - movl RDX(%rsp), %edx - movl RSI(%rsp), %esi - movl RDI(%rsp), %edi - movl %eax, %eax /* zero extension */ - - RESTORE_EXTRA_REGS - jmp cstar_do_call + /* + * We are going to jump back to syscall dispatch. + * Prepare syscall args as required by 64-bit C ABI. + * We must read data from pt_regs: ptrace could have changed it. + */ + movl %eax, %eax /* syscall number: zero extend it */ + movl RBX(%rsp), %edi /* arg1 */ + movl RCX(%rsp), %esi /* arg2 */ + movl RDX(%rsp), %edx /* arg3 */ + movl RSI(%rsp), %ecx /* arg4 */ + movl RDI(%rsp), %r8d /* arg5 */ + movl RBP(%rsp), %r9d /* arg6 */ + jmp cstar_dispatch END(entry_SYSCALL_compat) ia32_badarg: @@ -483,15 +498,15 @@ ENTRY(entry_INT80_compat) orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) - jnz ia32_tracesys + jnz int80_tracesys -ia32_do_call: /* 32-bit syscall -> 64-bit C ABI argument conversion */ movl %edi, %r8d /* arg5 */ movl %ebp, %r9d /* arg6 */ xchg %ecx, %esi /* rsi:arg2, rcx:arg4 */ movl %ebx, %edi /* arg1 */ movl %edx, %edx /* arg3 (zero extension) */ +int80_dispatch: cmpq $(IA32_NR_syscalls-1), %rax ja 1f @@ -500,24 +515,28 @@ ia32_do_call: 1: jmp int_ret_from_sys_call -ia32_tracesys: - SAVE_EXTRA_REGS - movq %rsp, %rdi /* &pt_regs -> arg1 */ +int80_tracesys: + /* + * Ptrace needs complete pt_regs. Fill members we didn't save earlier. + * r8..r15 are not really meaningful, but leaving uninitialized data + * there may leak kernel data to ptrace. + */ + SAVE_EXTRA_REGS /* pt_regs->bp, bx, r12-15 */ + movq %rsp, %rdi /* &pt_regs -> arg1 */ call syscall_trace_enter /* - * Reload arg registers from stack in case ptrace changed them. - * Don't reload %eax because syscall_trace_enter() returned - * the %rax value we should see. But do truncate it to 32 bits. - * If it's -1 to make us punt the syscall, then (u32)-1 is still - * an appropriately invalid value. + * We are going to jump back to syscall dispatch. + * Prepare syscall args as required by 64-bit C ABI. + * We must read data from pt_regs: ptrace could have changed it. */ - movl RCX(%rsp), %ecx - movl RDX(%rsp), %edx - movl RSI(%rsp), %esi - movl RDI(%rsp), %edi - movl %eax, %eax /* zero extension */ - RESTORE_EXTRA_REGS - jmp ia32_do_call + movl %eax, %eax /* syscall number: zero extend it */ + movl RBX(%rsp), %edi /* arg1 */ + movl RCX(%rsp), %esi /* arg2 */ + movl RDX(%rsp), %edx /* arg3 */ + movl RSI(%rsp), %ecx /* arg4 */ + movl RDI(%rsp), %r8d /* arg5 */ + movl RBP(%rsp), %r9d /* arg6 */ + jmp int80_dispatch END(entry_INT80_compat) .macro PTREGSCALL label, func -- 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/