blow the stack with arbitrarily-extendible VLAs

Jim Meyering jim@meyering.net
Sat May 5 20:28:00 GMT 2007


After seeing the recently-fixed user-extendible VLA in vfprintf.c,
I wondered if there were others.

Here's the result of a quick survey:

------------------------
from lio_listio.c:
Calling lio_listio with NENT too large blows the stack:

    lio_listio_internal (int mode, struct aiocb *const list[], int nent,
			 struct sigevent *sig)
    {
      struct sigevent defsigev;
      struct requestlist *requests[nent];
      ...
      struct waitlist waitlist[nent];

Here's sample code:

#include <aio.h>
#include <stdlib.h>
int
main (int argc, char **argv)
{
  return lio_listio (0, NULL, atoi(argv[1]), NULL);
}

Of course, with all the 0 arguments, it'll segfault for most positive
arguments, but if you give it a value larger than about 8MB (and smaller
than INT_MAX), it'll trigger the bug:

  $ gcc -Wall -O k.c -lrt && ./a.out 9999999
  zsh: segmentation fault  ./a.out 9999999
  [Exit 139 (SEGV)]

E.g., valgrind reports this:
...
==13681== Warning: client switching stacks?  SP change: 0x7FF000050 --> 0x7FA3B4C40
==13681==          to suppress, use: --max-stackframe=80000016 or greater
==13681== Invalid write of size 8
==13681==    at 0x4B2667B: lio_listio_internal (lio_listio.c:76)
==13681==  Address 0x7FA3B4C38 is on thread 1's stack

============================================================================
sysdeps/mach/hurd/poll.c(__poll) calls _hurd_select with "nfds",
which is the 2nd param to poll.  If it's too big, that blows
the stack (from hurd/hurdselect.c):
[ hurd/hurdselect.c does the same thing ]

  struct
    {
      struct hurd_userlink ulink;
      struct hurd_fd *cell;
      mach_port_t io_port;
      int type;
      mach_port_t reply_port;
    } d[nfds];

============================================================================
Similarly, for getaddrinfo_a's 3rd parameter:

    int
    getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig)
    {
      struct sigevent defsigev;
      struct requestlist *requests[ent];


============================================================================
Blow the stack by printing in fwide mode using a format string longer than
fits on the stack:

    int
    __fxprintf (FILE *fp, const char *fmt, ...)
    {
      if (fp == NULL)
	fp = stderr;

      va_list ap;
      va_start (ap, fmt);

      int res;
      if (_IO_fwide (fp, 0) > 0)
	{
	  size_t len = strlen (fmt) + 1;
	  wchar_t wfmt[len];



More information about the Libc-alpha mailing list