kprobes: add testcases for s390
authorSven Schnelle <svens@linux.ibm.com>
Thu, 9 Sep 2021 18:59:17 +0000 (20:59 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Mon, 4 Oct 2021 07:49:37 +0000 (09:49 +0200)
Add a few testcases to make sure that it's not possible to place
a kprobe in the mid of an instruction on s390.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Acked-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/Kconfig
arch/s390/configs/debug_defconfig
arch/s390/lib/Makefile
arch/s390/lib/test_kprobes.c [new file with mode: 0644]
arch/s390/lib/test_kprobes.h [new file with mode: 0644]
arch/s390/lib/test_kprobes_asm.S [new file with mode: 0644]

index b86de61b8caa2f2909b4c569c3f574942c07652a..4d63662a919df87d4c5174f0c69c6d25bb4db09d 100644 (file)
@@ -946,4 +946,16 @@ config S390_UNWIND_SELFTEST
 
          Say N if you are unsure.
 
+config S390_KPROBES_SANITY_TEST
+       def_tristate n
+       prompt "Enable s390 specific kprobes tests"
+       depends on KPROBES
+       depends on KUNIT
+       help
+         This option enables an s390 specific kprobes test module. This option
+         is not useful for distributions or general kernels, but only for kernel
+         developers working on architecture code.
+
+         Say N if you are unsure.
+
 endmenu
index 6aad18ee131d6634efd7188b9660d723f2ea36a6..1818d67c2c1c4f2f24643a38be02f407a21701ab 100644 (file)
@@ -62,6 +62,7 @@ CONFIG_CMM=m
 CONFIG_APPLDATA_BASE=y
 CONFIG_KVM=m
 CONFIG_S390_UNWIND_SELFTEST=y
+CONFIG_S390_KPROBES_SANITY_TEST=y
 CONFIG_KPROBES=y
 CONFIG_JUMP_LABEL=y
 CONFIG_STATIC_KEYS_SELFTEST=y
index 678333936f78ca881a6850e98da6f2d28e2aefb6..707cd4622c132d509e71e8d55a48cd2d314858fa 100644 (file)
@@ -7,6 +7,8 @@ lib-y += delay.o string.o uaccess.o find.o spinlock.o
 obj-y += mem.o xor.o
 lib-$(CONFIG_KPROBES) += probes.o
 lib-$(CONFIG_UPROBES) += probes.o
+obj-$(CONFIG_S390_KPROBES_SANITY_TEST) += test_kprobes_s390.o
+test_kprobes_s390-objs += test_kprobes_asm.o test_kprobes.o
 
 # Instrumenting memory accesses to __user data (in different address space)
 # produce false positives
diff --git a/arch/s390/lib/test_kprobes.c b/arch/s390/lib/test_kprobes.c
new file mode 100644 (file)
index 0000000..9e62d62
--- /dev/null
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/random.h>
+#include <kunit/test.h>
+#include "test_kprobes.h"
+
+static struct kprobe kp;
+
+static void setup_kprobe(struct kunit *test, struct kprobe *kp,
+                        const char *symbol, int offset)
+{
+       kp->offset = offset;
+       kp->addr = NULL;
+       kp->symbol_name = symbol;
+}
+
+static void test_kprobe_offset(struct kunit *test, struct kprobe *kp,
+                              const char *target, int offset)
+{
+       int ret;
+
+       setup_kprobe(test, kp, target, 0);
+       ret = register_kprobe(kp);
+       if (!ret)
+               unregister_kprobe(kp);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       setup_kprobe(test, kp, target, offset);
+       ret = register_kprobe(kp);
+       KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+       if (!ret)
+               unregister_kprobe(kp);
+}
+
+static void test_kprobe_odd(struct kunit *test)
+{
+       test_kprobe_offset(test, &kp, "kprobes_target_odd",
+                          kprobes_target_odd_offs);
+}
+
+static void test_kprobe_in_insn4(struct kunit *test)
+{
+       test_kprobe_offset(test, &kp, "kprobes_target_in_insn4",
+                          kprobes_target_in_insn4_offs);
+}
+
+static void test_kprobe_in_insn6_lo(struct kunit *test)
+{
+       test_kprobe_offset(test, &kp, "kprobes_target_in_insn6_lo",
+                          kprobes_target_in_insn6_lo_offs);
+}
+
+static void test_kprobe_in_insn6_hi(struct kunit *test)
+{
+       test_kprobe_offset(test, &kp, "kprobes_target_in_insn6_hi",
+                          kprobes_target_in_insn6_hi_offs);
+}
+
+static struct kunit_case kprobes_testcases[] = {
+       KUNIT_CASE(test_kprobe_odd),
+       KUNIT_CASE(test_kprobe_in_insn4),
+       KUNIT_CASE(test_kprobe_in_insn6_lo),
+       KUNIT_CASE(test_kprobe_in_insn6_hi),
+       {}
+};
+
+static struct kunit_suite kprobes_test_suite = {
+       .name = "kprobes_test_s390",
+       .test_cases = kprobes_testcases,
+};
+
+kunit_test_suites(&kprobes_test_suite);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/s390/lib/test_kprobes.h b/arch/s390/lib/test_kprobes.h
new file mode 100644 (file)
index 0000000..2b4c9bc
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef TEST_KPROBES_H
+#define TEST_KPROBES_H
+
+extern unsigned long kprobes_target_odd_offs;
+extern unsigned long kprobes_target_in_insn4_offs;
+extern unsigned long kprobes_target_in_insn6_lo_offs;
+extern unsigned long kprobes_target_in_insn6_hi_offs;
+
+#endif
diff --git a/arch/s390/lib/test_kprobes_asm.S b/arch/s390/lib/test_kprobes_asm.S
new file mode 100644 (file)
index 0000000..ade7a30
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#include <linux/linkage.h>
+#include <asm/ftrace.h>
+
+#define KPROBES_TARGET_START(name)     \
+       SYM_FUNC_START(name);           \
+       FTRACE_GEN_NOP_ASM(name)
+
+#define KPROBES_TARGET_END(name)       \
+       SYM_FUNC_END(name);             \
+       SYM_DATA(name##_offs, .quad 1b - name)
+
+KPROBES_TARGET_START(kprobes_target_in_insn4)
+       .word 0x4700 // bc 0,0
+1:     .word 0x0000
+       br %r14
+KPROBES_TARGET_END(kprobes_target_in_insn4)
+
+KPROBES_TARGET_START(kprobes_target_in_insn6_lo)
+       .word 0xe310 // ly 1,0
+1:     .word 0x0000
+       .word 0x0058
+       br %r14
+KPROBES_TARGET_END(kprobes_target_in_insn6_lo)
+
+KPROBES_TARGET_START(kprobes_target_in_insn6_hi)
+       .word 0xe310 // ly 1,0
+       .word 0x0000
+1:     .word 0x0058
+       br %r14
+KPROBES_TARGET_END(kprobes_target_in_insn6_hi)
+
+KPROBES_TARGET_START(kprobes_target_bp)
+       nop
+       .word 0x0000
+       nop
+1:     br %r14
+KPROBES_TARGET_END(kprobes_target_bp)
+
+KPROBES_TARGET_START(kprobes_target_odd)
+       .byte 0x07
+1:     .byte 0x07
+       br %r14
+KPROBES_TARGET_END(kprobes_target_odd)