chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / debian / patches / any / cvs-FORTIFY_SOURCE-format-strings.diff
1 2012-03-02  Kees Cook  <keescook@chromium.org>
2
3         [BZ #13656]
4         * stdio-common/vfprintf.c (vfprintf): Check for nargs overflow and
5         possibly allocate from heap instead of stack.
6
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)
10       0 if unknown.  */
11    int readonly_format = 0;
12  
13 +  /* For the argument descriptions, which may be allocated on the heap.  */
14 +  void *args_malloced = NULL;
15 +
16    /* This table maps a character into a number representing a
17       class.  In each step there is a destination label for each
18       class.  */
19 @@ -1647,9 +1650,10 @@ do_positional:
20         determine the size of the array needed to store the argument
21         attributes.  */
22      size_t nargs = 0;
23 -    int *args_type;
24 -    union printf_arg *args_value = NULL;
25 +    size_t bytes_per_arg;
26 +    union printf_arg *args_value;
27      int *args_size;
28 +    int *args_type;
29  
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:
33  
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);
40 +
41 +    /* Check for potential integer overflow.  */
42 +    if (__builtin_expect (nargs > SIZE_MAX / bytes_per_arg, 0))
43 +      {
44 +         __set_errno (ERANGE);
45 +         done = -1;
46 +         goto all_done;
47 +      }
48  
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);
54 +    else
55 +      {
56 +        args_value = args_malloced = malloc (nargs * bytes_per_arg);
57 +        if (args_value == NULL)
58 +          {
59 +            done = -1;
60 +            goto all_done;
61 +          }
62 +      }
63 +
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));
73  
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:
77    }
78  
79  all_done:
80 -  if (__builtin_expect (workstart != NULL, 0))
81 -    free (workstart);
82 +  free (args_malloced);
83 +  free (workstart);
84    /* Unlock the stream.  */
85    _IO_funlockfile (s);
86    _IO_cleanup_region_end (0);