Bug 437312 (CVE-2008-1367) - CVE-2008-1367 Kernel doesn't clear DF for signal handlers
Summary: CVE-2008-1367 Kernel doesn't clear DF for signal handlers
Keywords:
Status: CLOSED ERRATA
Alias: CVE-2008-1367
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
low
low
Target Milestone: ---
Assignee: Red Hat Product Security
QA Contact:
URL:
Whiteboard:
Depends On: 436131 437313 437314 437315 437316
Blocks:
TreeView+ depends on / blocked
 
Reported: 2008-03-13 15:03 UTC by Jan Lieskovsky
Modified: 2019-09-29 12:24 UTC (History)
7 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2010-12-23 16:45:19 UTC
Embargoed:


Attachments (Terms of Use)
Testcase for finding out the value of the DF flag. (679 bytes, text/x-csrc)
2008-03-13 15:05 UTC, Jan Lieskovsky
no flags Details


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHSA-2008:0211 0 normal SHIPPED_LIVE Important: kernel security and bug fix update 2008-05-07 07:03:52 UTC
Red Hat Product Errata RHSA-2008:0233 0 normal SHIPPED_LIVE Important: kernel security and bug fix update 2008-05-07 07:47:37 UTC
Red Hat Product Errata RHSA-2008:0508 0 normal SHIPPED_LIVE Important: kernel security and bug fix update 2008-06-25 15:18:03 UTC

Description Jan Lieskovsky 2008-03-13 15:03:34 UTC
Description of problem:

Jake Edge has reported the following gcc kernel related potential
security issue on LWN:

<cite>

A change to GCC for a recent release coupled with a kernel bug has created a
messy situation, with possible security implications. GCC changed some
assumptions about x86 processor flags, in accordance with the ABI standard, that
can lead to memory corruption for programs built with GCC 4.3.0. No one has come
up with a way to exploit the flaw, at least yet, but it clearly is a problem
that needs to be addressed.

The problem revolves around the x86 direction flag (DF), which governs whether
block memory operations operate forward through memory or backwards. The main
use for the flag is to support overlapping memory copies, where working
backwards through memory may be required so that the data being copied does not
get overwritten as the copy progresses. Debian hacker Aurélien Jarno reported
the problem to linux-kernel on March 5th, which was found when building Steel
Bank Common Lisp (SBCL) using the new compiler.

GCC's most recent release, 4.3.0, assumes that the direction flag has been
cleared (i.e. memory operations go in a forward direction) at the entry of each
function, as is specified by the ABI (which is, somewhat amusingly, found at
sco.com [PDF]). Unfortunately, this clashes with Linux signal handlers, which
get called, incorrectly, with the flag in whatever state it was in when the
signal occurred. This has the effect of leaking one bit of state from the user
space process that was running when the signal occurred to the signal handler,
which could be in another process.

That, in itself, is a bug, seemingly with fairly minimal impact. Prior to 4.3,
GCC would emit a cld (clear direction flag) opcode before doing inline string or
memory operations, so those operations would start from a known state. In 4.3,
GCC relies on the ABI mandate that the direction flag is cleared before entry to
a function, which means that the kernel needs to arrange that before calling a
signal handler. It currently doesn't, but a small patch fixes that.

The window of vulnerability is small, but was observed in SBCL. The sequence of
events that would lead to memory corruption are as follows:

    * a user space program does an operation (memmove() for example) that
      sets DF
    * a signal occurs for some process
    * the kernel calls the signal handler
    * the signal handler does a memmove() in what it thinks is a forward  
      direction
    * the memory is copied in the reverse direction, leading to corruption

</cite>

Link to the post:

http://lwn.net/Articles/272048/#Comments

Link to upstream fix:

http://git.kernel.org/?p=linux/kernel/git/x86/linux-2.6-x86.git;a=commitdiff;h=52c841e1012b8e73cc04b53f92fb933db580fb42

Comment 1 Jan Lieskovsky 2008-03-13 15:04:37 UTC
Additional comment from BZ#436131:

The debian folks reported that kernel doesn't ensure direction flag is cleared
upon entry to signal handler, which violates both i?86 and x86_64 ABIs.
Old GCCs conservatively used cld anyway before using any instructions that use
that flag, but GCC 4.3 no longer does that, it relies on the ABI guarantees that
on entry to a function the direction flag must be cleared.
See http://gcc.gnu.org/ml/gcc-patches/2006-12/msg00276.html
Anything that uses std instruction must cld again before calling another
function or before returning from function.
Unfortunately, if async signal is sent while a thread has std flag set, kernel
will start a signal handler with DF flag set.

The fix is addition of regs->eflags &= ~X86_EFLAGS_DF; or similar in
setup_frame/setup_rt_frame (i386, x86_64, x86_64 32-bit support).

While only code compiled with GCC 4.3 and later will be affected by this bug,
RHEL5 kernels are often used with later Fedora userland (e.g. koji buildboxes),
so IMHO if at all possible to fix should be backported to RHEL5.2 and perhaps
even RHEL4.7 kernels.

Comment 2 Jan Lieskovsky 2008-03-13 15:05:53 UTC
Created attachment 297943 [details]
Testcase for finding out the value of the DF flag.

Comment 4 Jan Lieskovsky 2008-03-13 15:08:38 UTC
Comments from Jason Baron and reply from Jakub Jelinek describing the 
current behaviour and the nature of the bug:

<cite jbaron>

Whenever i run the test case (sending SIGUSR1 to the test process), i get: 'DF =
1'. indicating that the the df flag is set...I expected it to be unset b/c from
reading this gcc clears the df flags...i've tried older distros and compat-gcc
and still i get DF = 1...what am i missing? thanks.

</cite>

<cite jakub>

If you get DF = 1, then that means the kernel is buggy.  The psABI says that the
DF flag must be clear upon entry to a function and also on exit from function.

GCC <= 4.2.x would add cld just in case, whenever it used some string
instruction (movs*/stos*/loads*/cmps* etc.), GCC 4.3.0 relies on the ABI
guarantee.  As GCC itself never issues std insn, it is just inline or
out-of-line assembly which has to reset cld after it did std (AFAIK all such
assembly I saw does that), the kernel has to start a process with cleared DF
flag (also done) and
the kernel signal handler needs to clear it for the signal handler (this is the
bug).

</cite>

Comment 10 Joshua Giles 2008-04-28 18:33:10 UTC
Hi Jan,

Can you post the rhel3 committed patch for clarification?  I see some usage of
the DF flag but it's unlike the upstream version.  

Comment 14 Vincent Danen 2010-12-23 16:45:19 UTC
This was addressed via:

Red Hat Enterprise Linux version 3 (RHSA-2008:0211)
Red Hat Enterprise Linux version 5 (RHSA-2008:0233)
Red Hat Enterprise Linux version 4 (RHSA-2008:0508)


Note You need to log in before you can comment on or make changes to this bug.