oss-sec mailing list archives
Re: CVE-2014-4699: Linux ptrace bug
From: Andy Lutomirski <luto () amacapital net>
Date: Tue, 08 Jul 2014 15:22:36 -0700
On 07/04/2014 02:05 PM, Andy Lutomirski wrote:
Hi everyone- Upstream commit b9cd18de4db3c9ffa7e17b0dc0ca99ed5aa4d43a fixes a ptrace bug. The exact scope of the bug is somewhat unclear right now. I see no reason why the bug should not be present as far back as Linux 2.6.17, but it seems to be difficult to reproduce on old kernels. There is some ongoing discussion on linux-distros about the impact and applicability of this bug. More details and a PoC to follow some time next week. I'm being intentionally vague here: this bug has existed for a long time, but exploiting it at all is tricky enough (and possibly kernel-version dependent enough) that it's gone unnoticed. I would currently prefer to give the distros and users a bit of a headstart before publicly disclosing the complete details of how to test/exploit the bug. It is likely to have a high enough impact, at least on new enough kernels, that it should be patched ASAP.
Time for full details. Intel CPUs implement sysret oddly: sysret will #GP *from kernel mode* if RIP/RCX is non-canonical. This is only a problem because sysret does not affect RSP, so the kernel needs to load the user's RSP value prior to running sysret. That means that an exception frame will be written to the address at RSP, which is necessarily user-controlled. If RSP is a writable user address and the CPU does not have SMAP, then the kernel's general_protection handler will actually execute from a user-controlled stack, and user code can attempt to race with the kernel to take over the system. Even on SMAP systems (which no one has yet anyway), it's possible to set RSP to point to an important kernel data structure and overwrite it in a partially controlled manner. Overwriting the IDT like this was traditional, but that's difficult now on Linux, since the public IDT address is read-only. If RSP points somewhere non-writable, then sysret will double-fault and OOPS cleanly on an IST stack. The upshot is that allowing user code to set the saved RIP address to a non-canonical value in a non-IRET-using system call is bad. On recent unpatched kernels, this can be done using fork(2). On other kernels, there may or may not be other attack vectors. The upstream fix fixes a related bug in that the sysret path failed to restore some registers on the same fork(2) path. This could potentially cause gdb to malfunction. I've attached a proof-of-concept exploit. It double-faults reliably on unpatched Intel CPUs. The precise cause of the double-fault is left as an exercise to the reader :) --Andy
Attachment:
ptrace_fork.c
Description:
Current thread:
- Re: CVE-2014-4699: Linux ptrace bug, (continued)
- Re: CVE-2014-4699: Linux ptrace bug Andy Lutomirski (Jul 08)
- Re: CVE-2014-4699: Linux ptrace bug Solar Designer (Jul 08)
- Re: CVE-2014-4699: Linux ptrace bug Yves-Alexis Perez (Jul 05)
- Re: CVE-2014-4699: Linux ptrace bug Marc Deslauriers (Jul 05)
- Re: CVE-2014-4699: Linux ptrace bug John Johansen (Jul 06)
- Re: CVE-2014-4699: Linux ptrace bug Solar Designer (Jul 06)
- Re: CVE-2014-4699: Linux ptrace bug John Johansen (Jul 06)
- Re: CVE-2014-4699: Linux ptrace bug Solar Designer (Jul 08)