oss-sec mailing list archives
alloca in inline functions can be dangerous
From: "Jason A. Donenfeld" <Jason () zx2c4 com>
Date: Mon, 10 Apr 2017 16:36:24 +0200
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
Current thread:
- alloca in inline functions can be dangerous Jason A. Donenfeld (Apr 10)
- Re: alloca in inline functions can be dangerous Leandro Pereira (Apr 10)
- Re: alloca in inline functions can be dangerous Andreas Lausch-Waas (Apr 15)
- Re: alloca in inline functions can be dangerous Florian Weimer (Apr 14)
- Re: alloca in inline functions can be dangerous Leandro Pereira (Apr 10)