cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

test_fprobe.c (4340B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * test_fprobe.c - simple sanity test for fprobe
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/fprobe.h>
      8#include <linux/random.h>
      9#include <kunit/test.h>
     10
     11#define div_factor 3
     12
     13static struct kunit *current_test;
     14
     15static u32 rand1, entry_val, exit_val;
     16
     17/* Use indirect calls to avoid inlining the target functions */
     18static u32 (*target)(u32 value);
     19static u32 (*target2)(u32 value);
     20static unsigned long target_ip;
     21static unsigned long target2_ip;
     22
     23static noinline u32 fprobe_selftest_target(u32 value)
     24{
     25	return (value / div_factor);
     26}
     27
     28static noinline u32 fprobe_selftest_target2(u32 value)
     29{
     30	return (value / div_factor) + 1;
     31}
     32
     33static notrace void fp_entry_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs)
     34{
     35	KUNIT_EXPECT_FALSE(current_test, preemptible());
     36	/* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */
     37	if (ip != target_ip)
     38		KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
     39	entry_val = (rand1 / div_factor);
     40}
     41
     42static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs)
     43{
     44	unsigned long ret = regs_return_value(regs);
     45
     46	KUNIT_EXPECT_FALSE(current_test, preemptible());
     47	if (ip != target_ip) {
     48		KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
     49		KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1);
     50	} else
     51		KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor));
     52	KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor));
     53	exit_val = entry_val + div_factor;
     54}
     55
     56/* Test entry only (no rethook) */
     57static void test_fprobe_entry(struct kunit *test)
     58{
     59	struct fprobe fp_entry = {
     60		.entry_handler = fp_entry_handler,
     61	};
     62
     63	current_test = test;
     64
     65	/* Before register, unregister should be failed. */
     66	KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry));
     67	KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL));
     68
     69	entry_val = 0;
     70	exit_val = 0;
     71	target(rand1);
     72	KUNIT_EXPECT_NE(test, 0, entry_val);
     73	KUNIT_EXPECT_EQ(test, 0, exit_val);
     74
     75	entry_val = 0;
     76	exit_val = 0;
     77	target2(rand1);
     78	KUNIT_EXPECT_NE(test, 0, entry_val);
     79	KUNIT_EXPECT_EQ(test, 0, exit_val);
     80
     81	KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry));
     82}
     83
     84static void test_fprobe(struct kunit *test)
     85{
     86	struct fprobe fp = {
     87		.entry_handler = fp_entry_handler,
     88		.exit_handler = fp_exit_handler,
     89	};
     90
     91	current_test = test;
     92	KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL));
     93
     94	entry_val = 0;
     95	exit_val = 0;
     96	target(rand1);
     97	KUNIT_EXPECT_NE(test, 0, entry_val);
     98	KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
     99
    100	entry_val = 0;
    101	exit_val = 0;
    102	target2(rand1);
    103	KUNIT_EXPECT_NE(test, 0, entry_val);
    104	KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
    105
    106	KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
    107}
    108
    109static void test_fprobe_syms(struct kunit *test)
    110{
    111	static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"};
    112	struct fprobe fp = {
    113		.entry_handler = fp_entry_handler,
    114		.exit_handler = fp_exit_handler,
    115	};
    116
    117	current_test = test;
    118	KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2));
    119
    120	entry_val = 0;
    121	exit_val = 0;
    122	target(rand1);
    123	KUNIT_EXPECT_NE(test, 0, entry_val);
    124	KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
    125
    126	entry_val = 0;
    127	exit_val = 0;
    128	target2(rand1);
    129	KUNIT_EXPECT_NE(test, 0, entry_val);
    130	KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
    131
    132	KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
    133}
    134
    135static unsigned long get_ftrace_location(void *func)
    136{
    137	unsigned long size, addr = (unsigned long)func;
    138
    139	if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size)
    140		return 0;
    141
    142	return ftrace_location_range(addr, addr + size - 1);
    143}
    144
    145static int fprobe_test_init(struct kunit *test)
    146{
    147	do {
    148		rand1 = prandom_u32();
    149	} while (rand1 <= div_factor);
    150
    151	target = fprobe_selftest_target;
    152	target2 = fprobe_selftest_target2;
    153	target_ip = get_ftrace_location(target);
    154	target2_ip = get_ftrace_location(target2);
    155
    156	return 0;
    157}
    158
    159static struct kunit_case fprobe_testcases[] = {
    160	KUNIT_CASE(test_fprobe_entry),
    161	KUNIT_CASE(test_fprobe),
    162	KUNIT_CASE(test_fprobe_syms),
    163	{}
    164};
    165
    166static struct kunit_suite fprobe_test_suite = {
    167	.name = "fprobe_test",
    168	.init = fprobe_test_init,
    169	.test_cases = fprobe_testcases,
    170};
    171
    172kunit_test_suites(&fprobe_test_suite);
    173
    174MODULE_LICENSE("GPL");