Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20140322183518.GA3735@brightrain.aerifal.cx>
Date: Sat, 22 Mar 2014 14:35:18 -0400
From: Rich Felker <dalias@...ifal.cx>
To: musl@...ts.openwall.com
Subject: Stack-based buffer overflow in musl libc versions 0.9.15 and earlier

An off-by-one error in the size of a buffer used by musl's
implementation of the printf-family functions for converting floating
point number to decimal leads to a buffer overflow when printing the
extremely small floating point values with extremely high precision.

In order to trigger the overflow, a value which is denormal when
represented as long double has to be printed to exact or near-exact
precision. On i386 and x86_64 targets where long double is 80-bit
extended precision, this means the precision must be more than 16381
places past the decimal point and the value printed must be below
2^-16381 to trigger the overflow. The overflow is impossible to
trigger on these targets with values of type double. On other targets
where long double has the same size and representation as double,
values below 2^-1021 with 1021 or more places past the decimal point
may trigger the overflow.

In testing, I was unable to cause the overflow, which only writes one
slot past the end of an array of 32-bit integers, to overwrite any
sensitive data such as return addresses. In fact, testing has always
shown that musl prints the smallest denormals correctly, which is why
this bug was not caught earlier. However, since the layout of objects
on the stack depends on the particular compiler used, it is possible
that some compilers may arrange the stack such that the overflow does
clobber the return address or a pointer through which the results are
later written, possibly leading to arbitrary code execution.

This issue was reported by Ryan Juckett (http://www.ryanjuckett.com)
who found it while comparing and evaluating different floating point
to decimal implementations.

The following commit fixes the issue and should apply cleanly to any
recent version of musl.

-------------------------------------------------------------------------------
commit ba231cf9e5923b6216081e9a626465c6643ce4d3
Author: Rich Felker <dalias@...ifal.cx>
Date:   Sun Mar 9 01:38:52 2014 -0500

    fix buffer overflow in printf formatting of denormals with low bit set
    
    empirically the overflow was an off-by-one, and it did not seem to be
    overwriting meaningful data. rather than simply increasing the buffer
    size by one, however, I have attempted to make the size obviously
    correct in terms of bounds on the number of iterations for the loops
    that fill the buffer. this still results in no more than a negligible
    size increase of the buffer on the stack (6-7 32-bit slots) and is a
    "safer" fix unless/until somebody wants to do the proof that a smaller
    buffer would suffice.

diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
index b5948bd..8570172 100644
--- a/src/stdio/vfprintf.c
+++ b/src/stdio/vfprintf.c
@@ -207,7 +207,8 @@ typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)
 
 static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
 {
-	uint32_t big[(LDBL_MAX_EXP+LDBL_MANT_DIG)/9+1];
+	uint32_t big[(LDBL_MANT_DIG+28)/29 + 1          // mantissa expansion
+		+ (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
 	uint32_t *a, *d, *r, *z;
 	int e2=0, e, i, j, l;
 	char buf[9+LDBL_MANT_DIG/4], *s;

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.