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
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
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