public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Kees Cook <keescook@chromium.org>
To: linux-hardening@vger.kernel.org
Cc: Kees Cook <keescook@chromium.org>,
	David Gow <davidgow@google.com>,
	linux-kernel@vger.kernel.org
Subject: [PATCH] kunit/fortify: Validate __alloc_size attribute results
Date: Tue, 18 Oct 2022 01:27:41 -0700	[thread overview]
Message-ID: <20221018082559.never.406-kees@kernel.org> (raw)

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@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.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


             reply	other threads:[~2022-10-18  8:28 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-18  8:27 Kees Cook [this message]
2022-10-19  3:35 ` [PATCH] kunit/fortify: Validate __alloc_size attribute results David Gow
2022-10-19  5:45   ` Kees Cook
2022-10-19  6:29     ` David Gow
2022-11-01 22:04       ` Kees Cook

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221018082559.never.406-kees@kernel.org \
    --to=keescook@chromium.org \
    --cc=davidgow@google.com \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox