From 4e3b02135297904c171d9900077e2ca9ec733c7f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 6 Jul 2014 23:46:24 +0000 Subject: [PATCH] [amd64] ptrace,x86: force IRET path after a ptrace_stop() (CVE-2014-4699) svn path=/dists/sid/linux/; revision=21504 --- debian/changelog | 3 + ...-force-IRET-path-after-a-ptrace_stop.patch | 74 +++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 78 insertions(+) create mode 100644 debian/patches/bugfix/all/ptrace-x86-force-IRET-path-after-a-ptrace_stop.patch diff --git a/debian/changelog b/debian/changelog index 29e222323..5fe970202 100644 --- a/debian/changelog +++ b/debian/changelog @@ -56,6 +56,9 @@ linux (3.14.10-1) UNRELEASED; urgency=medium - builddeb: use $OBJCOPY variable instead of objcopy (regression in 3.12) - [i386] efi-pstore: Fix an overflow on 32-bit builds + [ Ben Hutchings ] + * [amd64] ptrace,x86: force IRET path after a ptrace_stop() (CVE-2014-4699) + -- Ben Hutchings Sun, 06 Jul 2014 18:42:50 +0100 linux (3.14.9-1) unstable; urgency=medium diff --git a/debian/patches/bugfix/all/ptrace-x86-force-IRET-path-after-a-ptrace_stop.patch b/debian/patches/bugfix/all/ptrace-x86-force-IRET-path-after-a-ptrace_stop.patch new file mode 100644 index 000000000..323f4b592 --- /dev/null +++ b/debian/patches/bugfix/all/ptrace-x86-force-IRET-path-after-a-ptrace_stop.patch @@ -0,0 +1,74 @@ +From: Tejun Heo +Date: Thu, 3 Jul 2014 15:43:15 -0400 +Subject: ptrace,x86: force IRET path after a ptrace_stop() +Origin: https://git.kernel.org/linus/b9cd18de4db3c9ffa7e17b0dc0ca99ed5aa4d43a + +The 'sysret' fastpath does not correctly restore even all regular +registers, much less any segment registers or reflags values. That is +very much part of why it's faster than 'iret'. + +Normally that isn't a problem, because the normal ptrace() interface +catches the process using the signal handler infrastructure, which +always returns with an iret. + +However, some paths can get caught using ptrace_event() instead of the +signal path, and for those we need to make sure that we aren't going to +return to user space using 'sysret'. Otherwise the modifications that +may have been done to the register set by the tracer wouldn't +necessarily take effect. + +Fix it by forcing IRET path by setting TIF_NOTIFY_RESUME from +arch_ptrace_stop_needed() which is invoked from ptrace_stop(). + +Signed-off-by: Tejun Heo +Reported-by: Andy Lutomirski +Acked-by: Oleg Nesterov +Suggested-by: Linus Torvalds +Cc: stable@vger.kernel.org +Signed-off-by: Linus Torvalds +--- + arch/x86/include/asm/ptrace.h | 16 ++++++++++++++++ + include/linux/ptrace.h | 3 +++ + 2 files changed, 19 insertions(+) + +diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h +index 14fd6fd..6205f0c 100644 +--- a/arch/x86/include/asm/ptrace.h ++++ b/arch/x86/include/asm/ptrace.h +@@ -231,6 +231,22 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, + + #define ARCH_HAS_USER_SINGLE_STEP_INFO + ++/* ++ * When hitting ptrace_stop(), we cannot return using SYSRET because ++ * that does not restore the full CPU state, only a minimal set. The ++ * ptracer can change arbitrary register values, which is usually okay ++ * because the usual ptrace stops run off the signal delivery path which ++ * forces IRET; however, ptrace_event() stops happen in arbitrary places ++ * in the kernel and don't force IRET path. ++ * ++ * So force IRET path after a ptrace stop. ++ */ ++#define arch_ptrace_stop_needed(code, info) \ ++({ \ ++ set_thread_flag(TIF_NOTIFY_RESUME); \ ++ false; \ ++}) ++ + struct user_desc; + extern int do_get_thread_area(struct task_struct *p, int idx, + struct user_desc __user *info); +diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h +index 077904c..cc79eff 100644 +--- a/include/linux/ptrace.h ++++ b/include/linux/ptrace.h +@@ -334,6 +334,9 @@ static inline void user_single_step_siginfo(struct task_struct *tsk, + * calling arch_ptrace_stop() when it would be superfluous. For example, + * if the thread has not been back to user mode since the last stop, the + * thread state might indicate that nothing needs to be done. ++ * ++ * This is guaranteed to be invoked once before a task stops for ptrace and ++ * may include arch-specific operations necessary prior to a ptrace stop. + */ + #define arch_ptrace_stop_needed(code, info) (0) + #endif diff --git a/debian/patches/series b/debian/patches/series index 63add18c6..f1feb36f6 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -91,3 +91,4 @@ debian/drivers-base-platform-avoid-abi-change-in-3.14.6.patch debian/dma-avoid-abi-change-in-3.14.6.patch debian/vfs-avoid-abi-change-for-cve-2014-4014.patch debian/alsa-avoid-abi-change-for-cve-2014-4652-fix.patch +bugfix/all/ptrace-x86-force-IRET-path-after-a-ptrace_stop.patch