1 From 6143805bb45e716829d86851e9372f55a136064b Mon Sep 17 00:00:00 2001
2 From: Jeff Law <law@redhat.com>
3 Date: Mon, 15 Dec 2014 10:09:32 +0100
4 Subject: [PATCH 35/37] CVE-2012-3406: Stack overflow in vfprintf [BZ #16617]
6 A larger number of format specifiers coudld cause a stack overflow,
7 potentially allowing to bypass _FORTIFY_SOURCE format string
14 ChangeLog | 13 +++++++++
15 NEWS | 57 ++++++++++++++++++++++++++++++++++++++++
16 stdio-common/Makefile | 2 +-
17 stdio-common/bug23-2.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
18 stdio-common/bug23-3.c | 50 +++++++++++++++++++++++++++++++++++
19 stdio-common/bug23-4.c | 31 ++++++++++++++++++++++
20 stdio-common/vfprintf.c | 40 ++++++++++++++++++++++++++--
21 7 files changed, 260 insertions(+), 3 deletions(-)
22 create mode 100644 stdio-common/bug23-2.c
23 create mode 100644 stdio-common/bug23-3.c
24 create mode 100644 stdio-common/bug23-4.c
26 diff --git a/stdio-common/bug23-2.c b/stdio-common/bug23-2.c
28 index 0000000..9e0cfe6
30 +++ b/stdio-common/bug23-2.c
36 +static const char expected[] = "\
75 +abbcd55%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
80 + char *buf = malloc (strlen (expected) + 1);
81 + snprintf (buf, strlen (expected) + 1,
82 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
83 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
84 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
85 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
86 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
87 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
88 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
89 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
90 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
91 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
92 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
93 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
94 + "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
95 + "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
96 + "a", "b", "c", "d", 5);
97 + return strcmp (buf, expected) != 0;
100 +#define TEST_FUNCTION do_test ()
101 +#include "../test-skeleton.c"
102 diff --git a/stdio-common/bug23-3.c b/stdio-common/bug23-3.c
104 index 0000000..57c8cef
106 +++ b/stdio-common/bug23-3.c
115 + size_t instances = 16384;
116 +#define X0 "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
117 + const char *item = "\na\nabbcd55";
118 +#define X3 X0 X0 X0 X0 X0 X0 X0 X0
119 +#define X6 X3 X3 X3 X3 X3 X3 X3 X3
120 +#define X9 X6 X6 X6 X6 X6 X6 X6 X6
121 +#define X12 X9 X9 X9 X9 X9 X9 X9 X9
122 +#define X14 X12 X12 X12 X12
123 +#define TRAILER "%%%%%%%%%%%%%%%%%%%%%%%%%%"
124 +#define TRAILER2 TRAILER TRAILER
125 + size_t length = instances * strlen (item) + strlen (TRAILER) + 1;
127 + char *buf = malloc (length + 1);
128 + snprintf (buf, length + 1,
130 + "a", "b", "c", "d", 5);
132 + const char *p = buf;
134 + for (i = 0; i < instances; ++i)
136 + const char *expected;
137 + for (expected = item; *expected; ++expected)
139 + if (*p != *expected)
141 + printf ("mismatch at offset %zu (%zu): expected %d, got %d\n",
142 + (size_t) (p - buf), i, *expected & 0xFF, *p & 0xFF);
148 + if (strcmp (p, TRAILER "\n") != 0)
150 + printf ("mismatch at trailer: [%s]\n", p);
156 +#define TEST_FUNCTION do_test ()
157 +#include "../test-skeleton.c"
158 diff --git a/stdio-common/bug23-4.c b/stdio-common/bug23-4.c
160 index 0000000..a478564
162 +++ b/stdio-common/bug23-4.c
167 +#include <sys/resource.h>
169 +#define LIMIT 1000000
175 + getrlimit (RLIMIT_STACK, &lim);
176 + lim.rlim_cur = 1048576;
177 + setrlimit (RLIMIT_STACK, &lim);
178 + char *fmtstr = malloc (4 * LIMIT + 1);
179 + if (fmtstr == NULL)
181 + char *output = malloc (LIMIT + 1);
182 + if (output == NULL)
184 + for (size_t i = 0; i < LIMIT; i++)
185 + memcpy (fmtstr + 4 * i, "%1$d", 4);
186 + fmtstr[4 * LIMIT] = '\0';
187 + int ret = snprintf (output, LIMIT + 1, fmtstr, 0);
190 + for (size_t i = 0; i < LIMIT; i++)
191 + if (output[i] != '0')
195 diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
196 index f7e5f61..f423be6 100644
197 --- a/stdio-common/vfprintf.c
198 +++ b/stdio-common/vfprintf.c
199 @@ -263,6 +263,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
200 /* For the argument descriptions, which may be allocated on the heap. */
201 void *args_malloced = NULL;
203 + /* For positional argument handling. */
204 + struct printf_spec *specs;
206 + /* Track if we malloced the SPECS array and thus must free it. */
207 + bool specs_malloced = false;
209 /* This table maps a character into a number representing a
210 class. In each step there is a destination label for each
212 @@ -1678,8 +1684,8 @@ do_positional:
214 /* A more or less arbitrary start value. */
215 size_t nspecs_size = 32 * sizeof (struct printf_spec);
216 - struct printf_spec *specs = alloca (nspecs_size);
218 + specs = alloca (nspecs_size);
219 /* The number of arguments the format string requests. This will
220 determine the size of the array needed to store the argument
222 @@ -1720,11 +1726,39 @@ do_positional:
223 if (nspecs * sizeof (*specs) >= nspecs_size)
225 /* Extend the array of format specifiers. */
226 + if (nspecs_size * 2 < nspecs_size)
228 + __set_errno (ENOMEM);
232 struct printf_spec *old = specs;
233 - specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
234 + if (__libc_use_alloca (2 * nspecs_size))
235 + specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
239 + specs = malloc (nspecs_size);
242 + __set_errno (ENOMEM);
249 /* Copy the old array's elements to the new space. */
250 memmove (specs, old, nspecs * sizeof (*specs));
252 + /* If we had previously malloc'd space for SPECS, then
253 + release it after the copy is complete. */
254 + if (specs_malloced)
257 + /* Now set SPECS_MALLOCED if needed. */
258 + if (!__libc_use_alloca (nspecs_size))
259 + specs_malloced = true;
262 /* Parse the format specifier. */
263 @@ -2045,6 +2079,8 @@ do_positional:
267 + if (specs_malloced)
269 if (__glibc_unlikely (args_malloced != NULL))
270 free (args_malloced);
271 if (__glibc_unlikely (workstart != NULL))