diff options
Diffstat (limited to 'recipes-core/glibc/glibc/CVE-2018-6551-Fix-integer-overflows-in-internal-memalign-and-malloc-functions.patch')
-rw-r--r-- | recipes-core/glibc/glibc/CVE-2018-6551-Fix-integer-overflows-in-internal-memalign-and-malloc-functions.patch | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/recipes-core/glibc/glibc/CVE-2018-6551-Fix-integer-overflows-in-internal-memalign-and-malloc-functions.patch b/recipes-core/glibc/glibc/CVE-2018-6551-Fix-integer-overflows-in-internal-memalign-and-malloc-functions.patch new file mode 100644 index 0000000..cb766c4 --- /dev/null +++ b/recipes-core/glibc/glibc/CVE-2018-6551-Fix-integer-overflows-in-internal-memalign-and-malloc-functions.patch | |||
@@ -0,0 +1,401 @@ | |||
1 | From 5d7411e9ec03cae8e9bb5df4b515744e5065a64c Mon Sep 17 00:00:00 2001 | ||
2 | From: Andreas Wellving <andreas.wellving@enea.com> | ||
3 | Date: Mon, 22 Oct 2018 13:54:54 +0200 | ||
4 | Subject: [PATCH] Fix integer overflows in internal memalign and malloc [BZ #22343] [BZ #22774] | ||
5 | |||
6 | When posix_memalign is called with an alignment less than MALLOC_ALIGNMENT | ||
7 | and a requested size close to SIZE_MAX, it falls back to malloc code | ||
8 | (because the alignment of a block returned by malloc is sufficient to | ||
9 | satisfy the call). In this case, an integer overflow in _int_malloc leads | ||
10 | to posix_memalign incorrectly returning successfully. | ||
11 | |||
12 | Upon fixing this and writing a somewhat thorough regression test, it was | ||
13 | discovered that when posix_memalign is called with an alignment larger than | ||
14 | MALLOC_ALIGNMENT (so it uses _int_memalign instead) and a requested size | ||
15 | close to SIZE_MAX, a different integer overflow in _int_memalign leads to | ||
16 | posix_memalign incorrectly returning successfully. | ||
17 | |||
18 | Both integer overflows affect other memory allocation functions that use | ||
19 | _int_malloc (one affected malloc in x86) or _int_memalign as well. | ||
20 | |||
21 | This commit fixes both integer overflows. In addition to this, it adds a | ||
22 | regression test to guard against false successful allocations by the | ||
23 | following memory allocation functions when called with too-large allocation | ||
24 | sizes and, where relevant, various valid alignments: | ||
25 | malloc, realloc, calloc, memalign, posix_memalign, aligned_alloc, valloc, | ||
26 | and pvalloc. | ||
27 | |||
28 | (cherry picked from commit 8e448310d74b283c5cd02b9ed7fb997b47bf9b22) | ||
29 | |||
30 | CVE: CVE-2018-6551 | ||
31 | Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=8e448310d74b283c5cd02b9ed7fb997b47bf9b22] | ||
32 | |||
33 | Signed-off-by: Andreas Wellving <andreas.wellving@enea.com> | ||
34 | --- | ||
35 | ChangeLog | 13 +++ | ||
36 | NEWS | 11 ++ | ||
37 | malloc/Makefile | 1 + | ||
38 | malloc/malloc.c | 30 ++++-- | ||
39 | malloc/tst-malloc-too-large.c | 237 ++++++++++++++++++++++++++++++++++++++++++ | ||
40 | 5 files changed, 284 insertions(+), 8 deletions(-) | ||
41 | create mode 100644 malloc/tst-malloc-too-large.c | ||
42 | |||
43 | diff --git a/ChangeLog b/ChangeLog | ||
44 | index ad380fd..48b095b 100644 | ||
45 | --- a/ChangeLog | ||
46 | +++ b/ChangeLog | ||
47 | @@ -1,3 +1,16 @@ | ||
48 | +2018-01-18 Arjun Shankar <arjun@redhat.com> | ||
49 | + | ||
50 | + [BZ #22343] | ||
51 | + [BZ #22774] | ||
52 | + CVE-2018-6485 | ||
53 | + CVE-2018-6551 | ||
54 | + * malloc/malloc.c (checked_request2size): call REQUEST_OUT_OF_RANGE | ||
55 | + after padding. | ||
56 | + (_int_memalign): check for integer overflow before calling | ||
57 | + _int_malloc. | ||
58 | + * malloc/tst-malloc-too-large.c: New test. | ||
59 | + * malloc/Makefile: Add tst-malloc-too-large. | ||
60 | + | ||
61 | 2017-12-30 Aurelien Jarno <aurelien@aurel32.net> | ||
62 | Dmitry V. Levin <ldv@altlinux.org> | ||
63 | |||
64 | diff --git a/NEWS b/NEWS | ||
65 | index 195c06d..5134f34 100644 | ||
66 | --- a/NEWS | ||
67 | +++ b/NEWS | ||
68 | @@ -1,3 +1,4 @@ | ||
69 | + | ||
70 | GNU C Library NEWS -- history of user-visible changes. | ||
71 | Copyright (C) 1992-2017 Free Software Foundation, Inc. | ||
72 | See the end for copying conditions. | ||
73 | @@ -218,6 +219,14 @@ Security related changes: | ||
74 | for AT_SECURE or SUID binaries could be used to load libraries from the | ||
75 | current directory. | ||
76 | |||
77 | + CVE-2018-6485: The posix_memalign and memalign functions, when called with | ||
78 | + an object size near the value of SIZE_MAX, would return a pointer to a | ||
79 | + buffer which is too small, instead of NULL. Reported by Jakub Wilk. | ||
80 | + | ||
81 | + CVE-2018-6551: The malloc function, when called with an object size near | ||
82 | + the value of SIZE_MAX, would return a pointer to a buffer which is too | ||
83 | + small, instead of NULL. | ||
84 | + | ||
85 | The following bugs are resolved with this release: | ||
86 | |||
87 | [4099] stdio: Overly agressive caching by stream i/o functions. | ||
88 | @@ -365,6 +374,8 @@ The following bugs are resolved with this release: | ||
89 | [21073] libc: tunables: insecure environment variables passed to | ||
90 | subprocesses with AT_SECURE | ||
91 | [21081] string: Missing vzeroupper in memset-vec-unaligned-erms.S | ||
92 | + [22343] malloc: Integer overflow in posix_memalign (CVE-2018-6485) | ||
93 | + [22774] malloc: Integer overflow in malloc (CVE-2018-6551) | ||
94 | |||
95 | Version 2.24 | ||
96 | |||
97 | diff --git a/malloc/Makefile b/malloc/Makefile | ||
98 | index e93b83b..ab9e795 100644 | ||
99 | --- a/malloc/Makefile | ||
100 | +++ b/malloc/Makefile | ||
101 | @@ -33,6 +33,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ | ||
102 | tst-mallocfork2 \ | ||
103 | tst-interpose-nothread \ | ||
104 | tst-interpose-thread \ | ||
105 | + tst-malloc-too-large \ | ||
106 | |||
107 | tests-static := \ | ||
108 | tst-interpose-static-nothread \ | ||
109 | diff --git a/malloc/malloc.c b/malloc/malloc.c | ||
110 | index 4885793..a82555d 100644 | ||
111 | --- a/malloc/malloc.c | ||
112 | +++ b/malloc/malloc.c | ||
113 | @@ -1202,14 +1202,21 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
114 | MINSIZE : \ | ||
115 | ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) | ||
116 | |||
117 | -/* Same, except also perform argument check */ | ||
118 | - | ||
119 | -#define checked_request2size(req, sz) \ | ||
120 | - if (REQUEST_OUT_OF_RANGE (req)) { \ | ||
121 | - __set_errno (ENOMEM); \ | ||
122 | - return 0; \ | ||
123 | - } \ | ||
124 | - (sz) = request2size (req); | ||
125 | +/* Same, except also perform an argument and result check. First, we check | ||
126 | + that the padding done by request2size didn't result in an integer | ||
127 | + overflow. Then we check (using REQUEST_OUT_OF_RANGE) that the resulting | ||
128 | + size isn't so large that a later alignment would lead to another integer | ||
129 | + overflow. */ | ||
130 | +#define checked_request2size(req, sz) \ | ||
131 | +({ \ | ||
132 | + (sz) = request2size (req); \ | ||
133 | + if (((sz) < (req)) \ | ||
134 | + || REQUEST_OUT_OF_RANGE (sz)) \ | ||
135 | + { \ | ||
136 | + __set_errno (ENOMEM); \ | ||
137 | + return 0; \ | ||
138 | + } \ | ||
139 | +}) | ||
140 | |||
141 | /* | ||
142 | --------------- Physical chunk operations --------------- | ||
143 | @@ -4423,6 +4430,13 @@ _int_memalign (mstate av, size_t alignment, size_t bytes) | ||
144 | */ | ||
145 | |||
146 | |||
147 | + /* Check for overflow. */ | ||
148 | + if (nb > SIZE_MAX - alignment - MINSIZE) | ||
149 | + { | ||
150 | + __set_errno (ENOMEM); | ||
151 | + return 0; | ||
152 | + } | ||
153 | + | ||
154 | /* Call malloc with worst case padding to hit alignment. */ | ||
155 | |||
156 | m = (char *) (_int_malloc (av, nb + alignment + MINSIZE)); | ||
157 | diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c | ||
158 | new file mode 100644 | ||
159 | index 0000000..1f7bf29 | ||
160 | --- /dev/null | ||
161 | +++ b/malloc/tst-malloc-too-large.c | ||
162 | @@ -0,0 +1,237 @@ | ||
163 | +/* Test and verify that too-large memory allocations fail with ENOMEM. | ||
164 | + Copyright (C) 2018 Free Software Foundation, Inc. | ||
165 | + This file is part of the GNU C Library. | ||
166 | + | ||
167 | + The GNU C Library is free software; you can redistribute it and/or | ||
168 | + modify it under the terms of the GNU Lesser General Public | ||
169 | + License as published by the Free Software Foundation; either | ||
170 | + version 2.1 of the License, or (at your option) any later version. | ||
171 | + | ||
172 | + The GNU C Library is distributed in the hope that it will be useful, | ||
173 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
174 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
175 | + Lesser General Public License for more details. | ||
176 | + | ||
177 | + You should have received a copy of the GNU Lesser General Public | ||
178 | + License along with the GNU C Library; if not, see | ||
179 | + <http://www.gnu.org/licenses/>. */ | ||
180 | + | ||
181 | +/* Bug 22375 reported a regression in malloc where if after malloc'ing then | ||
182 | + free'ing a small block of memory, malloc is then called with a really | ||
183 | + large size argument (close to SIZE_MAX): instead of returning NULL and | ||
184 | + setting errno to ENOMEM, malloc incorrectly returns the previously | ||
185 | + allocated block instead. Bug 22343 reported a similar case where | ||
186 | + posix_memalign incorrectly returns successfully when called with an with | ||
187 | + a really large size argument. | ||
188 | + | ||
189 | + Both of these were caused by integer overflows in the allocator when it | ||
190 | + was trying to pad the requested size to allow for book-keeping or | ||
191 | + alignment. This test guards against such bugs by repeatedly allocating | ||
192 | + and freeing small blocks of memory then trying to allocate various block | ||
193 | + sizes larger than the memory bus width of 64-bit targets, or almost | ||
194 | + as large as SIZE_MAX on 32-bit targets supported by glibc. In each case, | ||
195 | + it verifies that such impossibly large allocations correctly fail. */ | ||
196 | + | ||
197 | + | ||
198 | +#include <stdlib.h> | ||
199 | +#include <malloc.h> | ||
200 | +#include <errno.h> | ||
201 | +#include <stdint.h> | ||
202 | +#include <sys/resource.h> | ||
203 | +#include <libc-internal.h> | ||
204 | +#include <support/check.h> | ||
205 | +#include <unistd.h> | ||
206 | +#include <sys/param.h> | ||
207 | + | ||
208 | + | ||
209 | +/* This function prepares for each 'too-large memory allocation' test by | ||
210 | + performing a small successful malloc/free and resetting errno prior to | ||
211 | + the actual test. */ | ||
212 | +static void | ||
213 | +test_setup (void) | ||
214 | +{ | ||
215 | + void *volatile ptr = malloc (16); | ||
216 | + TEST_VERIFY_EXIT (ptr != NULL); | ||
217 | + free (ptr); | ||
218 | + errno = 0; | ||
219 | +} | ||
220 | + | ||
221 | + | ||
222 | +/* This function tests each of: | ||
223 | + - malloc (SIZE) | ||
224 | + - realloc (PTR_FOR_REALLOC, SIZE) | ||
225 | + - for various values of NMEMB: | ||
226 | + - calloc (NMEMB, SIZE/NMEMB) | ||
227 | + - calloc (SIZE/NMEMB, NMEMB) | ||
228 | + and precedes each of these tests with a small malloc/free before it. */ | ||
229 | +static void | ||
230 | +test_large_allocations (size_t size) | ||
231 | +{ | ||
232 | + void * ptr_to_realloc; | ||
233 | + | ||
234 | + test_setup (); | ||
235 | + TEST_VERIFY (malloc (size) == NULL); | ||
236 | + TEST_VERIFY (errno == ENOMEM); | ||
237 | + | ||
238 | + ptr_to_realloc = malloc (16); | ||
239 | + TEST_VERIFY_EXIT (ptr_to_realloc != NULL); | ||
240 | + test_setup (); | ||
241 | + TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL); | ||
242 | + TEST_VERIFY (errno == ENOMEM); | ||
243 | + free (ptr_to_realloc); | ||
244 | + | ||
245 | + for (size_t nmemb = 1; nmemb <= 8; nmemb *= 2) | ||
246 | + if ((size % nmemb) == 0) | ||
247 | + { | ||
248 | + test_setup (); | ||
249 | + TEST_VERIFY (calloc (nmemb, size / nmemb) == NULL); | ||
250 | + TEST_VERIFY (errno == ENOMEM); | ||
251 | + | ||
252 | + test_setup (); | ||
253 | + TEST_VERIFY (calloc (size / nmemb, nmemb) == NULL); | ||
254 | + TEST_VERIFY (errno == ENOMEM); | ||
255 | + } | ||
256 | + else | ||
257 | + break; | ||
258 | +} | ||
259 | + | ||
260 | + | ||
261 | +static long pagesize; | ||
262 | + | ||
263 | +/* This function tests the following aligned memory allocation functions | ||
264 | + using several valid alignments and precedes each allocation test with a | ||
265 | + small malloc/free before it: | ||
266 | + memalign, posix_memalign, aligned_alloc, valloc, pvalloc. */ | ||
267 | +static void | ||
268 | +test_large_aligned_allocations (size_t size) | ||
269 | +{ | ||
270 | + /* ptr stores the result of posix_memalign but since all those calls | ||
271 | + should fail, posix_memalign should never change ptr. We set it to | ||
272 | + NULL here and later on we check that it remains NULL after each | ||
273 | + posix_memalign call. */ | ||
274 | + void * ptr = NULL; | ||
275 | + | ||
276 | + size_t align; | ||
277 | + | ||
278 | + /* All aligned memory allocation functions expect an alignment that is a | ||
279 | + power of 2. Given this, we test each of them with every valid | ||
280 | + alignment from 1 thru PAGESIZE. */ | ||
281 | + for (align = 1; align <= pagesize; align *= 2) | ||
282 | + { | ||
283 | + test_setup (); | ||
284 | + TEST_VERIFY (memalign (align, size) == NULL); | ||
285 | + TEST_VERIFY (errno == ENOMEM); | ||
286 | + | ||
287 | + /* posix_memalign expects an alignment that is a power of 2 *and* a | ||
288 | + multiple of sizeof (void *). */ | ||
289 | + if ((align % sizeof (void *)) == 0) | ||
290 | + { | ||
291 | + test_setup (); | ||
292 | + TEST_VERIFY (posix_memalign (&ptr, align, size) == ENOMEM); | ||
293 | + TEST_VERIFY (ptr == NULL); | ||
294 | + } | ||
295 | + | ||
296 | + /* aligned_alloc expects a size that is a multiple of alignment. */ | ||
297 | + if ((size % align) == 0) | ||
298 | + { | ||
299 | + test_setup (); | ||
300 | + TEST_VERIFY (aligned_alloc (align, size) == NULL); | ||
301 | + TEST_VERIFY (errno == ENOMEM); | ||
302 | + } | ||
303 | + } | ||
304 | + | ||
305 | + /* Both valloc and pvalloc return page-aligned memory. */ | ||
306 | + | ||
307 | + test_setup (); | ||
308 | + TEST_VERIFY (valloc (size) == NULL); | ||
309 | + TEST_VERIFY (errno == ENOMEM); | ||
310 | + | ||
311 | + test_setup (); | ||
312 | + TEST_VERIFY (pvalloc (size) == NULL); | ||
313 | + TEST_VERIFY (errno == ENOMEM); | ||
314 | +} | ||
315 | + | ||
316 | + | ||
317 | +#define FOURTEEN_ON_BITS ((1UL << 14) - 1) | ||
318 | +#define FIFTY_ON_BITS ((1UL << 50) - 1) | ||
319 | + | ||
320 | + | ||
321 | +static int | ||
322 | +do_test (void) | ||
323 | +{ | ||
324 | + | ||
325 | +#if __WORDSIZE >= 64 | ||
326 | + | ||
327 | + /* This test assumes that none of the supported targets have an address | ||
328 | + bus wider than 50 bits, and that therefore allocations for sizes wider | ||
329 | + than 50 bits will fail. Here, we ensure that the assumption continues | ||
330 | + to be true in the future when we might have address buses wider than 50 | ||
331 | + bits. */ | ||
332 | + | ||
333 | + struct rlimit alloc_size_limit | ||
334 | + = { | ||
335 | + .rlim_cur = FIFTY_ON_BITS, | ||
336 | + .rlim_max = FIFTY_ON_BITS | ||
337 | + }; | ||
338 | + | ||
339 | + setrlimit (RLIMIT_AS, &alloc_size_limit); | ||
340 | + | ||
341 | +#endif /* __WORDSIZE >= 64 */ | ||
342 | + | ||
343 | + DIAG_PUSH_NEEDS_COMMENT; | ||
344 | +#if __GNUC_PREREQ (7, 0) | ||
345 | + /* GCC 7 warns about too-large allocations; here we want to test | ||
346 | + that they fail. */ | ||
347 | + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); | ||
348 | +#endif | ||
349 | + | ||
350 | + /* Aligned memory allocation functions need to be tested up to alignment | ||
351 | + size equivalent to page size, which should be a power of 2. */ | ||
352 | + pagesize = sysconf (_SC_PAGESIZE); | ||
353 | + TEST_VERIFY_EXIT (powerof2 (pagesize)); | ||
354 | + | ||
355 | + /* Loop 1: Ensure that all allocations with SIZE close to SIZE_MAX, i.e. | ||
356 | + in the range (SIZE_MAX - 2^14, SIZE_MAX], fail. | ||
357 | + | ||
358 | + We can expect that this range of allocation sizes will always lead to | ||
359 | + an allocation failure on both 64 and 32 bit targets, because: | ||
360 | + | ||
361 | + 1. no currently supported 64-bit target has an address bus wider than | ||
362 | + 50 bits -- and (2^64 - 2^14) is much wider than that; | ||
363 | + | ||
364 | + 2. on 32-bit targets, even though 2^32 is only 4 GB and potentially | ||
365 | + addressable, glibc itself is more than 2^14 bytes in size, and | ||
366 | + therefore once glibc is loaded, less than (2^32 - 2^14) bytes remain | ||
367 | + available. */ | ||
368 | + | ||
369 | + for (size_t i = 0; i <= FOURTEEN_ON_BITS; i++) | ||
370 | + { | ||
371 | + test_large_allocations (SIZE_MAX - i); | ||
372 | + test_large_aligned_allocations (SIZE_MAX - i); | ||
373 | + } | ||
374 | + | ||
375 | +#if __WORDSIZE >= 64 | ||
376 | + /* On 64-bit targets, we need to test a much wider range of too-large | ||
377 | + sizes, so we test at intervals of (1 << 50) that allocation sizes | ||
378 | + ranging from SIZE_MAX down to (1 << 50) fail: | ||
379 | + The 14 MSBs are decremented starting from "all ON" going down to 1, | ||
380 | + the 50 LSBs are "all ON" and then "all OFF" during every iteration. */ | ||
381 | + for (size_t msbs = FOURTEEN_ON_BITS; msbs >= 1; msbs--) | ||
382 | + { | ||
383 | + size_t size = (msbs << 50) | FIFTY_ON_BITS; | ||
384 | + test_large_allocations (size); | ||
385 | + test_large_aligned_allocations (size); | ||
386 | + | ||
387 | + size = msbs << 50; | ||
388 | + test_large_allocations (size); | ||
389 | + test_large_aligned_allocations (size); | ||
390 | + } | ||
391 | +#endif /* __WORDSIZE >= 64 */ | ||
392 | + | ||
393 | + DIAG_POP_NEEDS_COMMENT; | ||
394 | + | ||
395 | + return 0; | ||
396 | +} | ||
397 | + | ||
398 | + | ||
399 | +#include <support/test-driver.c> | ||
400 | |||
401 | |||