The longest length of a symbol (KSYM_NAME_LEN) was increased to 512 in the reference [1]. This patch adds kunit test suite to check the longest symbol length. These tests verify that the longest symbol length defined is supported.
This test can also help other efforts for longer symbol length, like [2].
The test suite defines one symbol with the longest possible length.
The first test verify that functions with names of the created symbol, can be called or not.
The second test, verify that the symbols are created (or not) in the kernel symbol table.
[1] https://lore.kernel.org/lkml/20220802015052.10452-6-ojeda@kernel.org/ [2] https://lore.kernel.org/lkml/20240605032120.3179157-1-song@kernel.org/
Tested-by: Martin Rodriguez Reboredo yakoyoku@gmail.com Reviewed-by: Shuah Khan skhan@linuxfoundation.org Signed-off-by: Sergio González Collado sergio.collado@gmail.com Link: https://github.com/Rust-for-Linux/linux/issues/504 --- V5 -> V6: remove tests with symbols of length KSYM_NAME_LEN+1 --- V4 -> V5: fixed typo, added improved description --- V3 -> V4: add x86 mantainers, add new reference. --- V2 -> V3: updated base and added MODULE_DESCRIPTION() and MODULE_AUTHOR() --- V1 -> V2: corrected CI tests. Added fix proposed at [3]
[3] https://lore.kernel.org/lkml/Y9ES4UKl%2F+DtvAVS@gmail.com/T/#m3ef0e12bb834d0...
The test execution should result in something like: ``` [20:04:35] =============== longest-symbol (4 subtests) ================ [20:04:35] [PASSED] test_longest_symbol [20:04:35] [PASSED] test_longest_symbol_kallsyms [20:04:35] ================= [PASSED] longest-symbol ================== [20:04:35] ============================================================ [20:04:35] Testing complete. Ran 4 tests: passed: 4 ``` --- arch/x86/tools/insn_decoder_test.c | 3 +- lib/Kconfig.debug | 9 ++++ lib/Makefile | 2 + lib/longest_symbol_kunit.c | 84 ++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 lib/longest_symbol_kunit.c
diff --git a/arch/x86/tools/insn_decoder_test.c b/arch/x86/tools/insn_decoder_test.c index 472540aeabc2..3bde35ea4188 100644 --- a/arch/x86/tools/insn_decoder_test.c +++ b/arch/x86/tools/insn_decoder_test.c @@ -10,6 +10,7 @@ #include <assert.h> #include <unistd.h> #include <stdarg.h> +#include <linux/kallsysms.h>
#define unlikely(cond) (cond)
@@ -106,7 +107,7 @@ static void parse_args(int argc, char **argv) } }
-#define BUFSIZE 256 +#define BUFSIZE (256 + KSYM_NAME_LEN)
int main(int argc, char **argv) { diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5f1874622175..4c3a61862281 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2828,6 +2828,15 @@ config FORTIFY_KUNIT_TEST by the str*() and mem*() family of functions. For testing runtime traps of FORTIFY_SOURCE, see LKDTM's "FORTIFY_*" tests.
+config LONGEST_SYM_KUNIT_TEST + tristate "Test the longest symbol possible" if !KUNIT_ALL_TESTS + depends on KUNIT && KPROBES + default KUNIT_ALL_TESTS + help + Tests the longest symbol possible + + If unsure, say N. + config HW_BREAKPOINT_KUNIT_TEST bool "Test hw_breakpoint constraints accounting" if !KUNIT_ALL_TESTS depends on HAVE_HW_BREAKPOINT diff --git a/lib/Makefile b/lib/Makefile index d5cfc7afbbb8..e8fec9defec2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -393,6 +393,8 @@ obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o obj-$(CONFIG_CRC_KUNIT_TEST) += crc_kunit.o obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o +obj-$(CONFIG_LONGEST_SYM_KUNIT_TEST) += longest_symbol_kunit.o +CFLAGS_longest_symbol_kunit.o += $(call cc-disable-warning, missing-prototypes)
obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
diff --git a/lib/longest_symbol_kunit.c b/lib/longest_symbol_kunit.c new file mode 100644 index 000000000000..38ae117647e4 --- /dev/null +++ b/lib/longest_symbol_kunit.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test the longest symbol length. Execute with: + * ./tools/testing/kunit/kunit.py run longest-symbol + * --arch=x86_64 --kconfig_add CONFIG_KPROBES=y --kconfig_add CONFIG_MODULES=y + * --kconfig_add CONFIG_RETPOLINE=n --kconfig_add CONFIG_CFI_CLANG=n + * --kconfig_add CONFIG_MITIGATION_RETPOLINE=n + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <kunit/test.h> +#include <linux/stringify.h> +#include <linux/kprobes.h> +#include <linux/kallsyms.h> + +#define DI(name) s##name##name +#define DDI(name) DI(n##name##name) +#define DDDI(name) DDI(n##name##name) +#define DDDDI(name) DDDI(n##name##name) +#define DDDDDI(name) DDDDI(n##name##name) + +#define PLUS1(name) __PASTE(name, e) + +/*Generate a symbol whose name length is 511 */ +#define LONGEST_SYM_NAME DDDDDI(g1h2i3j4k5l6m7n) + +#define RETURN_LONGEST_SYM 0xAAAAA + +noinline int LONGEST_SYM_NAME(void); +noinline int LONGEST_SYM_NAME(void) +{ + return RETURN_LONGEST_SYM; +} + +_Static_assert(sizeof(__stringify(LONGEST_SYM_NAME)) == KSYM_NAME_LEN, +"Incorrect symbol length found. Expected KSYM_NAME_LEN: " +__stringify(KSYM_NAME) ", but found: " +__stringify(sizeof(LONGEST_SYM_NAME))); + +static void test_longest_symbol(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, RETURN_LONGEST_SYM, LONGEST_SYM_NAME()); +}; + +static void test_longest_symbol_kallsyms(struct kunit *test) +{ + unsigned long (*kallsyms_lookup_name)(const char *name); + static int (*longest_sym)(void); + + struct kprobe kp = { + .symbol_name = "kallsyms_lookup_name", + }; + + if (register_kprobe(&kp) < 0) { + pr_info("%s: kprobe not registered\n", __func__); + KUNIT_FAIL(test, "test_longest_symbol kallsysms: kprobe not registered\n"); + return; + } + + kunit_warn(test, "test_longest_symbol kallsyms: kprobe registered\n"); + kallsyms_lookup_name = (unsigned long (*)(const char *name))kp.addr; + unregister_kprobe(&kp); + + longest_sym = + (void *) kallsyms_lookup_name(__stringify(LONGEST_SYM_NAME)); + KUNIT_EXPECT_EQ(test, RETURN_LONGEST_SYM, longest_sym()); +}; + +static struct kunit_case longest_symbol_test_cases[] = { + KUNIT_CASE(test_longest_symbol), + KUNIT_CASE(test_longest_symbol_kallsyms), + {} +}; + +static struct kunit_suite longest_symbol_test_suite = { + .name = "longest-symbol", + .test_cases = longest_symbol_test_cases, +}; +kunit_test_suite(longest_symbol_test_suite); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Test the longest symbol length"); +MODULE_AUTHOR("Sergio González Collado");
On Sun, Jan 26, 2025 at 5:36 PM Sergio González Collado sergio.collado@gmail.com wrote:
The longest length of a symbol (KSYM_NAME_LEN) was increased to 512 in the reference [1]. This patch adds kunit test suite to check the longest symbol length. These tests verify that the longest symbol length defined is supported.
This test can also help other efforts for longer symbol length, like [2].
The test suite defines one symbol with the longest possible length.
The first test verify that functions with names of the created symbol, can be called or not.
The second test, verify that the symbols are created (or not) in the kernel symbol table.
[1] https://lore.kernel.org/lkml/20220802015052.10452-6-ojeda@kernel.org/ [2] https://lore.kernel.org/lkml/20240605032120.3179157-1-song@kernel.org/
Tested-by: Martin Rodriguez Reboredo yakoyoku@gmail.com Reviewed-by: Shuah Khan skhan@linuxfoundation.org Signed-off-by: Sergio González Collado sergio.collado@gmail.com Link: https://github.com/Rust-for-Linux/linux/issues/504
Hi Sergio!
Thanks for sending another version of this test. This now looks good to me! The test passes both built-in to the kernel and loaded as a module.
Happy to take this patch though the kselftest/kunit branch. However this patch does not cleanly apply to that branch right now. There are just a few lines in lib/Makefile that differ. It would be an easy fix of rebasing the patch and sending out a new version. Or would you prefer sending it through another branch? Let me know.
But other than the need to rebase, this patch looks good to me:
Reviewed-by: Rae Moar rmoar@google.com
Thanks! -Rae
V5 -> V6: remove tests with symbols of length KSYM_NAME_LEN+1
V4 -> V5: fixed typo, added improved description
V3 -> V4: add x86 mantainers, add new reference.
V2 -> V3: updated base and added MODULE_DESCRIPTION() and MODULE_AUTHOR()
V1 -> V2: corrected CI tests. Added fix proposed at [3]
[3] https://lore.kernel.org/lkml/Y9ES4UKl%2F+DtvAVS@gmail.com/T/#m3ef0e12bb834d0...
The test execution should result in something like:
[20:04:35] =============== longest-symbol (4 subtests) ================ [20:04:35] [PASSED] test_longest_symbol [20:04:35] [PASSED] test_longest_symbol_kallsyms [20:04:35] ================= [PASSED] longest-symbol ================== [20:04:35] ============================================================ [20:04:35] Testing complete. Ran 4 tests: passed: 4
arch/x86/tools/insn_decoder_test.c | 3 +- lib/Kconfig.debug | 9 ++++ lib/Makefile | 2 + lib/longest_symbol_kunit.c | 84 ++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 lib/longest_symbol_kunit.c
diff --git a/arch/x86/tools/insn_decoder_test.c b/arch/x86/tools/insn_decoder_test.c index 472540aeabc2..3bde35ea4188 100644 --- a/arch/x86/tools/insn_decoder_test.c +++ b/arch/x86/tools/insn_decoder_test.c @@ -10,6 +10,7 @@ #include <assert.h> #include <unistd.h> #include <stdarg.h> +#include <linux/kallsysms.h>
#define unlikely(cond) (cond)
@@ -106,7 +107,7 @@ static void parse_args(int argc, char **argv) } }
-#define BUFSIZE 256 +#define BUFSIZE (256 + KSYM_NAME_LEN)
int main(int argc, char **argv) { diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5f1874622175..4c3a61862281 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2828,6 +2828,15 @@ config FORTIFY_KUNIT_TEST by the str*() and mem*() family of functions. For testing runtime traps of FORTIFY_SOURCE, see LKDTM's "FORTIFY_*" tests.
+config LONGEST_SYM_KUNIT_TEST
tristate "Test the longest symbol possible" if !KUNIT_ALL_TESTS
depends on KUNIT && KPROBES
default KUNIT_ALL_TESTS
help
Tests the longest symbol possible
If unsure, say N.
config HW_BREAKPOINT_KUNIT_TEST bool "Test hw_breakpoint constraints accounting" if !KUNIT_ALL_TESTS depends on HAVE_HW_BREAKPOINT diff --git a/lib/Makefile b/lib/Makefile index d5cfc7afbbb8..e8fec9defec2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -393,6 +393,8 @@ obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o obj-$(CONFIG_CRC_KUNIT_TEST) += crc_kunit.o obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o +obj-$(CONFIG_LONGEST_SYM_KUNIT_TEST) += longest_symbol_kunit.o +CFLAGS_longest_symbol_kunit.o += $(call cc-disable-warning, missing-prototypes)
obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
diff --git a/lib/longest_symbol_kunit.c b/lib/longest_symbol_kunit.c new file mode 100644 index 000000000000..38ae117647e4 --- /dev/null +++ b/lib/longest_symbol_kunit.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Test the longest symbol length. Execute with:
- ./tools/testing/kunit/kunit.py run longest-symbol
- --arch=x86_64 --kconfig_add CONFIG_KPROBES=y --kconfig_add CONFIG_MODULES=y
- --kconfig_add CONFIG_RETPOLINE=n --kconfig_add CONFIG_CFI_CLANG=n
- --kconfig_add CONFIG_MITIGATION_RETPOLINE=n
- */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <kunit/test.h> +#include <linux/stringify.h> +#include <linux/kprobes.h> +#include <linux/kallsyms.h>
+#define DI(name) s##name##name +#define DDI(name) DI(n##name##name) +#define DDDI(name) DDI(n##name##name) +#define DDDDI(name) DDDI(n##name##name) +#define DDDDDI(name) DDDDI(n##name##name)
+#define PLUS1(name) __PASTE(name, e)
+/*Generate a symbol whose name length is 511 */ +#define LONGEST_SYM_NAME DDDDDI(g1h2i3j4k5l6m7n)
+#define RETURN_LONGEST_SYM 0xAAAAA
+noinline int LONGEST_SYM_NAME(void); +noinline int LONGEST_SYM_NAME(void) +{
return RETURN_LONGEST_SYM;
+}
+_Static_assert(sizeof(__stringify(LONGEST_SYM_NAME)) == KSYM_NAME_LEN, +"Incorrect symbol length found. Expected KSYM_NAME_LEN: " +__stringify(KSYM_NAME) ", but found: " +__stringify(sizeof(LONGEST_SYM_NAME)));
+static void test_longest_symbol(struct kunit *test) +{
KUNIT_EXPECT_EQ(test, RETURN_LONGEST_SYM, LONGEST_SYM_NAME());
+};
+static void test_longest_symbol_kallsyms(struct kunit *test) +{
unsigned long (*kallsyms_lookup_name)(const char *name);
static int (*longest_sym)(void);
struct kprobe kp = {
.symbol_name = "kallsyms_lookup_name",
};
if (register_kprobe(&kp) < 0) {
pr_info("%s: kprobe not registered\n", __func__);
KUNIT_FAIL(test, "test_longest_symbol kallsysms: kprobe not registered\n");
return;
}
kunit_warn(test, "test_longest_symbol kallsyms: kprobe registered\n");
kallsyms_lookup_name = (unsigned long (*)(const char *name))kp.addr;
unregister_kprobe(&kp);
longest_sym =
(void *) kallsyms_lookup_name(__stringify(LONGEST_SYM_NAME));
KUNIT_EXPECT_EQ(test, RETURN_LONGEST_SYM, longest_sym());
+};
+static struct kunit_case longest_symbol_test_cases[] = {
KUNIT_CASE(test_longest_symbol),
KUNIT_CASE(test_longest_symbol_kallsyms),
{}
+};
+static struct kunit_suite longest_symbol_test_suite = {
.name = "longest-symbol",
.test_cases = longest_symbol_test_cases,
+}; +kunit_test_suite(longest_symbol_test_suite);
+MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Test the longest symbol length");
+MODULE_AUTHOR("Sergio González Collado");
2.39.2
On Sun, Jan 26, 2025 at 11:36 PM Sergio González Collado sergio.collado@gmail.com wrote:
+#include <linux/kallsysms.h>
Typo?
Cheers, Miguel
Hello
+#include <linux/kallsysms.h>
Typo?
#include <linux/kallsysms.h> is needed to be able to read KSYM_NAME_LEN: https://elixir.bootlin.com/linux/v6.13/source/include/linux/kallsyms.h#L18
In the file insn_decoder_test.c, is added otherwise, when configuring that test with CONFIG_X86_DECODER_SELFTEST, you would get the error ``` arch/x86/tools/insn_decoder_test.c:110:24: error: ‘KSYM_NAME_LEN’ undeclared (first use in this function) 110 | #define BUFSIZE (256 + KSYM_NAME_LEN) ``` This was proposed here: https://lore.kernel.org/lkml/Y9ES4UKl%2F+DtvAVS@gmail.com/
Cheers, Sergio
Sergio
On Tue, Jan 28, 2025 at 1:24 PM Sergio González Collado sergio.collado@gmail.com wrote:
+#include <linux/kallsysms.h>
Typo?
#include <linux/kallsysms.h> is needed to be able to read KSYM_NAME_LEN: https://elixir.bootlin.com/linux/v6.13/source/include/linux/kallsyms.h#L18
What I meant is that the `#include` in the patch is:
kallsysms.h
which is different from:
kallsyms.h
Does that file build? Or am I missing something?
I just tried, and I indeed get:
HOSTCC arch/x86/tools/insn_decoder_test arch/x86/tools/insn_decoder_test.c:13:10: fatal error: 'linux/kallsysms.h' file not found 13 | #include <linux/kallsysms.h> | ^~~~~~~~~~~~~~~~~~~ 1 error generated.
Thanks!
Cheers, Miguel
On Tue, Jan 28, 2025 at 3:56 PM Miguel Ojeda miguel.ojeda.sandonis@gmail.com wrote:
On Tue, Jan 28, 2025 at 1:24 PM Sergio González Collado sergio.collado@gmail.com wrote:
+#include <linux/kallsysms.h>
Typo?
#include <linux/kallsysms.h> is needed to be able to read KSYM_NAME_LEN: https://elixir.bootlin.com/linux/v6.13/source/include/linux/kallsyms.h#L18
What I meant is that the `#include` in the patch is:
kallsysms.h
which is different from:
kallsyms.h
Does that file build? Or am I missing something?
I just tried, and I indeed get:
HOSTCC arch/x86/tools/insn_decoder_test arch/x86/tools/insn_decoder_test.c:13:10: fatal error:
'linux/kallsysms.h' file not found 13 | #include <linux/kallsysms.h> | ^~~~~~~~~~~~~~~~~~~ 1 error generated.
Thanks!
Cheers, Miguel
Hi!
Oh yep definitely missed that typo. Thanks for catching this!
Thanks! -Rae
-- You received this message because you are subscribed to the Google Groups "KUnit Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+unsubscribe@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/kunit-dev/CANiq72kXG4qURXjnZZTLPMn-k_WwFt0....
linux-kselftest-mirror@lists.linaro.org