lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Thu, 11 Jan 2007 02:00:53 +0100 From: Felix von Leitner <felix-fulldisclosure@...e.de> To: full-disclosure@...ts.grok.org.uk Subject: new class of printf issue: int overflow This is about two issues. First: abs within vasprintf. I just read some gnupg source code and stumbled upon their vasprintf implementation. Basically they make one pass over the format string to find out how much memory to malloc, and then they call sprintf on the malloced buffer. Here is an excerpt: if (*p == '*') { ++p; total_width += abs (va_arg (ap, int)); } I noticed this code because it calls abs on an int. A little known fact about abs is that it can return negative values. If the int is 0x80000000, for example, abs() will also return 0x80000000. So, I thought, mhh, if someone can control this value but not the format string, he can cause total_width to be very small but then write lots of stuff to it. Second issue: int overflow in *printf: But that got me thinking. *printf return an int, and it's supposed to be the number of chars written. So a typical idiom is size_t memory_needed=snprintf(NULL,0,format_string,...); char* ptr=malloc(memory_needed+1); sprintf(ptr,format_string,...); What if sprintf returns a negative value? printf can return -1 if write() failed, but sprintf can not traditionally return -1. The single unix specification says this about sprintf: If the value of n is zero on a call to snprintf(), nothing shall be written, the number of bytes that would have been written had n been sufficiently large excluding the terminating null shall be returned, and s may be a null pointer. So my guess is that nobody expects sprintf to return a negative value. Out of curiosity, I wrote this test program: $ cat > t.c #include <stdio.h> int main() { printf("%d\n",snprintf(0,0,"%*d %*d",0x40000000,1,0x40000000,1)); } $ gcc -o t t.c $ ./t -2147483647 ./t 17.02s user 0.03s system 99% cpu 17.161 total $ the second line comes from my zsh, and as you can see running this program took 17 seconds. top shows that the process used 1 gig of memory while it ran. :-) This scenario is pretty far fetched, obviously. In the above code snippet, returning a negative number doesn't hurt, because malloc will interpret it as unsigned really big number. But hey, there could be other scenarios. The question is: do we want to do something about it? What should printf do if it detects an int overflow? Return -1? Is there a good solution to this? Solaris apparently returns -1. Felix PS: Does anyone understand why sprintf does not count the \0 at the end? I think that's pretty brain-dead. _______________________________________________ Full-Disclosure - We believe in it. Charter: http://lists.grok.org.uk/full-disclosure-charter.html Hosted and sponsored by Secunia - http://secunia.com/
Powered by blists - more mailing lists