From: Anton Arapov <aarapov@redhat.com> Subject: [RHEL5.1 patch] RHBZ#297881: CVE-2007-4573 x86_64 syscall vulnerability Date: Mon, 24 Sep 2007 10:46:10 +0200 Bugzilla: 297881 Message-Id: <h8hclk5u3x.fsf@pepelac.englab.brq.redhat.com> Changelog: [x86_64] syscall vulnerability BZ#297881: https://bugzilla.redhat.com/show_bug.cgi?id=297881 Description: (by Roland McGrath) Any user on every x86_64 kernel around can arrange to run code of their choice in kernel mode without much trouble. AFAIK exactly the mechanism my exploit/test case uses is the only way to exploit it. That is, int $0x80 entry from 64-bit mode (bogus, but allowed) while PTRACE_SYSCALL'd and then ptrace changing orig_rax so the low bits are in the a valid syscall number range but some high bits are set. Et voila, the system call of your choice is really the kernel-mode call of your choice. Upstream status: commit# 176df2457ef6207156ca1a40991c54ca01fef567 - It actually does a little more than strictly needed -- the other registers are already zero extended. Also remove the now unnecessary and non functional compat task check in ptrace. Test status: Patch has been tested for compilation, bot and tested by problem reproducer written by Roland. == diff -urpN linux-2.6.18.noarch.orig/arch/x86_64/ia32/ia32entry.S linux-2.6.18.noarch/arch/x86_64/ia32/ia32entry.S --- linux-2.6.18.noarch.orig/arch/x86_64/ia32/ia32entry.S 2007-09-24 08:21:05.000000000 +0200 +++ linux-2.6.18.noarch/arch/x86_64/ia32/ia32entry.S 2007-09-24 08:38:50.000000000 +0200 @@ -38,6 +38,18 @@ movq %rax,R8(%rsp) .endm + .macro LOAD_ARGS32 offset + movl \offset(%rsp),%r11d + movl \offset+8(%rsp),%r10d + movl \offset+16(%rsp),%r9d + movl \offset+24(%rsp),%r8d + movl \offset+40(%rsp),%ecx + movl \offset+48(%rsp),%edx + movl \offset+56(%rsp),%esi + movl \offset+64(%rsp),%edi + movl \offset+72(%rsp),%eax + .endm + .macro CFI_STARTPROC32 simple CFI_STARTPROC \simple CFI_UNDEFINED r8 @@ -151,7 +163,7 @@ sysenter_tracesys: movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST movl %ebp, %ebp /* no need to do an access_ok check here because rbp has been @@ -253,7 +265,7 @@ cstar_tracesys: movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST movl RSP-ARGOFFSET(%rsp), %r8d /* no need to do an access_ok check here because r8 has been @@ -330,7 +342,7 @@ ia32_tracesys: movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST jmp ia32_do_syscall END(ia32_syscall) diff -urpN linux-2.6.18.noarch.orig/arch/x86_64/ia32/ia32entry-xen.S linux-2.6.18.noarch/arch/x86_64/ia32/ia32entry-xen.S --- linux-2.6.18.noarch.orig/arch/x86_64/ia32/ia32entry-xen.S 2007-09-24 08:21:05.000000000 +0200 +++ linux-2.6.18.noarch/arch/x86_64/ia32/ia32entry-xen.S 2007-09-24 08:42:35.000000000 +0200 @@ -55,6 +55,18 @@ #define __sti sti #endif + .macro LOAD_ARGS32 offset + movl \offset(%rsp),%r11d + movl \offset+8(%rsp),%r10d + movl \offset+16(%rsp),%r9d + movl \offset+24(%rsp),%r8d + movl \offset+40(%rsp),%ecx + movl \offset+48(%rsp),%edx + movl \offset+56(%rsp),%esi + movl \offset+64(%rsp),%edi + movl \offset+72(%rsp),%eax + .endm + .macro CFI_STARTPROC32 simple CFI_STARTPROC \simple CFI_UNDEFINED r8 @@ -171,7 +183,7 @@ sysenter_tracesys: movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST movl %ebp, %ebp /* no need to do an access_ok check here because rbp has been @@ -275,7 +287,7 @@ cstar_tracesys: movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST movl RSP-ARGOFFSET(%rsp), %r8d /* no need to do an access_ok check here because r8 has been @@ -357,7 +369,7 @@ ia32_tracesys: movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST jmp ia32_do_syscall END(ia32_syscall) diff -urpN linux-2.6.18.noarch.orig/arch/x86_64/kernel/ptrace.c linux-2.6.18.noarch/arch/x86_64/kernel/ptrace.c --- linux-2.6.18.noarch.orig/arch/x86_64/kernel/ptrace.c 2007-09-24 08:21:05.000000000 +0200 +++ linux-2.6.18.noarch/arch/x86_64/kernel/ptrace.c 2007-09-24 08:38:50.000000000 +0200 @@ -234,10 +234,6 @@ static int putreg(struct task_struct *ch { unsigned long tmp; - /* Some code in the 64bit emulation may not be 64bit clean. - Don't take any chances. */ - if (test_tsk_thread_flag(child, TIF_IA32)) - value &= 0xffffffff; switch (regno) { case offsetof(struct user_regs_struct,fs): if (value && (value & 3) != 3) -- Anton Arapov, <aarapov@redhat.com> Kernel Development, Red Hat GPG Key ID: 0x6FA8C812