From: Alexander Potapenko <glider@google.com>
To: akpm@linux-foundation.org, cl@linux.com, keescook@chromium.org
Cc: kernel-hardening@lists.openwall.com,
Nick Desaulniers <ndesaulniers@google.com>,
Kostya Serebryany <kcc@google.com>,
Dmitry Vyukov <dvyukov@google.com>,
Sandeep Patil <sspatil@android.com>,
Laura Abbott <labbott@redhat.com>, Jann Horn <jannh@google.com>,
linux-mm@kvack.org, linux-security-module@vger.kernel.org
Subject: [PATCH v2 2/4] lib: introduce test_meminit module
Date: Tue, 14 May 2019 16:35:35 +0200 [thread overview]
Message-ID: <20190514143537.10435-3-glider@google.com> (raw)
In-Reply-To: <20190514143537.10435-1-glider@google.com>
Add tests for heap and pagealloc initialization.
These can be used to check init_on_alloc and init_on_free implementations
as well as other approaches to initialization.
Signed-off-by: Alexander Potapenko <glider@google.com>
To: Kees Cook <keescook@chromium.org>
To: Andrew Morton <akpm@linux-foundation.org>
To: Christoph Lameter <cl@linux.com>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Kostya Serebryany <kcc@google.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Sandeep Patil <sspatil@android.com>
Cc: Laura Abbott <labbott@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: linux-mm@kvack.org
Cc: linux-security-module@vger.kernel.org
Cc: kernel-hardening@lists.openwall.com
---
lib/Kconfig.debug | 8 ++
lib/Makefile | 1 +
lib/test_meminit.c | 205 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 214 insertions(+)
create mode 100644 lib/test_meminit.c
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index d695ec1477f3..6c3fc68a4a77 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2020,6 +2020,14 @@ config TEST_STACKINIT
If unsure, say N.
+config TEST_MEMINIT
+ tristate "Test level of heap/page initialization"
+ help
+ Test if the kernel is zero-initializing heap and page allocations.
+ This can be useful to test init_on_alloc and init_on_free features.
+
+ If unsure, say N.
+
endif # RUNTIME_TESTING_MENU
config MEMTEST
diff --git a/lib/Makefile b/lib/Makefile
index 83d7df2661ff..29c5afbe9882 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -91,6 +91,7 @@ obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o
obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o
obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o
obj-$(CONFIG_TEST_STACKINIT) += test_stackinit.o
+obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o
obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
diff --git a/lib/test_meminit.c b/lib/test_meminit.c
new file mode 100644
index 000000000000..67d759498030
--- /dev/null
+++ b/lib/test_meminit.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for SL[AOU]B/page initialization at alloc/free time.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#define GARBAGE_INT (0x09A7BA9E)
+#define GARBAGE_BYTE (0x9E)
+
+#define REPORT_FAILURES_IN_FN() \
+ do { \
+ if (failures) \
+ pr_info("%s failed %d out of %d times\n", \
+ __func__, failures, num_tests); \
+ else \
+ pr_info("all %d tests in %s passed\n", \
+ num_tests, __func__); \
+ } while (0)
+
+/* Calculate the number of uninitialized bytes in the buffer. */
+static int count_nonzero_bytes(void *ptr, size_t size)
+{
+ int i, ret = 0;
+ unsigned char *p = (unsigned char *)ptr;
+
+ for (i = 0; i < size; i++)
+ if (p[i])
+ ret++;
+ return ret;
+}
+
+static void fill_with_garbage(void *ptr, size_t size)
+{
+ unsigned int *p = (unsigned int *)ptr;
+ int i = 0;
+
+ while (size >= sizeof(*p)) {
+ p[i] = GARBAGE_INT;
+ i++;
+ size -= sizeof(*p);
+ }
+ if (size)
+ memset(&p[i], GARBAGE_BYTE, size);
+}
+
+static int __init do_alloc_pages_order(int order, int *total_failures)
+{
+ struct page *page;
+ void *buf;
+ size_t size = PAGE_SIZE << order;
+
+ page = alloc_pages(GFP_KERNEL, order);
+ buf = page_address(page);
+ fill_with_garbage(buf, size);
+ __free_pages(page, order);
+
+ page = alloc_pages(GFP_KERNEL, order);
+ buf = page_address(page);
+ if (count_nonzero_bytes(buf, size))
+ (*total_failures)++;
+ fill_with_garbage(buf, size);
+ __free_pages(page, order);
+ return 1;
+}
+
+static int __init test_pages(int *total_failures)
+{
+ int failures = 0, num_tests = 0;
+ int i;
+
+ for (i = 0; i < 10; i++)
+ num_tests += do_alloc_pages_order(i, &failures);
+
+ REPORT_FAILURES_IN_FN();
+ *total_failures += failures;
+ return num_tests;
+}
+
+static int __init do_kmalloc_size(size_t size, int *total_failures)
+{
+ void *buf;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ fill_with_garbage(buf, size);
+ kfree(buf);
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (count_nonzero_bytes(buf, size))
+ (*total_failures)++;
+ fill_with_garbage(buf, size);
+ kfree(buf);
+ return 1;
+}
+
+static int __init do_vmalloc_size(size_t size, int *total_failures)
+{
+ void *buf;
+
+ buf = vmalloc(size);
+ fill_with_garbage(buf, size);
+ vfree(buf);
+
+ buf = vmalloc(size);
+ if (count_nonzero_bytes(buf, size))
+ (*total_failures)++;
+ fill_with_garbage(buf, size);
+ vfree(buf);
+ return 1;
+}
+
+static int __init test_kvmalloc(int *total_failures)
+{
+ int failures = 0, num_tests = 0;
+ int i, size;
+
+ for (i = 0; i < 20; i++) {
+ size = 1 << i;
+ num_tests += do_kmalloc_size(size, &failures);
+ num_tests += do_vmalloc_size(size, &failures);
+ }
+
+ REPORT_FAILURES_IN_FN();
+ *total_failures += failures;
+ return num_tests;
+}
+
+#define CTOR_BYTES 4
+/* Initialize the first 4 bytes of the object. */
+void some_ctor(void *obj)
+{
+ memset(obj, 'A', CTOR_BYTES);
+}
+
+static int __init do_kmem_cache_size(size_t size, bool want_ctor,
+ int *total_failures)
+{
+ struct kmem_cache *c;
+ void *buf;
+ int iter, bytes = 0;
+ int fail = 0;
+
+ c = kmem_cache_create("test_cache", size, 1, 0,
+ want_ctor ? some_ctor : NULL);
+ for (iter = 0; iter < 10; iter++) {
+ buf = kmem_cache_alloc(c, GFP_KERNEL);
+ if (!want_ctor || iter == 0)
+ bytes = count_nonzero_bytes(buf, size);
+ if (want_ctor) {
+ /*
+ * Newly initialized memory must be initialized using
+ * the constructor.
+ */
+ if (iter == 0 && bytes < CTOR_BYTES)
+ fail = 1;
+ } else {
+ if (bytes)
+ fail = 1;
+ }
+ fill_with_garbage(buf, size);
+ kmem_cache_free(c, buf);
+ }
+ kmem_cache_destroy(c);
+
+ *total_failures += fail;
+ return 1;
+}
+
+static int __init test_kmemcache(int *total_failures)
+{
+ int failures = 0, num_tests = 0;
+ int i, size;
+
+ for (i = 0; i < 10; i++) {
+ size = 4 << i;
+ num_tests += do_kmem_cache_size(size, false, &failures);
+ num_tests += do_kmem_cache_size(size, true, &failures);
+ }
+ REPORT_FAILURES_IN_FN();
+ *total_failures += failures;
+ return num_tests;
+}
+
+static int __init test_meminit_init(void)
+{
+ int failures = 0, num_tests = 0;
+
+ num_tests += test_pages(&failures);
+ num_tests += test_kvmalloc(&failures);
+ num_tests += test_kmemcache(&failures);
+
+ if (failures == 0)
+ pr_info("all %d tests passed!\n", num_tests);
+ else
+ pr_info("failures: %d out of %d\n", failures, num_tests);
+
+ return failures ? -EINVAL : 0;
+}
+module_init(test_meminit_init);
--
2.21.0.1020.gf2820cf01a-goog
next prev parent reply other threads:[~2019-05-14 14:36 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20190514143537.10435-1-glider@google.com>
2019-05-14 14:35 ` [PATCH v2 1/4] mm: security: introduce init_on_alloc=1 and init_on_free=1 boot options Alexander Potapenko
2019-05-16 16:19 ` Kees Cook
2019-05-16 16:42 ` Alexander Potapenko
2019-05-16 17:03 ` Kees Cook
2019-05-17 1:26 ` Kees Cook
2019-05-17 14:38 ` Alexander Potapenko
2019-05-17 14:04 ` Michal Hocko
2019-05-17 14:11 ` Alexander Potapenko
2019-05-17 14:20 ` Michal Hocko
2019-05-17 16:36 ` Kees Cook
2019-05-17 17:11 ` Michal Hocko
2019-05-14 14:35 ` Alexander Potapenko [this message]
2019-05-16 1:02 ` [PATCH v2 2/4] lib: introduce test_meminit module Kees Cook
2019-05-17 15:51 ` Alexander Potapenko
2019-05-17 16:37 ` Kees Cook
2019-05-14 14:35 ` [PATCH v2 3/4] gfp: mm: introduce __GFP_NO_AUTOINIT Alexander Potapenko
2019-05-17 12:59 ` Michal Hocko
2019-05-17 13:18 ` Alexander Potapenko
2019-05-17 13:25 ` Michal Hocko
2019-05-17 13:37 ` Alexander Potapenko
2019-05-17 14:01 ` Michal Hocko
2019-05-17 16:27 ` Kees Cook
2019-05-17 17:11 ` Michal Hocko
2019-05-21 14:18 ` Alexander Potapenko
2019-05-21 14:25 ` Michal Hocko
2019-05-14 14:35 ` [PATCH v2 4/4] net: apply __GFP_NO_AUTOINIT to AF_UNIX sk_buff allocations Alexander Potapenko
2019-05-16 16:53 ` Kees Cook
2019-05-17 0:26 ` Kees Cook
2019-05-17 8:49 ` Alexander Potapenko
2019-05-17 13:50 ` Alexander Potapenko
2019-05-17 16:13 ` Kees Cook
2019-05-17 0:50 ` [PATCH 5/4] mm: Introduce SLAB_NO_FREE_INIT and mark excluded caches Kees Cook
2019-05-17 8:34 ` Alexander Potapenko
2019-05-17 15:59 ` Kees Cook
2019-05-20 6:10 ` Mathias Krause
2019-05-20 16:12 ` 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=20190514143537.10435-3-glider@google.com \
--to=glider@google.com \
--cc=akpm@linux-foundation.org \
--cc=cl@linux.com \
--cc=dvyukov@google.com \
--cc=jannh@google.com \
--cc=kcc@google.com \
--cc=keescook@chromium.org \
--cc=kernel-hardening@lists.openwall.com \
--cc=labbott@redhat.com \
--cc=linux-mm@kvack.org \
--cc=linux-security-module@vger.kernel.org \
--cc=ndesaulniers@google.com \
--cc=sspatil@android.com \
/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