1 2012-03-02 Kees Cook <keescook@chromium.org>
4 * stdio-common/vfprintf.c (vfprintf): Check for nargs overflow and
5 possibly allocate from heap instead of stack.
7 --- a/stdio-common/vfprintf.c
8 +++ b/stdio-common/vfprintf.c
9 @@ -235,6 +235,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
11 int readonly_format = 0;
13 + /* For the argument descriptions, which may be allocated on the heap. */
14 + void *args_malloced = NULL;
16 /* This table maps a character into a number representing a
17 class. In each step there is a destination label for each
19 @@ -1647,9 +1650,10 @@ do_positional:
20 determine the size of the array needed to store the argument
24 - union printf_arg *args_value = NULL;
25 + size_t bytes_per_arg;
26 + union printf_arg *args_value;
30 /* Positional parameters refer to arguments directly. This could
31 also determine the maximum number of arguments. Track the
32 @@ -1698,13 +1702,38 @@ do_positional:
34 /* Determine the number of arguments the format string consumes. */
35 nargs = MAX (nargs, max_ref_arg);
36 + /* Calculate total size needed to represent a single argument across
37 + all three argument-related arrays. */
38 + bytes_per_arg = sizeof (*args_value) + sizeof (*args_size)
39 + + sizeof (*args_type);
41 + /* Check for potential integer overflow. */
42 + if (__builtin_expect (nargs > SIZE_MAX / bytes_per_arg, 0))
44 + __set_errno (ERANGE);
49 - /* Allocate memory for the argument descriptions. */
50 - args_type = alloca (nargs * sizeof (int));
51 + /* Allocate memory for all three argument arrays. */
52 + if (__libc_use_alloca (nargs * bytes_per_arg))
53 + args_value = alloca (nargs * bytes_per_arg);
56 + args_value = args_malloced = malloc (nargs * bytes_per_arg);
57 + if (args_value == NULL)
64 + /* Set up the remaining two arrays to each point past the end of the
65 + prior array, since space for all three has been allocated now. */
66 + args_size = &args_value[nargs].pa_int;
67 + args_type = &args_size[nargs];
68 memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
69 - nargs * sizeof (int));
70 - args_value = alloca (nargs * sizeof (union printf_arg));
71 - args_size = alloca (nargs * sizeof (int));
72 + nargs * sizeof (*args_type));
74 /* XXX Could do sanity check here: If any element in ARGS_TYPE is
75 still zero after this loop, format is invalid. For now we
76 @@ -1973,8 +2002,8 @@ do_positional:
80 - if (__builtin_expect (workstart != NULL, 0))
82 + free (args_malloced);
84 /* Unlock the stream. */
86 _IO_cleanup_region_end (0);