The address printed by %p in the kernel will expose the kernel address information, which is extremely unsafe. So Linux v4.15 limited the information printed by %p which will print a hashed value.
This patchset add no_hash_pointers startup parameter which can disable the restriction that %P only prints hashed values, so that %P can print the actual address in the kernel. I patched this function and the test modules associated with this and passed these tests after recompiling.
Tobin C. Harding (3): lib/test_printf: Add empty module_exit function kselftest: Add test module framework header lib: Use new kselftest header
Timur Tabi(3): kselftest: add support for skipped tests lib: use KSTM_MODULE_GLOBALS macro in kselftest drivers lib/vsprintf: no_hash_pointers prints all addresses as unhashed
.../admin-guide/kernel-parameters.txt | 15 +++ Documentation/dev-tools/kselftest.rst | 94 +++++++++++++++++- lib/test_bitmap.c | 23 +---- lib/test_printf.c | 29 +++--- lib/vsprintf.c | 36 ++++++- tools/testing/selftests/kselftest_module.h | 54 ++++++++++ 6 files changed, 215 insertions(+), 36 deletions(-) create mode 100644 tools/testing/selftests/kselftest_module.h
From: "Tobin C. Harding" tobin@kernel.org
mainline inclusion from mainline-v5.1-rc4 commit 6989808ee7636188cc091224bc76ab8e1696088a category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4BUC2 CVE: NA -----------------------------------------------------
Currently the test_printf module does not have an exit function, this prevents the module from being unloaded. If we cannot unload the module we cannot run the tests a second time.
Add an empty exit function.
Acked-by: Kees Cook keescook@chromium.org Signed-off-by: Tobin C. Harding tobin@kernel.org Signed-off-by: Shuah Khan shuah@kernel.org Signed-off-by: He Jinjin jinjin@isrc.iscas.ac.cn --- lib/test_printf.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/lib/test_printf.c b/lib/test_printf.c index 659b6cc0d483..601e8519319a 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -615,5 +615,11 @@ test_printf_init(void)
module_init(test_printf_init);
+static void __exit test_printf_exit(void) +{ +} + +module_exit(test_printf_exit); + MODULE_AUTHOR("Rasmus Villemoes linux@rasmusvillemoes.dk"); MODULE_LICENSE("GPL");
From: "Tobin C. Harding" tobin@kernel.org
mainline inclusion from mainline-v5.1-rc4 commit eebf4dd452377921e3a2635f0f5df2042470faef category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4BUC2 CVE: NA -----------------------------------------------------
kselftest runs as a userspace process. Sometimes we need to test things from kernel space. One way of doing this is by creating a test module. Currently doing so requires developers to write a bunch of boiler plate in the module if kselftest is to be used to run the tests. This means we currently have a load of duplicate code to achieve these ends. If we have a uniform method for implementing test modules then we can reduce code duplication, ensure uniformity in the test framework, ease code maintenance, and reduce the work required to create tests. This all helps to encourage developers to write and run tests.
Add a C header file that can be included in test modules. This provides a single point for common test functions/macros. Implement a few macros that make up the start of the test framework.
Add documentation for new kselftest header to kselftest documentation.
Acked-by: Kees Cook keescook@chromium.org Signed-off-by: Tobin C. Harding tobin@kernel.org Signed-off-by: Shuah Khan shuah@kernel.org Signed-off-by: He Jinjin jinjin@isrc.iscas.ac.cn --- Documentation/dev-tools/kselftest.rst | 94 +++++++++++++++++++++- tools/testing/selftests/kselftest_module.h | 48 +++++++++++ 2 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/kselftest_module.h
diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst index 6f653acea248..77c509ffef4a 100644 --- a/Documentation/dev-tools/kselftest.rst +++ b/Documentation/dev-tools/kselftest.rst @@ -14,6 +14,10 @@ in safe mode with a limited scope. In limited mode, cpu-hotplug test is run on a single cpu as opposed to all hotplug capable cpus, and memory hotplug test is run on 2% of hotplug capable memory instead of 10%.
+kselftest runs as a userspace process. Tests that can be written/run in +userspace may wish to use the `Test Harness`_. Tests that need to be +run in kernel space may wish to use a `Test Module`_. + Running the selftests (hotplug tests are run in limited mode) =============================================================
@@ -161,11 +165,97 @@ Contributing new tests (details)
e.g: tools/testing/selftests/android/ion/config
+Test Module +=========== + +Kselftest tests the kernel from userspace. Sometimes things need +testing from within the kernel, one method of doing this is to create a +test module. We can tie the module into the kselftest framework by +using a shell script test runner. ``kselftest_module.sh`` is designed +to facilitate this process. There is also a header file provided to +assist writing kernel modules that are for use with kselftest: + +- ``tools/testing/kselftest/kselftest_module.h`` +- ``tools/testing/kselftest/kselftest_module.sh`` + +How to use +---------- + +Here we show the typical steps to create a test module and tie it into +kselftest. We use kselftests for lib/ as an example. + +1. Create the test module + +2. Create the test script that will run (load/unload) the module + e.g. ``tools/testing/selftests/lib/printf.sh`` + +3. Add line to config file e.g. ``tools/testing/selftests/lib/config`` + +4. Add test script to makefile e.g. ``tools/testing/selftests/lib/Makefile`` + +5. Verify it works: + +.. code-block:: sh + + # Assumes you have booted a fresh build of this kernel tree + cd /path/to/linux/tree + make kselftest-merge + make modules + sudo make modules_install + make TARGETS=lib kselftest + +Example Module +-------------- + +A bare bones test module might look like this: + +.. code-block:: c + + // SPDX-License-Identifier: GPL-2.0+ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include "../tools/testing/selftests/kselftest_module.h" + + KSTM_MODULE_GLOBALS(); + + /* + * Kernel module for testing the foobinator + */ + + static int __init test_function() + { + ... + } + + static void __init selftest(void) + { + KSTM_CHECK_ZERO(do_test_case("", 0)); + } + + KSTM_MODULE_LOADERS(test_foo); + MODULE_AUTHOR("John Developer jd@fooman.org"); + MODULE_LICENSE("GPL"); + +Example test script +------------------- + +.. code-block:: sh + + #!/bin/bash + # SPDX-License-Identifier: GPL-2.0+ + $(dirname $0)/../kselftest_module.sh "foo" test_foo + + Test Harness ============
-The kselftest_harness.h file contains useful helpers to build tests. The tests -from tools/testing/selftests/seccomp/seccomp_bpf.c can be used as example. +The kselftest_harness.h file contains useful helpers to build tests. The +test harness is for userspace testing, for kernel space testing see `Test +Module`_ above. + +The tests from tools/testing/selftests/seccomp/seccomp_bpf.c can be used as +example.
Example ------- diff --git a/tools/testing/selftests/kselftest_module.h b/tools/testing/selftests/kselftest_module.h new file mode 100644 index 000000000000..e8eafaf0941a --- /dev/null +++ b/tools/testing/selftests/kselftest_module.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#ifndef __KSELFTEST_MODULE_H +#define __KSELFTEST_MODULE_H + +#include <linux/module.h> + +/* + * Test framework for writing test modules to be loaded by kselftest. + * See Documentation/dev-tools/kselftest.rst for an example test module. + */ + +#define KSTM_MODULE_GLOBALS() \ +static unsigned int total_tests __initdata; \ +static unsigned int failed_tests __initdata + +#define KSTM_CHECK_ZERO(x) do { \ + total_tests++; \ + if (x) { \ + pr_warn("TC failed at %s:%d\n", __func__, __LINE__); \ + failed_tests++; \ + } \ +} while (0) + +static inline int kstm_report(unsigned int total_tests, unsigned int failed_tests) +{ + if (failed_tests == 0) + pr_info("all %u tests passed\n", total_tests); + else + pr_warn("failed %u out of %u tests\n", failed_tests, total_tests); + + return failed_tests ? -EINVAL : 0; +} + +#define KSTM_MODULE_LOADERS(__module) \ +static int __init __module##_init(void) \ +{ \ + pr_info("loaded.\n"); \ + selftest(); \ + return kstm_report(total_tests, failed_tests); \ +} \ +static void __exit __module##_exit(void) \ +{ \ + pr_info("unloaded.\n"); \ +} \ +module_init(__module##_init); \ +module_exit(__module##_exit) + +#endif /* __KSELFTEST_MODULE_H */
From: "Tobin C. Harding" tobin@kernel.org
mainline inclusion from mainline-v5.1-rc4 commit 6b1a4d5b1a26ae830d50e08d7b3ca0e8b3e6b453 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4BUC2 CVE: NA -----------------------------------------------------
We just added a new C header file for use with test modules that are intended to be run with kselftest. We can reduce code duplication by using this header.
Use new kselftest header to reduce code duplication in test_printf and test_bitmap test modules.
Acked-by: Kees Cook keescook@chromium.org Signed-off-by: Tobin C. Harding tobin@kernel.org Signed-off-by: Shuah Khan shuah@kernel.org Signed-off-by: He Jinjin jinjin@isrc.iscas.ac.cn --- lib/test_bitmap.c | 20 ++++---------------- lib/test_printf.c | 23 +++++------------------ 2 files changed, 9 insertions(+), 34 deletions(-)
diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index 6cd7d0740005..792d90608052 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -12,6 +12,8 @@ #include <linux/slab.h> #include <linux/string.h>
+#include "../tools/testing/selftests/kselftest_module.h" + static unsigned total_tests __initdata; static unsigned failed_tests __initdata;
@@ -361,7 +363,7 @@ static void noinline __init test_mem_optimisations(void) } }
-static int __init test_bitmap_init(void) +static void __init selftest(void) { test_zero_clear(); test_fill_set(); @@ -369,22 +371,8 @@ static int __init test_bitmap_init(void) test_bitmap_arr32(); test_bitmap_parselist(); test_mem_optimisations(); - - if (failed_tests == 0) - pr_info("all %u tests passed\n", total_tests); - else - pr_warn("failed %u out of %u tests\n", - failed_tests, total_tests); - - return failed_tests ? -EINVAL : 0; }
-static void __exit test_bitmap_cleanup(void) -{ -} - -module_init(test_bitmap_init); -module_exit(test_bitmap_cleanup); - +KSTM_MODULE_LOADERS(test_bitmap); MODULE_AUTHOR("david decotigny david.decotigny@googlers.com"); MODULE_LICENSE("GPL"); diff --git a/lib/test_printf.c b/lib/test_printf.c index 601e8519319a..f4fcc1c43739 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -21,6 +21,8 @@ #include <linux/gfp.h> #include <linux/mm.h>
+#include "../tools/testing/selftests/kselftest_module.h" + #define BUF_SIZE 256 #define PAD_SIZE 16 #define FILL_CHAR '$' @@ -590,12 +592,11 @@ test_pointer(void) flags(); }
-static int __init -test_printf_init(void) +static void __init selftest(void) { alloced_buffer = kmalloc(BUF_SIZE + 2*PAD_SIZE, GFP_KERNEL); if (!alloced_buffer) - return -ENOMEM; + return; test_buffer = alloced_buffer + PAD_SIZE;
test_basic(); @@ -604,22 +605,8 @@ test_printf_init(void) test_pointer();
kfree(alloced_buffer); - - if (failed_tests == 0) - pr_info("all %u tests passed\n", total_tests); - else - pr_warn("failed %u out of %u tests\n", failed_tests, total_tests); - - return failed_tests ? -EINVAL : 0; }
-module_init(test_printf_init); - -static void __exit test_printf_exit(void) -{ -} - -module_exit(test_printf_exit); - +KSTM_MODULE_LOADERS(test_printf); MODULE_AUTHOR("Rasmus Villemoes linux@rasmusvillemoes.dk"); MODULE_LICENSE("GPL");
From: Timur Tabi timur@kernel.org
mainline inclusion from mainline-v5.11-rc2 commit d9d4de2309cd1721421c6488f1bb5744d2c83a39 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4BUC2 CVE: NA -----------------------------------------------------
Update the kselftest framework to allow client drivers to specify that some tests were skipped.
Signed-off-by: Timur Tabi timur@kernel.org Reviewed-by: Petr Mladek pmladek@suse.com Tested-by: Petr Mladek pmladek@suse.com Acked-by: Marco Elver elver@google.com Signed-off-by: Petr Mladek pmladek@suse.com Signed-off-by: He Jinjin jinjin@isrc.iscas.ac.cn Link: https://lore.kernel.org/r/20210214161348.369023-3-timur@kernel.org --- tools/testing/selftests/kselftest_module.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/kselftest_module.h b/tools/testing/selftests/kselftest_module.h index e8eafaf0941aa..e2ea41de3f354 100644 --- a/tools/testing/selftests/kselftest_module.h +++ b/tools/testing/selftests/kselftest_module.h @@ -11,7 +11,8 @@
#define KSTM_MODULE_GLOBALS() \ static unsigned int total_tests __initdata; \ -static unsigned int failed_tests __initdata +static unsigned int failed_tests __initdata; \ +static unsigned int skipped_tests __initdata
#define KSTM_CHECK_ZERO(x) do { \ total_tests++; \ @@ -21,11 +22,16 @@ static unsigned int failed_tests __initdata } \ } while (0)
-static inline int kstm_report(unsigned int total_tests, unsigned int failed_tests) +static inline int kstm_report(unsigned int total_tests, unsigned int failed_tests, + unsigned int skipped_tests) { - if (failed_tests == 0) - pr_info("all %u tests passed\n", total_tests); - else + if (failed_tests == 0) { + if (skipped_tests) { + pr_info("skipped %u tests\n", skipped_tests); + pr_info("remaining %u tests passed\n", total_tests); + } else + pr_info("all %u tests passed\n", total_tests); + } else pr_warn("failed %u out of %u tests\n", failed_tests, total_tests);
return failed_tests ? -EINVAL : 0; @@ -36,7 +42,7 @@ static int __init __module##_init(void) \ { \ pr_info("loaded.\n"); \ selftest(); \ - return kstm_report(total_tests, failed_tests); \ + return kstm_report(total_tests, failed_tests, skipped_tests); \ } \ static void __exit __module##_exit(void) \ { \
From: Timur Tabi timur@kernel.org
mainline inclusion from mainline-v5.11-rc2 commit 4e89a78779647ca7ee2967551c599633fe9d3647 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4BUC2 CVE: NA -----------------------------------------------
Instead of defining the total/failed test counters manually, test drivers that are clients of kselftest should use the macro created for this purpose.
Signed-off-by: Timur Tabi timur@kernel.org Reviewed-by: Petr Mladek pmladek@suse.com Acked-by: Marco Elver elver@google.com Signed-off-by: Petr Mladek pmladek@suse.com Signed-off-by: He Jinjin jinjin@isrc.iscas.ac.cn Link: https://lore.kernel.org/r/20210214161348.369023-2-timur@kernel.org --- lib/test_bitmap.c | 3 +-- lib/test_printf.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index 4425a1dd4ef1c..0ea0e8258f14a 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -16,8 +16,7 @@
#include "../tools/testing/selftests/kselftest_module.h"
-static unsigned total_tests __initdata; -static unsigned failed_tests __initdata; +KSTM_MODULE_GLOBALS();
static char pbl_buffer[PAGE_SIZE] __initdata;
diff --git a/lib/test_printf.c b/lib/test_printf.c index 7ac87f18a10ff..ad2bcfa8caa12 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -30,8 +30,8 @@ #define PAD_SIZE 16 #define FILL_CHAR '$'
-static unsigned total_tests __initdata; -static unsigned failed_tests __initdata; +KSTM_MODULE_GLOBALS(); + static char *test_buffer __initdata; static char *alloced_buffer __initdata;
From: Timur Tabi timur@kernel.org
mainline inclusion from mainline-v5.11-rc2 commit 5ead723a20e0447bc7db33dc3070b420e5f80aa6 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4BUC2 CVE: NA -----------------------------------------------
If the no_hash_pointers command line parameter is set, then printk("%p") will print pointers as unhashed, which is useful for debugging purposes. This change applies to any function that uses vsprintf, such as print_hex_dump() and seq_buf_printf().
A large warning message is displayed if this option is enabled. Unhashed pointers expose kernel addresses, which can be a security risk.
Also update test_printf to skip the hashed pointer tests if the command-line option is set.
Signed-off-by: Timur Tabi timur@kernel.org Acked-by: Petr Mladek pmladek@suse.com Acked-by: Randy Dunlap rdunlap@infradead.org Acked-by: Sergey Senozhatsky sergey.senozhatsky@gmail.com Acked-by: Vlastimil Babka vbabka@suse.cz Acked-by: Marco Elver elver@google.com Signed-off-by: Petr Mladek pmladek@suse.com Signed-off-by: He Jinjin jinjin@isrc.iscas.ac.cn Link: https://lore.kernel.org/r/20210214161348.369023-4-timur@kernel.org --- Documentation/admin-guide/kernel-parameters.txt | 15 +++++++++++ lib/test_printf.c | 8 ++++++ lib/vsprintf.c | 36 +++++++++++++++++++++++-- 3 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index c722ec19cd004..c549bc7891083 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3281,6 +3281,21 @@ in certain environments such as networked servers or real-time systems.
+ no_hash_pointers + Force pointers printed to the console or buffers to be + unhashed. By default, when a pointer is printed via %p + format string, that pointer is "hashed", i.e. obscured + by hashing the pointer value. This is a security feature + that hides actual kernel addresses from unprivileged + users, but it also makes debugging the kernel more + difficult since unequal pointers can no longer be + compared. However, if this command-line option is + specified, then all normal pointers will have their true + value printed. Pointers printed via %pK may still be + hashed. This option should only be specified when + debugging the kernel. Please do not use on production + kernels. + nohibernate [HIBERNATION] Disable hibernation and resume.
nohz= [KNL] Boottime enable/disable dynamic ticks diff --git a/lib/test_printf.c b/lib/test_printf.c index ad2bcfa8caa12..a6755798e9e62 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -35,6 +35,8 @@ KSTM_MODULE_GLOBALS(); static char *test_buffer __initdata; static char *alloced_buffer __initdata;
+extern bool no_hash_pointers; + static int __printf(4, 0) __init do_test(int bufsize, const char *expect, int elen, const char *fmt, va_list ap) @@ -301,6 +303,12 @@ plain(void) { int err;
+ if (no_hash_pointers) { + pr_warn("skipping plain 'p' tests"); + skipped_tests += 2; + return; + } + err = plain_hash(); if (err) { pr_warn("plain 'p' does not appear to be hashed\n"); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index b3b44c2c8a92..a93a27775b66 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1861,6 +1861,32 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, return widen_string(buf, buf - buf_start, end, spec); }
+/* Disable pointer hashing if requested */ +bool no_hash_pointers __ro_after_init; +EXPORT_SYMBOL_GPL(no_hash_pointers); + +static int __init no_hash_pointers_enable(char *str) +{ + no_hash_pointers = true; + + pr_warn("**********************************************************\n"); + pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_warn("** **\n"); + pr_warn("** This system shows unhashed kernel memory addresses **\n"); + pr_warn("** via the console, logs, and other interfaces. This **\n"); + pr_warn("** might reduce the security of your system. **\n"); + pr_warn("** **\n"); + pr_warn("** If you see this message and you are not debugging **\n"); + pr_warn("** the kernel, report this immediately to your system **\n"); + pr_warn("** administrator! **\n"); + pr_warn("** **\n"); + pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_warn("**********************************************************\n"); + + return 0; +} +early_param("no_hash_pointers", no_hash_pointers_enable); + /* * Show a '%p' thing. A kernel extension is that the '%p' is followed * by an extra set of alphanumeric characters that are extended format @@ -2098,8 +2124,14 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, return pointer_string(buf, end, ptr, spec); }
- /* default is to _not_ leak addresses, hash before printing */ - return ptr_to_id(buf, end, ptr, spec); + /* + * default is to _not_ leak addresses, so hash before printing, + * unless no_hash_pointers is specified on the command line. + */ + if (unlikely(no_hash_pointers)) + return pointer_string(buf, end, ptr, spec); + else + return ptr_to_id(buf, end, ptr, spec); }
/*