Browse code

glibc : fix CVE-2018-6485

Change-Id: I581fd4cff3f414cb1d71a293a9b73a05a211e4cd
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/4821
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Dheeraj S Shetty <dheerajs@vmware.com>
Reviewed-by: Anish Swaminathan <anishs@vmware.com>

Xiaolin Li authored on 2018/02/24 04:54:42
Showing 2 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,344 @@
0
+From 9331dbdcd7aa8e997eb4caa9b1b0cb6c804320c8 Mon Sep 17 00:00:00 2001
1
+From: Arjun Shankar <arjun@redhat.com>
2
+Date: Thu, 18 Jan 2018 16:47:06 +0000
3
+Subject: [PATCH] Fix integer overflows in internal memalign and malloc [BZ
4
+ #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
+ ChangeLog                     |  13 +++
31
+ NEWS                          |  10 ++
32
+ malloc/Makefile               |   1 +
33
+ malloc/malloc.c               |  30 ++++--
34
+ malloc/tst-malloc-too-large.c | 237 ++++++++++++++++++++++++++++++++++++++++++
35
+ 5 files changed, 283 insertions(+), 8 deletions(-)
36
+ create mode 100644 malloc/tst-malloc-too-large.c
37
+
38
+diff --git a/malloc/Makefile b/malloc/Makefile
39
+index 89fce91..9b40e87 100644
40
+--- a/malloc/Makefile
41
+@@ -34,6 +34,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
42
+ 	 tst-interpose-nothread \
43
+ 	 tst-interpose-thread \
44
+ 	 tst-alloc_buffer \
45
++	 tst-malloc-too-large \
46
+ 
47
+ tests-static := \
48
+ 	 tst-interpose-static-nothread \
49
+diff --git a/malloc/malloc.c b/malloc/malloc.c
50
+index 4e07663..0686e5d 100644
51
+--- a/malloc/malloc.c
52
+@@ -1202,14 +1202,21 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53
+    MINSIZE :                                                      \
54
+    ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
55
+ 
56
+-/*  Same, except also perform argument check */
57
+-
58
+-#define checked_request2size(req, sz)                             \
59
+-  if (REQUEST_OUT_OF_RANGE (req)) {					      \
60
+-      __set_errno (ENOMEM);						      \
61
+-      return 0;								      \
62
+-    }									      \
63
+-  (sz) = request2size (req);
64
++/* Same, except also perform an argument and result check.  First, we check
65
++   that the padding done by request2size didn't result in an integer
66
++   overflow.  Then we check (using REQUEST_OUT_OF_RANGE) that the resulting
67
++   size isn't so large that a later alignment would lead to another integer
68
++   overflow.  */
69
++#define checked_request2size(req, sz) \
70
++({				    \
71
++  (sz) = request2size (req);	    \
72
++  if (((sz) < (req))		    \
73
++      || REQUEST_OUT_OF_RANGE (sz)) \
74
++    {				    \
75
++      __set_errno (ENOMEM);	    \
76
++      return 0;			    \
77
++    }				    \
78
++})
79
+ 
80
+ /*
81
+    --------------- Physical chunk operations ---------------
82
+@@ -4423,6 +4430,13 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
83
+    */
84
+ 
85
+ 
86
++  /* Check for overflow.  */
87
++  if (nb > SIZE_MAX - alignment - MINSIZE)
88
++    {
89
++      __set_errno (ENOMEM);
90
++      return 0;
91
++    }
92
++
93
+   /* Call malloc with worst case padding to hit alignment. */
94
+ 
95
+   m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
96
+diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c
97
+new file mode 100644
98
+index 0000000..1f7bf29
99
+--- /dev/null
100
+@@ -0,0 +1,237 @@
101
++/* Test and verify that too-large memory allocations fail with ENOMEM.
102
++   Copyright (C) 2018 Free Software Foundation, Inc.
103
++   This file is part of the GNU C Library.
104
++
105
++   The GNU C Library is free software; you can redistribute it and/or
106
++   modify it under the terms of the GNU Lesser General Public
107
++   License as published by the Free Software Foundation; either
108
++   version 2.1 of the License, or (at your option) any later version.
109
++
110
++   The GNU C Library is distributed in the hope that it will be useful,
111
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
112
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
113
++   Lesser General Public License for more details.
114
++
115
++   You should have received a copy of the GNU Lesser General Public
116
++   License along with the GNU C Library; if not, see
117
++   <http://www.gnu.org/licenses/>.  */
118
++
119
++/* Bug 22375 reported a regression in malloc where if after malloc'ing then
120
++   free'ing a small block of memory, malloc is then called with a really
121
++   large size argument (close to SIZE_MAX): instead of returning NULL and
122
++   setting errno to ENOMEM, malloc incorrectly returns the previously
123
++   allocated block instead.  Bug 22343 reported a similar case where
124
++   posix_memalign incorrectly returns successfully when called with an with
125
++   a really large size argument.
126
++
127
++   Both of these were caused by integer overflows in the allocator when it
128
++   was trying to pad the requested size to allow for book-keeping or
129
++   alignment.  This test guards against such bugs by repeatedly allocating
130
++   and freeing small blocks of memory then trying to allocate various block
131
++   sizes larger than the memory bus width of 64-bit targets, or almost
132
++   as large as SIZE_MAX on 32-bit targets supported by glibc.  In each case,
133
++   it verifies that such impossibly large allocations correctly fail.  */
134
++
135
++
136
++#include <stdlib.h>
137
++#include <malloc.h>
138
++#include <errno.h>
139
++#include <stdint.h>
140
++#include <sys/resource.h>
141
++#include <libc-internal.h>
142
++#include <support/check.h>
143
++#include <unistd.h>
144
++#include <sys/param.h>
145
++
146
++
147
++/* This function prepares for each 'too-large memory allocation' test by
148
++   performing a small successful malloc/free and resetting errno prior to
149
++   the actual test.  */
150
++static void
151
++test_setup (void)
152
++{
153
++  void *volatile ptr = malloc (16);
154
++  TEST_VERIFY_EXIT (ptr != NULL);
155
++  free (ptr);
156
++  errno = 0;
157
++}
158
++
159
++
160
++/* This function tests each of:
161
++   - malloc (SIZE)
162
++   - realloc (PTR_FOR_REALLOC, SIZE)
163
++   - for various values of NMEMB:
164
++    - calloc (NMEMB, SIZE/NMEMB)
165
++    - calloc (SIZE/NMEMB, NMEMB)
166
++   and precedes each of these tests with a small malloc/free before it.  */
167
++static void
168
++test_large_allocations (size_t size)
169
++{
170
++  void * ptr_to_realloc;
171
++
172
++  test_setup ();
173
++  TEST_VERIFY (malloc (size) == NULL);
174
++  TEST_VERIFY (errno == ENOMEM);
175
++
176
++  ptr_to_realloc = malloc (16);
177
++  TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
178
++  test_setup ();
179
++  TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL);
180
++  TEST_VERIFY (errno == ENOMEM);
181
++  free (ptr_to_realloc);
182
++
183
++  for (size_t nmemb = 1; nmemb <= 8; nmemb *= 2)
184
++    if ((size % nmemb) == 0)
185
++      {
186
++        test_setup ();
187
++        TEST_VERIFY (calloc (nmemb, size / nmemb) == NULL);
188
++        TEST_VERIFY (errno == ENOMEM);
189
++
190
++        test_setup ();
191
++        TEST_VERIFY (calloc (size / nmemb, nmemb) == NULL);
192
++        TEST_VERIFY (errno == ENOMEM);
193
++      }
194
++    else
195
++      break;
196
++}
197
++
198
++
199
++static long pagesize;
200
++
201
++/* This function tests the following aligned memory allocation functions
202
++   using several valid alignments and precedes each allocation test with a
203
++   small malloc/free before it:
204
++   memalign, posix_memalign, aligned_alloc, valloc, pvalloc.  */
205
++static void
206
++test_large_aligned_allocations (size_t size)
207
++{
208
++  /* ptr stores the result of posix_memalign but since all those calls
209
++     should fail, posix_memalign should never change ptr.  We set it to
210
++     NULL here and later on we check that it remains NULL after each
211
++     posix_memalign call.  */
212
++  void * ptr = NULL;
213
++
214
++  size_t align;
215
++
216
++  /* All aligned memory allocation functions expect an alignment that is a
217
++     power of 2.  Given this, we test each of them with every valid
218
++     alignment from 1 thru PAGESIZE.  */
219
++  for (align = 1; align <= pagesize; align *= 2)
220
++    {
221
++      test_setup ();
222
++      TEST_VERIFY (memalign (align, size) == NULL);
223
++      TEST_VERIFY (errno == ENOMEM);
224
++
225
++      /* posix_memalign expects an alignment that is a power of 2 *and* a
226
++         multiple of sizeof (void *).  */
227
++      if ((align % sizeof (void *)) == 0)
228
++        {
229
++          test_setup ();
230
++          TEST_VERIFY (posix_memalign (&ptr, align, size) == ENOMEM);
231
++          TEST_VERIFY (ptr == NULL);
232
++        }
233
++
234
++      /* aligned_alloc expects a size that is a multiple of alignment.  */
235
++      if ((size % align) == 0)
236
++        {
237
++          test_setup ();
238
++          TEST_VERIFY (aligned_alloc (align, size) == NULL);
239
++          TEST_VERIFY (errno == ENOMEM);
240
++        }
241
++    }
242
++
243
++  /* Both valloc and pvalloc return page-aligned memory.  */
244
++
245
++  test_setup ();
246
++  TEST_VERIFY (valloc (size) == NULL);
247
++  TEST_VERIFY (errno == ENOMEM);
248
++
249
++  test_setup ();
250
++  TEST_VERIFY (pvalloc (size) == NULL);
251
++  TEST_VERIFY (errno == ENOMEM);
252
++}
253
++
254
++
255
++#define FOURTEEN_ON_BITS ((1UL << 14) - 1)
256
++#define FIFTY_ON_BITS ((1UL << 50) - 1)
257
++
258
++
259
++static int
260
++do_test (void)
261
++{
262
++
263
++#if __WORDSIZE >= 64
264
++
265
++  /* This test assumes that none of the supported targets have an address
266
++     bus wider than 50 bits, and that therefore allocations for sizes wider
267
++     than 50 bits will fail.  Here, we ensure that the assumption continues
268
++     to be true in the future when we might have address buses wider than 50
269
++     bits.  */
270
++
271
++  struct rlimit alloc_size_limit
272
++    = {
273
++        .rlim_cur = FIFTY_ON_BITS,
274
++        .rlim_max = FIFTY_ON_BITS
275
++      };
276
++
277
++  setrlimit (RLIMIT_AS, &alloc_size_limit);
278
++
279
++#endif /* __WORDSIZE >= 64 */
280
++
281
++  DIAG_PUSH_NEEDS_COMMENT;
282
++#if __GNUC_PREREQ (7, 0)
283
++  /* GCC 7 warns about too-large allocations; here we want to test
284
++     that they fail.  */
285
++  DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
286
++#endif
287
++
288
++  /* Aligned memory allocation functions need to be tested up to alignment
289
++     size equivalent to page size, which should be a power of 2.  */
290
++  pagesize = sysconf (_SC_PAGESIZE);
291
++  TEST_VERIFY_EXIT (powerof2 (pagesize));
292
++
293
++  /* Loop 1: Ensure that all allocations with SIZE close to SIZE_MAX, i.e.
294
++     in the range (SIZE_MAX - 2^14, SIZE_MAX], fail.
295
++
296
++     We can expect that this range of allocation sizes will always lead to
297
++     an allocation failure on both 64 and 32 bit targets, because:
298
++
299
++     1. no currently supported 64-bit target has an address bus wider than
300
++     50 bits -- and (2^64 - 2^14) is much wider than that;
301
++
302
++     2. on 32-bit targets, even though 2^32 is only 4 GB and potentially
303
++     addressable, glibc itself is more than 2^14 bytes in size, and
304
++     therefore once glibc is loaded, less than (2^32 - 2^14) bytes remain
305
++     available.  */
306
++
307
++  for (size_t i = 0; i <= FOURTEEN_ON_BITS; i++)
308
++    {
309
++      test_large_allocations (SIZE_MAX - i);
310
++      test_large_aligned_allocations (SIZE_MAX - i);
311
++    }
312
++
313
++#if __WORDSIZE >= 64
314
++  /* On 64-bit targets, we need to test a much wider range of too-large
315
++     sizes, so we test at intervals of (1 << 50) that allocation sizes
316
++     ranging from SIZE_MAX down to (1 << 50) fail:
317
++     The 14 MSBs are decremented starting from "all ON" going down to 1,
318
++     the 50 LSBs are "all ON" and then "all OFF" during every iteration.  */
319
++  for (size_t msbs = FOURTEEN_ON_BITS; msbs >= 1; msbs--)
320
++    {
321
++      size_t size = (msbs << 50) | FIFTY_ON_BITS;
322
++      test_large_allocations (size);
323
++      test_large_aligned_allocations (size);
324
++
325
++      size = msbs << 50;
326
++      test_large_allocations (size);
327
++      test_large_aligned_allocations (size);
328
++    }
329
++#endif /* __WORDSIZE >= 64 */
330
++
331
++  DIAG_POP_NEEDS_COMMENT;
332
++
333
++  return 0;
334
++}
335
++
336
++
337
++#include <support/test-driver.c>
338
+-- 
339
+2.9.3
340
+
... ...
@@ -4,7 +4,7 @@
4 4
 Summary:        Main C library
5 5
 Name:           glibc
6 6
 Version:        2.26
7
-Release:        9%{?dist}
7
+Release:        10%{?dist}
8 8
 License:        LGPLv2+
9 9
 URL:            http://www.gnu.org/software/libc
10 10
 Group:          Applications/System
... ...
@@ -23,6 +23,7 @@ Patch5:         glibc-fix-CVE-2017-15804.patch
23 23
 Patch6:         glibc-fix-CVE-2017-17426.patch
24 24
 Patch7:         glibc-fix-CVE-2017-16997.patch
25 25
 Patch8:         glibc-fix-CVE-2018-1000001.patch
26
+Patch9:         glibc-fix-CVE-2018-6485.patch
26 27
 Provides:       rtld(GNU_HASH)
27 28
 Requires:       filesystem
28 29
 %description
... ...
@@ -85,6 +86,7 @@ sed -i 's/\\$$(pwd)/`pwd`/' timezone/Makefile
85 85
 %patch6 -p1
86 86
 %patch7 -p1
87 87
 %patch8 -p1
88
+%patch9 -p1
88 89
 install -vdm 755 %{_builddir}/%{name}-build
89 90
 # do not try to explicitly provide GLIBC_PRIVATE versioned libraries
90 91
 %define __find_provides %{_builddir}/%{name}-%{version}/find_provides.sh
... ...
@@ -288,6 +290,8 @@ grep "^FAIL: nptl/tst-eintr1" tests.sum >/dev/null && n=$((n+1)) ||:
288 288
 
289 289
 
290 290
 %changelog
291
+*   Tue Jan 20 2018 Xiaolin Li <xiaolinl@vmware.com> 2.26-10
292
+-   Fix CVE-2018-6485
291 293
 *   Tue Jan 20 2018 Xiaolin Li <xiaolinl@vmware.com> 2.26-9
292 294
 -   Fix CVE-2018-1000001
293 295
 *   Mon Jan 08 2018 Xiaolin Li <xiaolinl@vmware.com> 2.26-8