|
Message-Id: <a18696795bb4b91a@frisell.zx2c4.com> Date: Mon, 10 Apr 2017 16:36:24 +0200 From: "Jason A. Donenfeld" <Jason@...c4.com> To: oss-security <oss-security@...ts.openwall.com> Subject: alloca in inline functions can be dangerous Hey folks, I'm not sure this is the right mailing list to discuss this matter, but hopefully it finds an audience here. I was debugging some code recently, when I found a very nasty interaction between alloca and inline functions. Observe the following block: static inline void process_widget(struct widget *widget, unsigned int fcount) { struct fragment fragments[fcount]; widgets_to_fragments(fragments, widget); process_fragments(fragments); } static void iterate_widgets(struct widgetlist *widgetlist) { struct widget *widget; unsigned int fcount; for (widget = widgetlist->first; widget; widget = widget->next) { fcount = widget_get_frags_required(widget); if (fcount > 256) continue; process_widget(widget, fcount); } } This seems pretty benign. However, let's look at two transformations that gcc makes. First the VLA is changed to use alloca: static inline void process_widget(struct widget *widget, unsigned int fcount) { struct fragment *fragments = __builtin_alloca(fcount); widgets_to_fragments(fragments, widget); } Next, that block is inlined: static void iterate_widgets(struct widgetlist *widgetlist) { struct fragment *fragments; struct widget *widget; unsigned int fcount; for (widget = widgetlist->first; widget; widget = widget->next) { fcount = widget_get_frags_required(widget); if (fcount > 256) continue; fragments = __builtin_alloca(fcount); widgets_to_fragments(fragments, widget); process_fragments(fragments); } } Uh oh speghettio: now the vulnerability becomes clear. Alloca only gives back its stack at the end of the function, not the end of the block. Since process_widget was inlined, we now keep calling alloca for every widget in the widgetlist. Problemo! A stack overflow is imminant, depending on the size of widgetlist. I briefly searched for some information about this type of vulnerability on the internet, and couldn't find anything. At best, I found somebody on a gcc list saying that gcc wouldn't inline functions that use alloca. But now I see that this is clearly not true. So now the standard advice of "don't use VLAs or alloca in loops!" now extends to "don't use VLAs or alloca in loops or inline functions that might be called inside loops." It seems like it would be prudent for gcc to either issue a warning when alloca is used in an inline function called from inside a loop, or simply refuse to inline those function calls (similar to what it does if you ever try to take the address of an inline function). I'm interested if anybody else has encountered this behavior or has any thoughts about it. Thanks, Jason
Powered by blists - more mailing lists
Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.