diff options
author | Kees Cook <keescook@chromium.org> | 2018-05-10 19:40:03 -0400 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2018-06-05 15:16:51 -0400 |
commit | ca90800a91ba723d78ded634d037c1d2df8b54d6 (patch) | |
tree | 5c709a41d95010d66d7a3f22607614ae117f66d2 /lib/test_overflow.c | |
parent | 610b15c50e86eb1e4b77274fabcaea29ac72d6a8 (diff) |
test_overflow: Add memory allocation overflow tests
Make sure that the memory allocators are behaving as expected in the face
of overflows of multiplied arguments or when using the array_size()-family
helpers.
Example output of new tests (with the expected __alloc_pages_slowpath
and vmalloc warnings about refusing giant allocations removed):
[ 93.062076] test_overflow: kmalloc detected saturation
[ 93.062988] test_overflow: kmalloc_node detected saturation
[ 93.063818] test_overflow: kzalloc detected saturation
[ 93.064539] test_overflow: kzalloc_node detected saturation
[ 93.120386] test_overflow: kvmalloc detected saturation
[ 93.143458] test_overflow: kvmalloc_node detected saturation
[ 93.166861] test_overflow: kvzalloc detected saturation
[ 93.189924] test_overflow: kvzalloc_node detected saturation
[ 93.221671] test_overflow: vmalloc detected saturation
[ 93.246326] test_overflow: vmalloc_node detected saturation
[ 93.270260] test_overflow: vzalloc detected saturation
[ 93.293824] test_overflow: vzalloc_node detected saturation
[ 93.294597] test_overflow: devm_kmalloc detected saturation
[ 93.295383] test_overflow: devm_kzalloc detected saturation
[ 93.296217] test_overflow: all tests passed
Signed-off-by: Kees Cook <keescook@chromium.org>
Diffstat (limited to 'lib/test_overflow.c')
-rw-r--r-- | lib/test_overflow.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/lib/test_overflow.c b/lib/test_overflow.c index 501ed86205c4..aecbbb217305 100644 --- a/lib/test_overflow.c +++ b/lib/test_overflow.c | |||
@@ -4,11 +4,15 @@ | |||
4 | */ | 4 | */ |
5 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 5 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
6 | 6 | ||
7 | #include <linux/device.h> | ||
7 | #include <linux/init.h> | 8 | #include <linux/init.h> |
8 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
10 | #include <linux/mm.h> | ||
9 | #include <linux/module.h> | 11 | #include <linux/module.h> |
10 | #include <linux/overflow.h> | 12 | #include <linux/overflow.h> |
13 | #include <linux/slab.h> | ||
11 | #include <linux/types.h> | 14 | #include <linux/types.h> |
15 | #include <linux/vmalloc.h> | ||
12 | 16 | ||
13 | #define DEFINE_TEST_ARRAY(t) \ | 17 | #define DEFINE_TEST_ARRAY(t) \ |
14 | static const struct test_ ## t { \ | 18 | static const struct test_ ## t { \ |
@@ -283,11 +287,117 @@ static int __init test_overflow_calculation(void) | |||
283 | return err; | 287 | return err; |
284 | } | 288 | } |
285 | 289 | ||
290 | /* | ||
291 | * Deal with the various forms of allocator arguments. See comments above | ||
292 | * the DEFINE_TEST_ALLOC() instances for mapping of the "bits". | ||
293 | */ | ||
294 | #define alloc010(alloc, arg, sz) alloc(sz, GFP_KERNEL) | ||
295 | #define alloc011(alloc, arg, sz) alloc(sz, GFP_KERNEL, NUMA_NO_NODE) | ||
296 | #define alloc000(alloc, arg, sz) alloc(sz) | ||
297 | #define alloc001(alloc, arg, sz) alloc(sz, NUMA_NO_NODE) | ||
298 | #define alloc110(alloc, arg, sz) alloc(arg, sz, GFP_KERNEL) | ||
299 | #define free0(free, arg, ptr) free(ptr) | ||
300 | #define free1(free, arg, ptr) free(arg, ptr) | ||
301 | |||
302 | /* Wrap around to 8K */ | ||
303 | #define TEST_SIZE (9 << PAGE_SHIFT) | ||
304 | |||
305 | #define DEFINE_TEST_ALLOC(func, free_func, want_arg, want_gfp, want_node)\ | ||
306 | static int __init test_ ## func (void *arg) \ | ||
307 | { \ | ||
308 | volatile size_t a = TEST_SIZE; \ | ||
309 | volatile size_t b = (SIZE_MAX / TEST_SIZE) + 1; \ | ||
310 | void *ptr; \ | ||
311 | \ | ||
312 | /* Tiny allocation test. */ \ | ||
313 | ptr = alloc ## want_arg ## want_gfp ## want_node (func, arg, 1);\ | ||
314 | if (!ptr) { \ | ||
315 | pr_warn(#func " failed regular allocation?!\n"); \ | ||
316 | return 1; \ | ||
317 | } \ | ||
318 | free ## want_arg (free_func, arg, ptr); \ | ||
319 | \ | ||
320 | /* Wrapped allocation test. */ \ | ||
321 | ptr = alloc ## want_arg ## want_gfp ## want_node (func, arg, \ | ||
322 | a * b); \ | ||
323 | if (!ptr) { \ | ||
324 | pr_warn(#func " unexpectedly failed bad wrapping?!\n"); \ | ||
325 | return 1; \ | ||
326 | } \ | ||
327 | free ## want_arg (free_func, arg, ptr); \ | ||
328 | \ | ||
329 | /* Saturated allocation test. */ \ | ||
330 | ptr = alloc ## want_arg ## want_gfp ## want_node (func, arg, \ | ||
331 | array_size(a, b)); \ | ||
332 | if (ptr) { \ | ||
333 | pr_warn(#func " missed saturation!\n"); \ | ||
334 | free ## want_arg (free_func, arg, ptr); \ | ||
335 | return 1; \ | ||
336 | } \ | ||
337 | pr_info(#func " detected saturation\n"); \ | ||
338 | return 0; \ | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * Allocator uses a trailing node argument --------+ (e.g. kmalloc_node()) | ||
343 | * Allocator uses the gfp_t argument -----------+ | (e.g. kmalloc()) | ||
344 | * Allocator uses a special leading argument + | | (e.g. devm_kmalloc()) | ||
345 | * | | | | ||
346 | */ | ||
347 | DEFINE_TEST_ALLOC(kmalloc, kfree, 0, 1, 0); | ||
348 | DEFINE_TEST_ALLOC(kmalloc_node, kfree, 0, 1, 1); | ||
349 | DEFINE_TEST_ALLOC(kzalloc, kfree, 0, 1, 0); | ||
350 | DEFINE_TEST_ALLOC(kzalloc_node, kfree, 0, 1, 1); | ||
351 | DEFINE_TEST_ALLOC(vmalloc, vfree, 0, 0, 0); | ||
352 | DEFINE_TEST_ALLOC(vmalloc_node, vfree, 0, 0, 1); | ||
353 | DEFINE_TEST_ALLOC(vzalloc, vfree, 0, 0, 0); | ||
354 | DEFINE_TEST_ALLOC(vzalloc_node, vfree, 0, 0, 1); | ||
355 | DEFINE_TEST_ALLOC(kvmalloc, kvfree, 0, 1, 0); | ||
356 | DEFINE_TEST_ALLOC(kvmalloc_node, kvfree, 0, 1, 1); | ||
357 | DEFINE_TEST_ALLOC(kvzalloc, kvfree, 0, 1, 0); | ||
358 | DEFINE_TEST_ALLOC(kvzalloc_node, kvfree, 0, 1, 1); | ||
359 | DEFINE_TEST_ALLOC(devm_kmalloc, devm_kfree, 1, 1, 0); | ||
360 | DEFINE_TEST_ALLOC(devm_kzalloc, devm_kfree, 1, 1, 0); | ||
361 | |||
362 | static int __init test_overflow_allocation(void) | ||
363 | { | ||
364 | const char device_name[] = "overflow-test"; | ||
365 | struct device *dev; | ||
366 | int err = 0; | ||
367 | |||
368 | /* Create dummy device for devm_kmalloc()-family tests. */ | ||
369 | dev = root_device_register(device_name); | ||
370 | if (!dev) { | ||
371 | pr_warn("Cannot register test device\n"); | ||
372 | return 1; | ||
373 | } | ||
374 | |||
375 | err |= test_kmalloc(NULL); | ||
376 | err |= test_kmalloc_node(NULL); | ||
377 | err |= test_kzalloc(NULL); | ||
378 | err |= test_kzalloc_node(NULL); | ||
379 | err |= test_kvmalloc(NULL); | ||
380 | err |= test_kvmalloc_node(NULL); | ||
381 | err |= test_kvzalloc(NULL); | ||
382 | err |= test_kvzalloc_node(NULL); | ||
383 | err |= test_vmalloc(NULL); | ||
384 | err |= test_vmalloc_node(NULL); | ||
385 | err |= test_vzalloc(NULL); | ||
386 | err |= test_vzalloc_node(NULL); | ||
387 | err |= test_devm_kmalloc(dev); | ||
388 | err |= test_devm_kzalloc(dev); | ||
389 | |||
390 | device_unregister(dev); | ||
391 | |||
392 | return err; | ||
393 | } | ||
394 | |||
286 | static int __init test_module_init(void) | 395 | static int __init test_module_init(void) |
287 | { | 396 | { |
288 | int err = 0; | 397 | int err = 0; |
289 | 398 | ||
290 | err |= test_overflow_calculation(); | 399 | err |= test_overflow_calculation(); |
400 | err |= test_overflow_allocation(); | ||
291 | 401 | ||
292 | if (err) { | 402 | if (err) { |
293 | pr_warn("FAIL!\n"); | 403 | pr_warn("FAIL!\n"); |