blob: e30307fbc02e40a6385fabb366551b91259b3278 [file] [log] [blame]
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001From 8f5e8b01a1da2a207228f2072c934fa5918554b8 Mon Sep 17 00:00:00 2001
2From: Joseph Myers <joseph@codesourcery.com>
3Date: Fri, 4 Dec 2015 20:36:28 +0000
4Subject: [PATCH] Fix nan functions handling of payload strings (bug 16961, bug
5 16962).
6
7The nan, nanf and nanl functions handle payload strings by doing e.g.:
8
9 if (tagp[0] != '\0')
10 {
11 char buf[6 + strlen (tagp)];
12 sprintf (buf, "NAN(%s)", tagp);
13 return strtod (buf, NULL);
14 }
15
16This is an unbounded stack allocation based on the length of the
17argument. Furthermore, if the argument starts with an n-char-sequence
18followed by ')', that n-char-sequence is wrongly treated as
19significant for determining the payload of the resulting NaN, when ISO
20C says the call should be equivalent to strtod ("NAN", NULL), without
21being affected by that initial n-char-sequence. This patch fixes both
22those problems by using the __strtod_nan etc. functions recently
23factored out of strtod etc. for that purpose, with those functions
24being exported from libc at version GLIBC_PRIVATE.
25
26Tested for x86_64, x86, mips64 and powerpc.
27
28 [BZ #16961]
29 [BZ #16962]
30 * math/s_nan.c (__nan): Use __strtod_nan instead of constructing a
31 string on the stack for strtod.
32 * math/s_nanf.c (__nanf): Use __strtof_nan instead of constructing
33 a string on the stack for strtof.
34 * math/s_nanl.c (__nanl): Use __strtold_nan instead of
35 constructing a string on the stack for strtold.
36 * stdlib/Versions (libc): Add __strtof_nan, __strtod_nan and
37 __strtold_nan to GLIBC_PRIVATE.
38 * math/test-nan-overflow.c: New file.
39 * math/test-nan-payload.c: Likewise.
40 * math/Makefile (tests): Add test-nan-overflow and
41 test-nan-payload.
42
43Upstream-Status: Backport
44CVE: CVE-2015-9761 patch #2
45[Yocto # 8980]
46
47https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=8f5e8b01a1da2a207228f2072c934fa5918554b8
48
49Signed-off-by: Armin Kuster <akuster@mvista.com>
50
51---
52 ChangeLog | 17 +++++++
53 NEWS | 6 +++
54 math/Makefile | 3 +-
55 math/s_nan.c | 9 +---
56 math/s_nanf.c | 9 +---
57 math/s_nanl.c | 9 +---
58 math/test-nan-overflow.c | 66 +++++++++++++++++++++++++
59 math/test-nan-payload.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++
60 stdlib/Versions | 1 +
61 9 files changed, 217 insertions(+), 25 deletions(-)
62 create mode 100644 math/test-nan-overflow.c
63 create mode 100644 math/test-nan-payload.c
64
65Index: git/ChangeLog
66===================================================================
67--- git.orig/ChangeLog
68+++ git/ChangeLog
69@@ -1,3 +1,20 @@
70+2015-12-04 Joseph Myers <joseph@codesourcery.com>
71+
72+ [BZ #16961]
73+ [BZ #16962]
74+ * math/s_nan.c (__nan): Use __strtod_nan instead of constructing a
75+ string on the stack for strtod.
76+ * math/s_nanf.c (__nanf): Use __strtof_nan instead of constructing
77+ a string on the stack for strtof.
78+ * math/s_nanl.c (__nanl): Use __strtold_nan instead of
79+ constructing a string on the stack for strtold.
80+ * stdlib/Versions (libc): Add __strtof_nan, __strtod_nan and
81+ __strtold_nan to GLIBC_PRIVATE.
82+ * math/test-nan-overflow.c: New file.
83+ * math/test-nan-payload.c: Likewise.
84+ * math/Makefile (tests): Add test-nan-overflow and
85+ test-nan-payload.
86+
87 2015-11-24 Joseph Myers <joseph@codesourcery.com>
88
89 * stdlib/strtod_nan.c: New file.
90Index: git/NEWS
91===================================================================
92--- git.orig/NEWS
93+++ git/NEWS
94@@ -99,6 +99,12 @@ Version 2.22
95
96 Version 2.21
97
98+Security related changes:
99+
100+* The nan, nanf and nanl functions no longer have unbounded stack usage
101+ depending on the length of the string passed as an argument to the
102+ functions. Reported by Joseph Myers.
103+
104 * The following bugs are resolved with this release:
105
106 6652, 10672, 12674, 12847, 12926, 13862, 14132, 14138, 14171, 14498,
107Index: git/math/Makefile
108===================================================================
109--- git.orig/math/Makefile
110+++ git/math/Makefile
111@@ -110,6 +110,7 @@ tests = test-matherr test-fenv atest-exp
112 test-tgmath-ret bug-nextafter bug-nexttoward bug-tgmath1 \
113 test-tgmath-int test-tgmath2 test-powl tst-CMPLX tst-CMPLX2 test-snan \
114 test-fenv-tls test-fenv-preserve test-fenv-return test-fenvinline \
115+ test-nan-overflow test-nan-payload \
116 $(tests-static)
117 tests-static = test-fpucw-static test-fpucw-ieee-static
118 # We do the `long double' tests only if this data type is available and
119Index: git/math/s_nan.c
120===================================================================
121--- git.orig/math/s_nan.c
122+++ git/math/s_nan.c
123@@ -28,14 +28,7 @@
124 double
125 __nan (const char *tagp)
126 {
127- if (tagp[0] != '\0')
128- {
129- char buf[6 + strlen (tagp)];
130- sprintf (buf, "NAN(%s)", tagp);
131- return strtod (buf, NULL);
132- }
133-
134- return NAN;
135+ return __strtod_nan (tagp, NULL, 0);
136 }
137 weak_alias (__nan, nan)
138 #ifdef NO_LONG_DOUBLE
139Index: git/math/s_nanf.c
140===================================================================
141--- git.orig/math/s_nanf.c
142+++ git/math/s_nanf.c
143@@ -28,13 +28,6 @@
144 float
145 __nanf (const char *tagp)
146 {
147- if (tagp[0] != '\0')
148- {
149- char buf[6 + strlen (tagp)];
150- sprintf (buf, "NAN(%s)", tagp);
151- return strtof (buf, NULL);
152- }
153-
154- return NAN;
155+ return __strtof_nan (tagp, NULL, 0);
156 }
157 weak_alias (__nanf, nanf)
158Index: git/math/s_nanl.c
159===================================================================
160--- git.orig/math/s_nanl.c
161+++ git/math/s_nanl.c
162@@ -28,13 +28,6 @@
163 long double
164 __nanl (const char *tagp)
165 {
166- if (tagp[0] != '\0')
167- {
168- char buf[6 + strlen (tagp)];
169- sprintf (buf, "NAN(%s)", tagp);
170- return strtold (buf, NULL);
171- }
172-
173- return NAN;
174+ return __strtold_nan (tagp, NULL, 0);
175 }
176 weak_alias (__nanl, nanl)
177Index: git/math/test-nan-overflow.c
178===================================================================
179--- /dev/null
180+++ git/math/test-nan-overflow.c
181@@ -0,0 +1,66 @@
182+/* Test nan functions stack overflow (bug 16962).
183+ Copyright (C) 2015 Free Software Foundation, Inc.
184+ This file is part of the GNU C Library.
185+
186+ The GNU C Library is free software; you can redistribute it and/or
187+ modify it under the terms of the GNU Lesser General Public
188+ License as published by the Free Software Foundation; either
189+ version 2.1 of the License, or (at your option) any later version.
190+
191+ The GNU C Library is distributed in the hope that it will be useful,
192+ but WITHOUT ANY WARRANTY; without even the implied warranty of
193+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
194+ Lesser General Public License for more details.
195+
196+ You should have received a copy of the GNU Lesser General Public
197+ License along with the GNU C Library; if not, see
198+ <http://www.gnu.org/licenses/>. */
199+
200+#include <math.h>
201+#include <stdio.h>
202+#include <string.h>
203+#include <sys/resource.h>
204+
205+#define STACK_LIM 1048576
206+#define STRING_SIZE (2 * STACK_LIM)
207+
208+static int
209+do_test (void)
210+{
211+ int result = 0;
212+ struct rlimit lim;
213+ getrlimit (RLIMIT_STACK, &lim);
214+ lim.rlim_cur = STACK_LIM;
215+ setrlimit (RLIMIT_STACK, &lim);
216+ char *nanstr = malloc (STRING_SIZE);
217+ if (nanstr == NULL)
218+ {
219+ puts ("malloc failed, cannot test");
220+ return 77;
221+ }
222+ memset (nanstr, '0', STRING_SIZE - 1);
223+ nanstr[STRING_SIZE - 1] = 0;
224+#define NAN_TEST(TYPE, FUNC) \
225+ do \
226+ { \
227+ char *volatile p = nanstr; \
228+ volatile TYPE v = FUNC (p); \
229+ if (isnan (v)) \
230+ puts ("PASS: " #FUNC); \
231+ else \
232+ { \
233+ puts ("FAIL: " #FUNC); \
234+ result = 1; \
235+ } \
236+ } \
237+ while (0)
238+ NAN_TEST (float, nanf);
239+ NAN_TEST (double, nan);
240+#ifndef NO_LONG_DOUBLE
241+ NAN_TEST (long double, nanl);
242+#endif
243+ return result;
244+}
245+
246+#define TEST_FUNCTION do_test ()
247+#include "../test-skeleton.c"
248Index: git/math/test-nan-payload.c
249===================================================================
250--- /dev/null
251+++ git/math/test-nan-payload.c
252@@ -0,0 +1,122 @@
253+/* Test nan functions payload handling (bug 16961).
254+ Copyright (C) 2015 Free Software Foundation, Inc.
255+ This file is part of the GNU C Library.
256+
257+ The GNU C Library is free software; you can redistribute it and/or
258+ modify it under the terms of the GNU Lesser General Public
259+ License as published by the Free Software Foundation; either
260+ version 2.1 of the License, or (at your option) any later version.
261+
262+ The GNU C Library is distributed in the hope that it will be useful,
263+ but WITHOUT ANY WARRANTY; without even the implied warranty of
264+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
265+ Lesser General Public License for more details.
266+
267+ You should have received a copy of the GNU Lesser General Public
268+ License along with the GNU C Library; if not, see
269+ <http://www.gnu.org/licenses/>. */
270+
271+#include <float.h>
272+#include <math.h>
273+#include <stdio.h>
274+#include <stdlib.h>
275+#include <string.h>
276+
277+/* Avoid built-in functions. */
278+#define WRAP_NAN(FUNC, STR) \
279+ ({ const char *volatile wns = (STR); FUNC (wns); })
280+#define WRAP_STRTO(FUNC, STR) \
281+ ({ const char *volatile wss = (STR); FUNC (wss, NULL); })
282+
283+#define CHECK_IS_NAN(TYPE, A) \
284+ do \
285+ { \
286+ if (isnan (A)) \
287+ puts ("PASS: " #TYPE " " #A); \
288+ else \
289+ { \
290+ puts ("FAIL: " #TYPE " " #A); \
291+ result = 1; \
292+ } \
293+ } \
294+ while (0)
295+
296+#define CHECK_SAME_NAN(TYPE, A, B) \
297+ do \
298+ { \
299+ if (memcmp (&(A), &(B), sizeof (A)) == 0) \
300+ puts ("PASS: " #TYPE " " #A " = " #B); \
301+ else \
302+ { \
303+ puts ("FAIL: " #TYPE " " #A " = " #B); \
304+ result = 1; \
305+ } \
306+ } \
307+ while (0)
308+
309+#define CHECK_DIFF_NAN(TYPE, A, B) \
310+ do \
311+ { \
312+ if (memcmp (&(A), &(B), sizeof (A)) != 0) \
313+ puts ("PASS: " #TYPE " " #A " != " #B); \
314+ else \
315+ { \
316+ puts ("FAIL: " #TYPE " " #A " != " #B); \
317+ result = 1; \
318+ } \
319+ } \
320+ while (0)
321+
322+/* Cannot test payloads by memcmp for formats where NaNs have padding
323+ bits. */
324+#define CAN_TEST_EQ(MANT_DIG) ((MANT_DIG) != 64 && (MANT_DIG) != 106)
325+
326+#define RUN_TESTS(TYPE, SFUNC, FUNC, MANT_DIG) \
327+ do \
328+ { \
329+ TYPE n123 = WRAP_NAN (FUNC, "123"); \
330+ CHECK_IS_NAN (TYPE, n123); \
331+ TYPE s123 = WRAP_STRTO (SFUNC, "NAN(123)"); \
332+ CHECK_IS_NAN (TYPE, s123); \
333+ TYPE n456 = WRAP_NAN (FUNC, "456"); \
334+ CHECK_IS_NAN (TYPE, n456); \
335+ TYPE s456 = WRAP_STRTO (SFUNC, "NAN(456)"); \
336+ CHECK_IS_NAN (TYPE, s456); \
337+ TYPE n123x = WRAP_NAN (FUNC, "123)"); \
338+ CHECK_IS_NAN (TYPE, n123x); \
339+ TYPE nemp = WRAP_NAN (FUNC, ""); \
340+ CHECK_IS_NAN (TYPE, nemp); \
341+ TYPE semp = WRAP_STRTO (SFUNC, "NAN()"); \
342+ CHECK_IS_NAN (TYPE, semp); \
343+ TYPE sx = WRAP_STRTO (SFUNC, "NAN"); \
344+ CHECK_IS_NAN (TYPE, sx); \
345+ if (CAN_TEST_EQ (MANT_DIG)) \
346+ CHECK_SAME_NAN (TYPE, n123, s123); \
347+ if (CAN_TEST_EQ (MANT_DIG)) \
348+ CHECK_SAME_NAN (TYPE, n456, s456); \
349+ if (CAN_TEST_EQ (MANT_DIG)) \
350+ CHECK_SAME_NAN (TYPE, nemp, semp); \
351+ if (CAN_TEST_EQ (MANT_DIG)) \
352+ CHECK_SAME_NAN (TYPE, n123x, sx); \
353+ CHECK_DIFF_NAN (TYPE, n123, n456); \
354+ CHECK_DIFF_NAN (TYPE, n123, nemp); \
355+ CHECK_DIFF_NAN (TYPE, n123, n123x); \
356+ CHECK_DIFF_NAN (TYPE, n456, nemp); \
357+ CHECK_DIFF_NAN (TYPE, n456, n123x); \
358+ } \
359+ while (0)
360+
361+static int
362+do_test (void)
363+{
364+ int result = 0;
365+ RUN_TESTS (float, strtof, nanf, FLT_MANT_DIG);
366+ RUN_TESTS (double, strtod, nan, DBL_MANT_DIG);
367+#ifndef NO_LONG_DOUBLE
368+ RUN_TESTS (long double, strtold, nanl, LDBL_MANT_DIG);
369+#endif
370+ return result;
371+}
372+
373+#define TEST_FUNCTION do_test ()
374+#include "../test-skeleton.c"
375Index: git/stdlib/Versions
376===================================================================
377--- git.orig/stdlib/Versions
378+++ git/stdlib/Versions
379@@ -118,5 +118,6 @@ libc {
380 # Used from other libraries
381 __libc_secure_getenv;
382 __call_tls_dtors;
383+ __strtof_nan; __strtod_nan; __strtold_nan;
384 }
385 }