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>
| 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 |