@@ -306,6 +306,53 @@ zio_fini(void)
306
306
* ==========================================================================
307
307
*/
308
308
309
+ #ifdef ZFS_DEBUG
310
+ static const ulong_t zio_buf_canary = (ulong_t )0xdeadc0dedead210b ;
311
+ #endif
312
+
313
+ /*
314
+ * Use empty space after the buffer to detect overflows.
315
+ *
316
+ * Since zio_init() creates kmem caches only for certain set of buffer sizes,
317
+ * allocations of different sizes may have some unused space after the data.
318
+ * Filling part of that space with a known pattern on allocation and checking
319
+ * it on free should allow us to detect some buffer overflows.
320
+ */
321
+ static void
322
+ zio_buf_put_canary (ulong_t * p , size_t size , kmem_cache_t * * cache , size_t c )
323
+ {
324
+ #ifdef ZFS_DEBUG
325
+ size_t off = P2ROUNDUP (size , sizeof (ulong_t ));
326
+ ulong_t * canary = p + off / sizeof (ulong_t );
327
+ size_t asize = (c + 1 ) << SPA_MINBLOCKSHIFT ;
328
+ if (c + 1 < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT &&
329
+ cache [c ] == cache [c + 1 ])
330
+ asize = (c + 2 ) << SPA_MINBLOCKSHIFT ;
331
+ for (; off < asize ; canary ++ , off += sizeof (ulong_t ))
332
+ * canary = zio_buf_canary ;
333
+ #endif
334
+ }
335
+
336
+ static void
337
+ zio_buf_check_canary (ulong_t * p , size_t size , kmem_cache_t * * cache , size_t c )
338
+ {
339
+ #ifdef ZFS_DEBUG
340
+ size_t off = P2ROUNDUP (size , sizeof (ulong_t ));
341
+ ulong_t * canary = p + off / sizeof (ulong_t );
342
+ size_t asize = (c + 1 ) << SPA_MINBLOCKSHIFT ;
343
+ if (c + 1 < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT &&
344
+ cache [c ] == cache [c + 1 ])
345
+ asize = (c + 2 ) << SPA_MINBLOCKSHIFT ;
346
+ for (; off < asize ; canary ++ , off += sizeof (ulong_t )) {
347
+ if (unlikely (* canary != zio_buf_canary )) {
348
+ PANIC ("ZIO buffer overflow %p (%zu) + %zu %#lx != %#lx" ,
349
+ p , size , (canary - p ) * sizeof (ulong_t ),
350
+ * canary , zio_buf_canary );
351
+ }
352
+ }
353
+ #endif
354
+ }
355
+
309
356
/*
310
357
* Use zio_buf_alloc to allocate ZFS metadata. This data will appear in a
311
358
* crashdump if the kernel panics, so use it judiciously. Obviously, it's
@@ -322,7 +369,9 @@ zio_buf_alloc(size_t size)
322
369
atomic_add_64 (& zio_buf_cache_allocs [c ], 1 );
323
370
#endif
324
371
325
- return (kmem_cache_alloc (zio_buf_cache [c ], KM_PUSHPAGE ));
372
+ void * p = kmem_cache_alloc (zio_buf_cache [c ], KM_PUSHPAGE );
373
+ zio_buf_put_canary (p , size , zio_buf_cache , c );
374
+ return (p );
326
375
}
327
376
328
377
/*
@@ -338,7 +387,9 @@ zio_data_buf_alloc(size_t size)
338
387
339
388
VERIFY3U (c , < , SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT );
340
389
341
- return (kmem_cache_alloc (zio_data_buf_cache [c ], KM_PUSHPAGE ));
390
+ void * p = kmem_cache_alloc (zio_data_buf_cache [c ], KM_PUSHPAGE );
391
+ zio_buf_put_canary (p , size , zio_data_buf_cache , c );
392
+ return (p );
342
393
}
343
394
344
395
void
@@ -351,6 +402,7 @@ zio_buf_free(void *buf, size_t size)
351
402
atomic_add_64 (& zio_buf_cache_frees [c ], 1 );
352
403
#endif
353
404
405
+ zio_buf_check_canary (buf , size , zio_buf_cache , c );
354
406
kmem_cache_free (zio_buf_cache [c ], buf );
355
407
}
356
408
@@ -361,6 +413,7 @@ zio_data_buf_free(void *buf, size_t size)
361
413
362
414
VERIFY3U (c , < , SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT );
363
415
416
+ zio_buf_check_canary (buf , size , zio_data_buf_cache , c );
364
417
kmem_cache_free (zio_data_buf_cache [c ], buf );
365
418
}
366
419
0 commit comments