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