lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Tue, 18 Oct 2022 01:27:41 -0700 From: Kees Cook <keescook@...omium.org> To: linux-hardening@...r.kernel.org Cc: Kees Cook <keescook@...omium.org>, David Gow <davidgow@...gle.com>, linux-kernel@...r.kernel.org Subject: [PATCH] kunit/fortify: Validate __alloc_size attribute results Validate the effect of the __alloc_size attribute on allocators. If the compiler doesn't support __builtin_dynamic_object_size(), skip the test. Cc: linux-hardening@...r.kernel.org Signed-off-by: Kees Cook <keescook@...omium.org> --- To pass this depends on the following patches: https://lore.kernel.org/lkml/20221018073430.never.551-kees@kernel.org/ https://lore.kernel.org/lkml/20221018082232.never.213-kees@kernel.org/ To not be skipped, either GCC 12 or Clang is needed. --- lib/fortify_kunit.c | 92 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/lib/fortify_kunit.c b/lib/fortify_kunit.c index 409af07f340a..5076ba11adfd 100644 --- a/lib/fortify_kunit.c +++ b/lib/fortify_kunit.c @@ -16,7 +16,10 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <kunit/test.h> +#include <linux/device.h> #include <linux/string.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> static const char array_of_10[] = "this is 10"; static const char *ptr_of_11 = "this is 11!"; @@ -60,9 +63,98 @@ static void control_flow_split_test(struct kunit *test) KUNIT_EXPECT_EQ(test, want_minus_one(pick), SIZE_MAX); } +#define check_alloc(alloc, free) do { \ + size_t expected = size; \ + void *p = alloc; \ + KUNIT_EXPECT_TRUE_MSG(test, p != NULL, #alloc " failed?!\n"); \ + KUNIT_EXPECT_EQ_MSG(test, __builtin_dynamic_object_size(p, 1), \ + expected, \ + "__alloc_size() not working with " #alloc "\n"); \ + free; \ +} while (0) + +static volatile size_t unknown_size = 50; + +static void alloc_size_test(struct kunit *test) +{ +#if !__has_builtin(__builtin_dynamic_object_size) + kunit_skip(test, "Compiler is missing __builtin_dynamic_object_size() support\n"); +#else + const char device_name[] = "fortify-test"; + struct device *dev; + gfp_t gfp = GFP_KERNEL | __GFP_NOWARN; + size_t size = unknown_size, prev_size; + void *orig; + + /* kmalloc()-family */ + check_alloc(kmalloc(size++, gfp), kfree(p)); + check_alloc(kmalloc_node(size++, gfp, NUMA_NO_NODE), kfree(p)); + check_alloc(kzalloc(size++, gfp), kfree(p)); + check_alloc(kzalloc_node(size++, gfp, NUMA_NO_NODE), kfree(p)); + check_alloc(kcalloc(1, size++, gfp), kfree(p)); + check_alloc(kcalloc_node(1, size++, gfp, NUMA_NO_NODE), kfree(p)); + check_alloc(kmalloc_array(1, size++, gfp), kfree(p)); + check_alloc(kmalloc_array_node(1, size++, gfp, NUMA_NO_NODE), kfree(p)); + check_alloc(__kmalloc(size++, gfp), kfree(p)); + check_alloc(__kmalloc_node(size++, gfp, NUMA_NO_NODE), kfree(p)); + + /* kmemdup() */ + prev_size = size; + size = 11; + check_alloc(kmemdup("hello there", size, gfp), kfree(p)); + size = prev_size + 1; + + /* krealloc()-family */ + orig = kmalloc(size++, gfp); + check_alloc(krealloc(orig, size++, gfp), kfree(p)); + orig = kmalloc(size++, gfp); + check_alloc(krealloc_array(orig, 1, size++, gfp), kfree(p)); + + /* vmalloc()-family */ + check_alloc(vmalloc(size++), vfree(p)); + check_alloc(vzalloc(size++), vfree(p)); + check_alloc(__vmalloc(size++, gfp), vfree(p)); + + /* kvalloc()-family */ + check_alloc(kvmalloc(size++, gfp), kvfree(p)); + check_alloc(kvmalloc_node(size++, gfp, NUMA_NO_NODE), kvfree(p)); + check_alloc(kvzalloc(size++, gfp), kvfree(p)); + check_alloc(kvzalloc_node(size++, gfp, NUMA_NO_NODE), kvfree(p)); + check_alloc(kvcalloc(1, size++, gfp), kvfree(p)); + check_alloc(kvmalloc_array(1, size++, gfp), kvfree(p)); + + /* kvrealloc() */ + prev_size = size++; + orig = kvmalloc(prev_size, gfp); + check_alloc(kvrealloc(orig, prev_size, size++, gfp), kfree(p)); + + /* Create dummy device for devm_kmalloc()-family tests. */ + dev = root_device_register(device_name); + KUNIT_ASSERT_FALSE_MSG(test, IS_ERR(dev), + "Cannot register test device\n"); + + /* devm_kmalloc()-family */ + check_alloc(devm_kmalloc(dev, size++, gfp), devm_kfree(dev, p)); + check_alloc(devm_kzalloc(dev, size++, gfp), devm_kfree(dev, p)); + + /* devm_kmemdup() */ + prev_size = size; + size = 4; + check_alloc(devm_kmemdup(dev, "Ohai", size, gfp), devm_kfree(dev, p)); + size = prev_size + 1; + + /* devm_kremalloc() */ + orig = devm_kmalloc(dev, size++, gfp); + check_alloc(devm_krealloc(dev, orig, size++, gfp), devm_kfree(dev, p)); + + device_unregister(dev); +#endif +} + static struct kunit_case fortify_test_cases[] = { KUNIT_CASE(known_sizes_test), KUNIT_CASE(control_flow_split_test), + KUNIT_CASE(alloc_size_test), {} }; -- 2.34.1
Powered by blists - more mailing lists