Sun Mar 8 00:31:19 2020 UTC ()
KMEM_SIZE: append the size_t to the allocated buffer, rather than
prepending, so it doesn't screw up the alignment of the buffer.

Reported-by: syzbot+c024c50570cccac51532@syzkaller.appspotmail.com


(ad)
diff -r1.78 -r1.79 src/sys/kern/subr_kmem.c

cvs diff -r1.78 -r1.79 src/sys/kern/subr_kmem.c (expand / switch to unified diff)

--- src/sys/kern/subr_kmem.c 2020/01/25 15:08:40 1.78
+++ src/sys/kern/subr_kmem.c 2020/03/08 00:31:19 1.79
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: subr_kmem.c,v 1.78 2020/01/25 15:08:40 ad Exp $ */ 1/* $NetBSD: subr_kmem.c,v 1.79 2020/03/08 00:31:19 ad Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2009-2020 The NetBSD Foundation, Inc. 4 * Copyright (c) 2009-2020 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran and Maxime Villard. 8 * by Andrew Doran and Maxime Villard.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -52,43 +52,43 @@ @@ -52,43 +52,43 @@
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE. 55 * SUCH DAMAGE.
56 */ 56 */
57 57
58/* 58/*
59 * Allocator of kernel wired memory. This allocator has some debug features 59 * Allocator of kernel wired memory. This allocator has some debug features
60 * enabled with "option DIAGNOSTIC" and "option DEBUG". 60 * enabled with "option DIAGNOSTIC" and "option DEBUG".
61 */ 61 */
62 62
63/* 63/*
64 * KMEM_SIZE: detect alloc/free size mismatch bugs. 64 * KMEM_SIZE: detect alloc/free size mismatch bugs.
65 * Prefix each allocations with a fixed-sized, aligned header and record 65 * Append to each allocation a fixed-sized footer and record the exact
66 * the exact user-requested allocation size in it. When freeing, compare 66 * user-requested allocation size in it. When freeing, compare it with
67 * it with kmem_free's "size" argument. 67 * kmem_free's "size" argument.
68 * 68 *
69 * This option is enabled on DIAGNOSTIC. 69 * This option is enabled on DIAGNOSTIC.
70 * 70 *
71 * |CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK| 71 * |CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK| |
72 * +-----+-----+-----+-----+-----+-----+-----+-----+-----+---+-+ 72 * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-+
73 * |/////| | | | | | | | | |U| 73 * | | | | | | | | |/////|U|
74 * |/HSZ/| | | | | | | | | |U| 74 * | | | | | | | | |/HSZ/|U|
75 * |/////| | | | | | | | | |U| 75 * | | | | | | | | |/////|U|
76 * +-----+-----+-----+-----+-----+-----+-----+-----+-----+---+-+ 76 * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-+
77 * |Size | Buffer usable by the caller (requested size) |Unused\ 77 * | Buffer usable by the caller (requested size) |Size |Unused
78 */ 78 */
79 79
80#include <sys/cdefs.h> 80#include <sys/cdefs.h>
81__KERNEL_RCSID(0, "$NetBSD: subr_kmem.c,v 1.78 2020/01/25 15:08:40 ad Exp $"); 81__KERNEL_RCSID(0, "$NetBSD: subr_kmem.c,v 1.79 2020/03/08 00:31:19 ad Exp $");
82 82
83#ifdef _KERNEL_OPT 83#ifdef _KERNEL_OPT
84#include "opt_kmem.h" 84#include "opt_kmem.h"
85#endif 85#endif
86 86
87#include <sys/param.h> 87#include <sys/param.h>
88#include <sys/callback.h> 88#include <sys/callback.h>
89#include <sys/kmem.h> 89#include <sys/kmem.h>
90#include <sys/pool.h> 90#include <sys/pool.h>
91#include <sys/debug.h> 91#include <sys/debug.h>
92#include <sys/lockdebug.h> 92#include <sys/lockdebug.h>
93#include <sys/cpu.h> 93#include <sys/cpu.h>
94#include <sys/asan.h> 94#include <sys/asan.h>
@@ -158,30 +158,27 @@ static size_t kmem_cache_maxidx __read_m @@ -158,30 +158,27 @@ static size_t kmem_cache_maxidx __read_m
158 158
159static pool_cache_t kmem_cache_big[KMEM_CACHE_BIG_COUNT] __cacheline_aligned; 159static pool_cache_t kmem_cache_big[KMEM_CACHE_BIG_COUNT] __cacheline_aligned;
160static size_t kmem_cache_big_maxidx __read_mostly; 160static size_t kmem_cache_big_maxidx __read_mostly;
161 161
162#if defined(DIAGNOSTIC) && defined(_HARDKERNEL) 162#if defined(DIAGNOSTIC) && defined(_HARDKERNEL)
163#define KMEM_SIZE 163#define KMEM_SIZE
164#endif 164#endif
165 165
166#if defined(DEBUG) && defined(_HARDKERNEL) 166#if defined(DEBUG) && defined(_HARDKERNEL)
167static void *kmem_freecheck; 167static void *kmem_freecheck;
168#endif 168#endif
169 169
170#if defined(KMEM_SIZE) 170#if defined(KMEM_SIZE)
171struct kmem_header { 171#define SIZE_SIZE sizeof(size_t)
172 size_t size; 
173} __aligned(KMEM_ALIGN); 
174#define SIZE_SIZE sizeof(struct kmem_header) 
175static void kmem_size_set(void *, size_t); 172static void kmem_size_set(void *, size_t);
176static void kmem_size_check(void *, size_t); 173static void kmem_size_check(void *, size_t);
177#else 174#else
178#define SIZE_SIZE 0 175#define SIZE_SIZE 0
179#define kmem_size_set(p, sz) /* nothing */ 176#define kmem_size_set(p, sz) /* nothing */
180#define kmem_size_check(p, sz) /* nothing */ 177#define kmem_size_check(p, sz) /* nothing */
181#endif 178#endif
182 179
183CTASSERT(KM_SLEEP == PR_WAITOK); 180CTASSERT(KM_SLEEP == PR_WAITOK);
184CTASSERT(KM_NOSLEEP == PR_NOWAIT); 181CTASSERT(KM_NOSLEEP == PR_NOWAIT);
185 182
186/* 183/*
187 * kmem_intr_alloc: allocate wired memory. 184 * kmem_intr_alloc: allocate wired memory.
@@ -219,27 +216,26 @@ kmem_intr_alloc(size_t requested_size, k @@ -219,27 +216,26 @@ kmem_intr_alloc(size_t requested_size, k
219 | VM_INSTANTFIT, (vmem_addr_t *)&p); 216 | VM_INSTANTFIT, (vmem_addr_t *)&p);
220 if (ret) { 217 if (ret) {
221 return NULL; 218 return NULL;
222 } 219 }
223 FREECHECK_OUT(&kmem_freecheck, p); 220 FREECHECK_OUT(&kmem_freecheck, p);
224 return p; 221 return p;
225 } 222 }
226 223
227 p = pool_cache_get(pc, kmflags); 224 p = pool_cache_get(pc, kmflags);
228 225
229 if (__predict_true(p != NULL)) { 226 if (__predict_true(p != NULL)) {
230 FREECHECK_OUT(&kmem_freecheck, p); 227 FREECHECK_OUT(&kmem_freecheck, p);
231 kmem_size_set(p, requested_size); 228 kmem_size_set(p, requested_size);
232 p += SIZE_SIZE; 
233 kasan_mark(p, origsize, size, KASAN_KMEM_REDZONE); 229 kasan_mark(p, origsize, size, KASAN_KMEM_REDZONE);
234 return p; 230 return p;
235 } 231 }
236 return p; 232 return p;
237} 233}
238 234
239/* 235/*
240 * kmem_intr_zalloc: allocate zeroed wired memory. 236 * kmem_intr_zalloc: allocate zeroed wired memory.
241 */ 237 */
242void * 238void *
243kmem_intr_zalloc(size_t size, km_flag_t kmflags) 239kmem_intr_zalloc(size_t size, km_flag_t kmflags)
244{ 240{
245 void *p; 241 void *p;
@@ -273,27 +269,26 @@ kmem_intr_free(void *p, size_t requested @@ -273,27 +269,26 @@ kmem_intr_free(void *p, size_t requested
273 pc = kmem_cache[index]; 269 pc = kmem_cache[index];
274 } else if ((index = ((allocsz - 1) >> KMEM_BIG_SHIFT)) 270 } else if ((index = ((allocsz - 1) >> KMEM_BIG_SHIFT))
275 < kmem_cache_big_maxidx) { 271 < kmem_cache_big_maxidx) {
276 pc = kmem_cache_big[index]; 272 pc = kmem_cache_big[index];
277 } else { 273 } else {
278 FREECHECK_IN(&kmem_freecheck, p); 274 FREECHECK_IN(&kmem_freecheck, p);
279 uvm_km_kmem_free(kmem_va_arena, (vaddr_t)p, 275 uvm_km_kmem_free(kmem_va_arena, (vaddr_t)p,
280 round_page(size)); 276 round_page(size));
281 return; 277 return;
282 } 278 }
283 279
284 kasan_mark(p, size, size, 0); 280 kasan_mark(p, size, size, 0);
285 281
286 p = (uint8_t *)p - SIZE_SIZE; 
287 kmem_size_check(p, requested_size); 282 kmem_size_check(p, requested_size);
288 FREECHECK_IN(&kmem_freecheck, p); 283 FREECHECK_IN(&kmem_freecheck, p);
289 LOCKDEBUG_MEM_CHECK(p, size); 284 LOCKDEBUG_MEM_CHECK(p, size);
290 285
291 pool_cache_put(pc, p); 286 pool_cache_put(pc, p);
292} 287}
293 288
294/* -------------------------------- Kmem API -------------------------------- */ 289/* -------------------------------- Kmem API -------------------------------- */
295 290
296/* 291/*
297 * kmem_alloc: allocate wired memory. 292 * kmem_alloc: allocate wired memory.
298 * => must not be called from interrupt context. 293 * => must not be called from interrupt context.
299 */ 294 */
@@ -475,35 +470,31 @@ kmem_strfree(char *str) @@ -475,35 +470,31 @@ kmem_strfree(char *str)
475{ 470{
476 if (str == NULL) 471 if (str == NULL)
477 return; 472 return;
478 473
479 kmem_free(str, strlen(str) + 1); 474 kmem_free(str, strlen(str) + 1);
480} 475}
481 476
482/* --------------------------- DEBUG / DIAGNOSTIC --------------------------- */ 477/* --------------------------- DEBUG / DIAGNOSTIC --------------------------- */
483 478
484#if defined(KMEM_SIZE) 479#if defined(KMEM_SIZE)
485static void 480static void
486kmem_size_set(void *p, size_t sz) 481kmem_size_set(void *p, size_t sz)
487{ 482{
488 struct kmem_header *hd; 483 memcpy((size_t *)((uintptr_t)p + sz), &sz, sizeof(size_t));
489 hd = (struct kmem_header *)p; 
490 hd->size = sz; 
491} 484}
492 485
493static void 486static void
494kmem_size_check(void *p, size_t sz) 487kmem_size_check(void *p, size_t sz)
495{ 488{
496 struct kmem_header *hd; 
497 size_t hsz; 489 size_t hsz;
498 490
499 hd = (struct kmem_header *)p; 491 memcpy(&hsz, (size_t *)((uintptr_t)p + sz), sizeof(size_t));
500 hsz = hd->size; 
501 492
502 if (hsz != sz) { 493 if (hsz != sz) {
503 panic("kmem_free(%p, %zu) != allocated size %zu", 494 panic("kmem_free(%p, %zu) != allocated size %zu; overwrote?",
504 (const uint8_t *)p + SIZE_SIZE, sz, hsz); 495 p, sz, hsz);
505 } 496 }
506 497
507 hd->size = -1; 498 memset((size_t *)((uintptr_t)p + sz), 0xff, sizeof(size_t));
508} 499}
509#endif /* defined(KMEM_SIZE) */ 500#endif /* defined(KMEM_SIZE) */