at master 8.6 kB view raw
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_only_val, entry_val, exit_val; 16static u32 entry_only_count, entry_count, exit_count; 17 18/* Use indirect calls to avoid inlining the target functions */ 19static u32 (*target)(u32 value); 20static u32 (*target2)(u32 value); 21static unsigned long target_ip; 22static unsigned long target2_ip; 23static int entry_return_value; 24 25static noinline u32 fprobe_selftest_target(u32 value) 26{ 27 return (value / div_factor); 28} 29 30static noinline u32 fprobe_selftest_target2(u32 value) 31{ 32 return (value / div_factor) + 1; 33} 34 35static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip, 36 unsigned long ret_ip, 37 struct ftrace_regs *fregs, void *data) 38{ 39 KUNIT_EXPECT_FALSE(current_test, preemptible()); 40 /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */ 41 if (ip != target_ip) 42 KUNIT_EXPECT_EQ(current_test, ip, target2_ip); 43 entry_val = (rand1 / div_factor); 44 if (fp->entry_data_size) { 45 KUNIT_EXPECT_NOT_NULL(current_test, data); 46 if (data) 47 *(u32 *)data = entry_val; 48 } else 49 KUNIT_EXPECT_NULL(current_test, data); 50 51 return entry_return_value; 52} 53 54static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, 55 unsigned long ret_ip, 56 struct ftrace_regs *fregs, void *data) 57{ 58 unsigned long ret = ftrace_regs_get_return_value(fregs); 59 60 KUNIT_EXPECT_FALSE(current_test, preemptible()); 61 if (ip != target_ip) { 62 KUNIT_EXPECT_EQ(current_test, ip, target2_ip); 63 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1); 64 } else 65 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor)); 66 KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor)); 67 exit_val = entry_val + div_factor; 68 if (fp->entry_data_size) { 69 KUNIT_EXPECT_NOT_NULL(current_test, data); 70 if (data) 71 KUNIT_EXPECT_EQ(current_test, *(u32 *)data, entry_val); 72 } else 73 KUNIT_EXPECT_NULL(current_test, data); 74} 75 76/* Test entry only (no rethook) */ 77static void test_fprobe_entry(struct kunit *test) 78{ 79 struct fprobe fp_entry = { 80 .entry_handler = fp_entry_handler, 81 }; 82 83 current_test = test; 84 85 /* Before register, unregister should be failed. */ 86 KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry)); 87 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL)); 88 89 entry_val = 0; 90 exit_val = 0; 91 target(rand1); 92 KUNIT_EXPECT_NE(test, 0, entry_val); 93 KUNIT_EXPECT_EQ(test, 0, exit_val); 94 95 entry_val = 0; 96 exit_val = 0; 97 target2(rand1); 98 KUNIT_EXPECT_NE(test, 0, entry_val); 99 KUNIT_EXPECT_EQ(test, 0, exit_val); 100 101 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry)); 102} 103 104static void test_fprobe(struct kunit *test) 105{ 106 struct fprobe fp = { 107 .entry_handler = fp_entry_handler, 108 .exit_handler = fp_exit_handler, 109 }; 110 111 current_test = test; 112 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL)); 113 114 entry_val = 0; 115 exit_val = 0; 116 target(rand1); 117 KUNIT_EXPECT_NE(test, 0, entry_val); 118 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 119 120 entry_val = 0; 121 exit_val = 0; 122 target2(rand1); 123 KUNIT_EXPECT_NE(test, 0, entry_val); 124 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 125 126 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 127} 128 129static void test_fprobe_syms(struct kunit *test) 130{ 131 static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"}; 132 struct fprobe fp = { 133 .entry_handler = fp_entry_handler, 134 .exit_handler = fp_exit_handler, 135 }; 136 137 current_test = test; 138 KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2)); 139 140 entry_val = 0; 141 exit_val = 0; 142 target(rand1); 143 KUNIT_EXPECT_NE(test, 0, entry_val); 144 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 145 146 entry_val = 0; 147 exit_val = 0; 148 target2(rand1); 149 KUNIT_EXPECT_NE(test, 0, entry_val); 150 KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); 151 152 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 153} 154 155/* Test private entry_data */ 156static void test_fprobe_data(struct kunit *test) 157{ 158 struct fprobe fp = { 159 .entry_handler = fp_entry_handler, 160 .exit_handler = fp_exit_handler, 161 .entry_data_size = sizeof(u32), 162 }; 163 164 current_test = test; 165 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL)); 166 167 target(rand1); 168 169 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 170} 171 172static void test_fprobe_skip(struct kunit *test) 173{ 174 struct fprobe fp = { 175 .entry_handler = fp_entry_handler, 176 .exit_handler = fp_exit_handler, 177 }; 178 179 current_test = test; 180 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL)); 181 182 entry_return_value = 1; 183 entry_val = 0; 184 exit_val = 0; 185 target(rand1); 186 KUNIT_EXPECT_NE(test, 0, entry_val); 187 KUNIT_EXPECT_EQ(test, 0, exit_val); 188 KUNIT_EXPECT_EQ(test, 0, fp.nmissed); 189 entry_return_value = 0; 190 191 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); 192} 193 194/* Handler for fprobe entry only case */ 195static notrace int entry_only_handler(struct fprobe *fp, unsigned long ip, 196 unsigned long ret_ip, 197 struct ftrace_regs *fregs, void *data) 198{ 199 KUNIT_EXPECT_FALSE(current_test, preemptible()); 200 KUNIT_EXPECT_EQ(current_test, ip, target_ip); 201 202 entry_only_count++; 203 entry_only_val = (rand1 / div_factor); 204 205 return 0; 206} 207 208static notrace int fprobe_entry_multi_handler(struct fprobe *fp, unsigned long ip, 209 unsigned long ret_ip, 210 struct ftrace_regs *fregs, 211 void *data) 212{ 213 KUNIT_EXPECT_FALSE(current_test, preemptible()); 214 KUNIT_EXPECT_EQ(current_test, ip, target_ip); 215 216 entry_count++; 217 entry_val = (rand1 / div_factor); 218 219 return 0; 220} 221 222static notrace void fprobe_exit_multi_handler(struct fprobe *fp, unsigned long ip, 223 unsigned long ret_ip, 224 struct ftrace_regs *fregs, 225 void *data) 226{ 227 unsigned long ret = ftrace_regs_get_return_value(fregs); 228 229 KUNIT_EXPECT_FALSE(current_test, preemptible()); 230 KUNIT_EXPECT_EQ(current_test, ip, target_ip); 231 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor)); 232 233 exit_count++; 234 exit_val = ret; 235} 236 237static void check_fprobe_multi(struct kunit *test) 238{ 239 entry_only_count = entry_count = exit_count = 0; 240 entry_only_val = entry_val = exit_val = 0; 241 242 target(rand1); 243 244 /* Verify all handlers were called */ 245 KUNIT_EXPECT_EQ(test, 1, entry_only_count); 246 KUNIT_EXPECT_EQ(test, 1, entry_count); 247 KUNIT_EXPECT_EQ(test, 1, exit_count); 248 249 /* Verify values are correct */ 250 KUNIT_EXPECT_EQ(test, (rand1 / div_factor), entry_only_val); 251 KUNIT_EXPECT_EQ(test, (rand1 / div_factor), entry_val); 252 KUNIT_EXPECT_EQ(test, (rand1 / div_factor), exit_val); 253} 254 255/* Test multiple fprobes hooking the same target function */ 256static void test_fprobe_multi(struct kunit *test) 257{ 258 struct fprobe fp1 = { 259 .entry_handler = fprobe_entry_multi_handler, 260 .exit_handler = fprobe_exit_multi_handler, 261 }; 262 struct fprobe fp2 = { 263 .entry_handler = entry_only_handler, 264 }; 265 266 current_test = test; 267 268 /* Test Case 1: Register in order 1 -> 2 */ 269 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp1, "fprobe_selftest_target", NULL)); 270 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp2, "fprobe_selftest_target", NULL)); 271 272 check_fprobe_multi(test); 273 274 /* Unregister all */ 275 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp1)); 276 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp2)); 277 278 /* Test Case 2: Register in order 2 -> 1 */ 279 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp2, "fprobe_selftest_target", NULL)); 280 KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp1, "fprobe_selftest_target", NULL)); 281 282 check_fprobe_multi(test); 283 284 /* Unregister all */ 285 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp1)); 286 KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp2)); 287} 288 289static unsigned long get_ftrace_location(void *func) 290{ 291 unsigned long size, addr = (unsigned long)func; 292 293 if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size) 294 return 0; 295 296 return ftrace_location_range(addr, addr + size - 1); 297} 298 299static int fprobe_test_init(struct kunit *test) 300{ 301 rand1 = get_random_u32_above(div_factor); 302 target = fprobe_selftest_target; 303 target2 = fprobe_selftest_target2; 304 target_ip = get_ftrace_location(target); 305 target2_ip = get_ftrace_location(target2); 306 307 return 0; 308} 309 310static struct kunit_case fprobe_testcases[] = { 311 KUNIT_CASE(test_fprobe_entry), 312 KUNIT_CASE(test_fprobe), 313 KUNIT_CASE(test_fprobe_syms), 314 KUNIT_CASE(test_fprobe_data), 315 KUNIT_CASE(test_fprobe_skip), 316 KUNIT_CASE(test_fprobe_multi), 317 {} 318}; 319 320static struct kunit_suite fprobe_test_suite = { 321 .name = "fprobe_test", 322 .init = fprobe_test_init, 323 .test_cases = fprobe_testcases, 324}; 325 326kunit_test_suites(&fprobe_test_suite); 327