Affected Software (tested 27.08.2009): - Fedora 11 - Slackware 12.2 - Ubuntu 9.04 - others linux distributions Previous URL: http://securityreason.com/achievement_securityalert/53 --- 0.Description --- strfmon -- convert monetary value to string The strfmon() function places characters into the array pointed to by s as controlled by the string pointed to by format. No more than maxsize bytes are placed into the array. The format string is composed of zero or more directives: ordinary characters (not %), which are copied unchanged to the output stream; and conversion specifications, each of which results in fetching zero or more subsequent arguments. Each conversion specification is introduced by the % character. SYNOPSIS: #include <monetary.h> ssize_t strfmon(char * restrict s, size_t maxsize, const char * restrict format, ...); --- 1. glibc 2.10.1 stdio/strfmon.c Multiple vulnerabilities --- In March 2008, our team has published a security note (SREASONRES:20080325) about vulnerabilities in strfmon(3) function. Issue has been officially diagnosed in NetBSD, FreeBSD and MacOSX. However, from the source code due to a glibc also is vulnerable to. We have informed glibc team. However, the description of the issue and fix was not enough for gnu team. They has changed status for BOGUS and response was: --- And what exactly does an BSD implementation has to do with glibc? --- Today we now, only NetBSD is secure for this. And all systems uses glibc are affected. Despite the differences in the code NetBSD libc and glibc, issue is the same but the exploit differs from that presented in (SREASONRES:20080325). Description of the vulnerabalitie: http://securityreason.com/achievement_securityalert/53 (SREASONRES:20080325) http://xorl.wordpress.com/2009/04/11/cve-2008-1391-netbsd-strfmon-integer-overflow/ Description of the fix: ftp://ftp.netbsd.org/pub/NetBSD/security/advisories/NetBSD-SA2008-006.txt.asc To present this issue in Fedora 11, we will use php client. money_format() use strfmon(3) function so this program will be perfect. [cx@localhost ~]$ php -r 'money_format("%.1073741821i",1);' Segmentation fault for 'money_format("%.1073741821i",1);' we will get Program received signal SIGSEGV, Segmentation fault. 0x0019331a in __printf_fp () from /lib/libc.so.6 (gdb) bt #0 0x0019331a in __printf_fp () from /lib/libc.so.6 #1 0x0018832b in __vstrfmon_l () from /lib/libc.so.6 #2 0x00187a36 in strfmon () from /lib/libc.so.6 strfmon() will call to __printf_fp() with overflowed arg. In result (gdb) x/20s ($esi)-10 0x8448ff6: "" 0x8448ff7: "" 0x8448ff8: "0" 0x8448ffa: "" 0x8448ffb: "" 0x8448ffc: "0" 0x8448ffe: "" 0x8448fff: "" 0x8449000: <Address 0x8449000 out of bounds> 0x8449000: <Address 0x8449000 out of bounds> 0x8449000: <Address 0x8449000 out of bounds> ... (gdb) i r eax 0x30 48 ecx 0x0 0 edx 0x0 0 ebx 0x2bdff4 2875380 esp 0xbfffec14 0xbfffec14 ebp 0xbfffed78 0xbfffed78 esi 0x8449000 138711040 edi 0x810c 33036 eip 0x19331a 0x19331a <__printf_fp+3274> Now let's see what will hapen for 'money_format("%.1073741822i",1);' Program received signal SIGSEGV, Segmentation fault. 0x0034b27b in hack_digit.12295 () from /lib/libc.so.6 php will crash in hack_digit(). (gdb) i r eax 0x3ffffffe 1073741822 ecx 0x32 50 edx 0x2 2 ebx 0x476ff4 4681716 esp 0xbfffebc4 0xbfffebc4 ebp 0xbfffebf4 0xbfffebf4 esi 0x32 50 edi 0x3e 62 we can try change edi register. For 'money_format("%.1073741824i",1);' (gdb) i r eax 0x40000000 1073741824 ecx 0x32 50 edx 0x2 2 ebx 0x35bff4 3522548 esp 0xbfffebbc 0xbfffebbc ebp 0xbfffebec 0xbfffebec esi 0x32 50 edi 0x42 66 But let's see what will hapen for 'money_format("%.77715949976712904702i", 1.1);' crash in Program received signal SIGSEGV, Segmentation fault. 0x00e4327b in hack_digit.12295 () from /lib/libc.so.6 (gdb) i r eax 0x3ffffffe 1073741822 ecx 0x34 52 edx 0x2 2 ebx 0xf6eff4 16183284 esp 0xbfffebb4 0xbfffebb4 ebp 0xbfffebe4 0xbfffebe4 esi 0x34 52 edi 0x3e 62 esi 52. Interesting is that the PHP memory_limit has no control over what happens in the level of the libc. Function strfmon(3) can allocate a lot of data in memory without control by PHP memory_limit and will crash. For example: php -r 'money_format("%.1343741821i",1);' will allocate ~1049MB real memory. memory_limit can be less that 1049M Strange is the fact that nobody checked the code of glibc. The algorithm used in BSD libc and glibc is very similar. Funy.
(In reply to comment #0) > Affected Software (tested 27.08.2009): > - Fedora 11 > - Slackware 12.2 > - Ubuntu 9.04 > - others linux distributions Look like you should be listing architectures here too, as they do seem to matter here. > --- > And what exactly does an BSD implementation has to do with glibc? > --- That sounds like a reference to: http://sourceware.org/bugzilla/show_bug.cgi?id=9707 Further on, I'll be quoting this advisory: http://securityreason.com/achievement_securityalert/67 > Let's see libc/stdlib/strfmon_l.c (glibc rev-1.5.2.4) ... > if (width > LONG_MAX / 10 > || (width == LONG_MAX && val > LONG_MAX % 10)) > { > __set_errno (E2BIG); > return -1; > } ... > if (width >= maxsize - (dest - s)) > { > __set_errno (E2BIG); > return -1; > } .. > Perfect. The above code protects us. For the posterity and completeness of references, integer overflow check was added via following commit: http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=153aa31b93be22e01b236375fb02a9f9b9a0195f This sounds like a reason why your original vector %99999999999999999999n does not work any more. > But what is below, is a mistake already This seems to refer to missing integer overflows checks in the code converting left_prec / right_prec from string to number, as similar approach is used there as for converting width: http://sourceware.org/git/?p=glibc.git;a=blob;f=stdlib/strfmon_l.c#l242 http://sourceware.org/git/?p=glibc.git;a=blob;f=stdlib/strfmon_l.c#l259 But wait, how does that explain a crash on "%.1073741821i"? 1073741821 is less than 2^31, so it won't overflow (signed) integer on either 32 bit or 64 bit architectures, right? > info.width = left_prec + (right_prec ? (right_prec + 1) : 0); This should not overflow either, as left_prec is 0 here. So the problem seems to be elsewhere... So let's ignore srtfmon for a while and try something more simple: printf("%.1073741821f\n", 0.0); Testing this on F11 glibc-2.10.1, this crashes when compiled with -m32, but does not with -m64. Little more looking leads to: http://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/printf_fp.c#l890 This is where integer overflow occurs (when computing wbuffer_to_alloc). It should also explain where do ~1gig memory usage come from with your "%.1343741821i" test. Ulrich, I bet your knowledge of this code is a lot better than reporter's and mine combined, so you can come up with proper fix. I just hope this additional info does help. Is it enough for NEW -> ASSIGNED state change.
http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=199eb0de8d
Only 32-bit had a problem and it's fixed.
*** Bug 260998 has been marked as a duplicate of this bug. *** Seen from the domain http://volichat.com Page where seen: http://volichat.com/adult-chat-rooms Marked for reference. Resolved as fixed @bugzilla.
*** Bug 9707 has been marked as a duplicate of this bug. ***