Message ID | 20230517212847.1821277-1-josimmon@redhat.com |
---|---|
State | New |
Headers | show |
Series | vfprintf-internal: Get rid of alloca. | expand |
On 5/17/23 17:28, Joe Simmons-Talbott via Libc-alpha wrote: > Avoid potential stack overflow from unbounded alloca. Use the existing > scratch_buffer instead. Fails 32-bit i686 CI: https://patchwork.sourceware.org/project/glibc/patch/20230517212847.1821277-1-josimmon@redhat.com/ Please have a look. > --- > stdio-common/vfprintf-internal.c | 22 +++++++++++++++++++++- > 1 file changed, 21 insertions(+), 1 deletion(-) > > diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c > index c76c06e49b..baaefb763a 100644 > --- a/stdio-common/vfprintf-internal.c > +++ b/stdio-common/vfprintf-internal.c > @@ -1066,6 +1066,8 @@ printf_positional (struct Xprintf_buffer * buf, const CHAR_T *format, > union printf_arg *args_value; > int *args_size; > int *args_type; > + int *args_pa_user; > + size_t args_pa_user_offset; > { > /* Calculate total size needed to represent a single argument > across all three argument-related arrays. */ > @@ -1082,6 +1084,7 @@ printf_positional (struct Xprintf_buffer * buf, const CHAR_T *format, > now. */ > args_size = &args_value[nargs].pa_int; > args_type = &args_size[nargs]; > + args_pa_user = &args_type[nargs]; > memset (args_type, (mode_flags & PRINTF_FORTIFY) != 0 ? '\xff' : '\0', > nargs * sizeof (*args_type)); > } > @@ -1171,7 +1174,24 @@ printf_positional (struct Xprintf_buffer * buf, const CHAR_T *format, > else if (__glibc_unlikely (__printf_va_arg_table != NULL) > && __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL) > { > - args_value[cnt].pa_user = alloca (args_size[cnt]); > + if (args_pa_user > argsbuf + args_size) > + { > + args_pa_user_offset = args_pa_user - &args_type[nargs]; > + if (!scratch_buffer_grow_preserve (&argsbuf)) > + { > + Xprintf_buffer_mark_failed (buf); > + goto all_done; > + } > + args_value = argsbuf.data; > + /* Set up the remaining two arrays to each point past the end of > + the prior array, since space for all three has been allocated > + now. */ > + args_size = &args_value[nargs].pa_int; > + args_type = &args_size[nargs]; > + args_pa_user = &args_type[nargs] + args_pa_user_offset; > + } > + args_value[cnt].pa_user = args_pa_user; > + args_pa_user += args_size[cnt]; > (*__printf_va_arg_table[args_type[cnt] - PA_LAST]) > (args_value[cnt].pa_user, ap_savep); > }
diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c index c76c06e49b..baaefb763a 100644 --- a/stdio-common/vfprintf-internal.c +++ b/stdio-common/vfprintf-internal.c @@ -1066,6 +1066,8 @@ printf_positional (struct Xprintf_buffer * buf, const CHAR_T *format, union printf_arg *args_value; int *args_size; int *args_type; + int *args_pa_user; + size_t args_pa_user_offset; { /* Calculate total size needed to represent a single argument across all three argument-related arrays. */ @@ -1082,6 +1084,7 @@ printf_positional (struct Xprintf_buffer * buf, const CHAR_T *format, now. */ args_size = &args_value[nargs].pa_int; args_type = &args_size[nargs]; + args_pa_user = &args_type[nargs]; memset (args_type, (mode_flags & PRINTF_FORTIFY) != 0 ? '\xff' : '\0', nargs * sizeof (*args_type)); } @@ -1171,7 +1174,24 @@ printf_positional (struct Xprintf_buffer * buf, const CHAR_T *format, else if (__glibc_unlikely (__printf_va_arg_table != NULL) && __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL) { - args_value[cnt].pa_user = alloca (args_size[cnt]); + if (args_pa_user > argsbuf + args_size) + { + args_pa_user_offset = args_pa_user - &args_type[nargs]; + if (!scratch_buffer_grow_preserve (&argsbuf)) + { + Xprintf_buffer_mark_failed (buf); + goto all_done; + } + args_value = argsbuf.data; + /* Set up the remaining two arrays to each point past the end of + the prior array, since space for all three has been allocated + now. */ + args_size = &args_value[nargs].pa_int; + args_type = &args_size[nargs]; + args_pa_user = &args_type[nargs] + args_pa_user_offset; + } + args_value[cnt].pa_user = args_pa_user; + args_pa_user += args_size[cnt]; (*__printf_va_arg_table[args_type[cnt] - PA_LAST]) (args_value[cnt].pa_user, ap_savep); }