1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <signal.h> 6 #include <unistd.h> 7 #include <stdbool.h> 8 #include <string.h> 9 #include <stdint.h> 10 #include <fcntl.h> 11 #include <linux/bpf.h> 12 #include <sys/ioctl.h> 13 #include <sys/types.h> 14 #include <sys/stat.h> 15 #include <linux/perf_event.h> 16 17 #include <bpf/bpf.h> 18 #include <bpf/libbpf.h> 19 #include "bpf_util.h" 20 #include "perf-sys.h" 21 #include "trace_helpers.h" 22 23 static struct bpf_program *progs[2]; 24 static struct bpf_link *links[2]; 25 26 #define CHECK_PERROR_RET(condition) ({ \ 27 int __ret = !!(condition); \ 28 if (__ret) { \ 29 printf("FAIL: %s:\n", __func__); \ 30 perror(" "); \ 31 return -1; \ 32 } \ 33 }) 34 35 #define CHECK_AND_RET(condition) ({ \ 36 int __ret = !!(condition); \ 37 if (__ret) \ 38 return -1; \ 39 }) 40 41 static __u64 ptr_to_u64(void *ptr) 42 { 43 return (__u64) (unsigned long) ptr; 44 } 45 46 #define PMU_TYPE_FILE "/sys/bus/event_source/devices/%s/type" 47 static int bpf_find_probe_type(const char *event_type) 48 { 49 char buf[256]; 50 int fd, ret; 51 52 ret = snprintf(buf, sizeof(buf), PMU_TYPE_FILE, event_type); 53 CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf)); 54 55 fd = open(buf, O_RDONLY); 56 CHECK_PERROR_RET(fd < 0); 57 58 ret = read(fd, buf, sizeof(buf)); 59 close(fd); 60 CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf)); 61 62 errno = 0; 63 ret = (int)strtol(buf, NULL, 10); 64 CHECK_PERROR_RET(errno); 65 return ret; 66 } 67 68 #define PMU_RETPROBE_FILE "/sys/bus/event_source/devices/%s/format/retprobe" 69 static int bpf_get_retprobe_bit(const char *event_type) 70 { 71 char buf[256]; 72 int fd, ret; 73 74 ret = snprintf(buf, sizeof(buf), PMU_RETPROBE_FILE, event_type); 75 CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf)); 76 77 fd = open(buf, O_RDONLY); 78 CHECK_PERROR_RET(fd < 0); 79 80 ret = read(fd, buf, sizeof(buf)); 81 close(fd); 82 CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf)); 83 CHECK_PERROR_RET(strlen(buf) < strlen("config:")); 84 85 errno = 0; 86 ret = (int)strtol(buf + strlen("config:"), NULL, 10); 87 CHECK_PERROR_RET(errno); 88 return ret; 89 } 90 91 static int test_debug_fs_kprobe(int link_idx, const char *fn_name, 92 __u32 expected_fd_type) 93 { 94 __u64 probe_offset, probe_addr; 95 __u32 len, prog_id, fd_type; 96 int err, event_fd; 97 char buf[256]; 98 99 len = sizeof(buf); 100 event_fd = bpf_link__fd(links[link_idx]); 101 err = bpf_task_fd_query(getpid(), event_fd, 0, buf, &len, 102 &prog_id, &fd_type, &probe_offset, 103 &probe_addr); 104 if (err < 0) { 105 printf("FAIL: %s, for event_fd idx %d, fn_name %s\n", 106 __func__, link_idx, fn_name); 107 perror(" :"); 108 return -1; 109 } 110 if (strcmp(buf, fn_name) != 0 || 111 fd_type != expected_fd_type || 112 probe_offset != 0x0 || probe_addr != 0x0) { 113 printf("FAIL: bpf_trace_event_query(event_fd[%d]):\n", 114 link_idx); 115 printf("buf: %s, fd_type: %u, probe_offset: 0x%llx," 116 " probe_addr: 0x%llx\n", 117 buf, fd_type, probe_offset, probe_addr); 118 return -1; 119 } 120 return 0; 121 } 122 123 static int test_nondebug_fs_kuprobe_common(const char *event_type, 124 const char *name, __u64 offset, __u64 addr, bool is_return, 125 char *buf, __u32 *buf_len, __u32 *prog_id, __u32 *fd_type, 126 __u64 *probe_offset, __u64 *probe_addr) 127 { 128 int is_return_bit = bpf_get_retprobe_bit(event_type); 129 int type = bpf_find_probe_type(event_type); 130 struct perf_event_attr attr = {}; 131 struct bpf_link *link; 132 int fd, err = -1; 133 134 if (type < 0 || is_return_bit < 0) { 135 printf("FAIL: %s incorrect type (%d) or is_return_bit (%d)\n", 136 __func__, type, is_return_bit); 137 return err; 138 } 139 140 attr.sample_period = 1; 141 attr.wakeup_events = 1; 142 if (is_return) 143 attr.config |= 1 << is_return_bit; 144 145 if (name) { 146 attr.config1 = ptr_to_u64((void *)name); 147 attr.config2 = offset; 148 } else { 149 attr.config1 = 0; 150 attr.config2 = addr; 151 } 152 attr.size = sizeof(attr); 153 attr.type = type; 154 155 fd = sys_perf_event_open(&attr, -1, 0, -1, 0); 156 link = bpf_program__attach_perf_event(progs[0], fd); 157 if (libbpf_get_error(link)) { 158 printf("ERROR: bpf_program__attach_perf_event failed\n"); 159 link = NULL; 160 close(fd); 161 goto cleanup; 162 } 163 164 CHECK_PERROR_RET(bpf_task_fd_query(getpid(), fd, 0, buf, buf_len, 165 prog_id, fd_type, probe_offset, probe_addr) < 0); 166 err = 0; 167 168 cleanup: 169 bpf_link__destroy(link); 170 return err; 171 } 172 173 static int test_nondebug_fs_probe(const char *event_type, const char *name, 174 __u64 offset, __u64 addr, bool is_return, 175 __u32 expected_fd_type, 176 __u32 expected_ret_fd_type, 177 char *buf, __u32 buf_len) 178 { 179 __u64 probe_offset, probe_addr; 180 __u32 prog_id, fd_type; 181 int err; 182 183 err = test_nondebug_fs_kuprobe_common(event_type, name, 184 offset, addr, is_return, 185 buf, &buf_len, &prog_id, 186 &fd_type, &probe_offset, 187 &probe_addr); 188 if (err < 0) { 189 printf("FAIL: %s, " 190 "for name %s, offset 0x%llx, addr 0x%llx, is_return %d\n", 191 __func__, name ? name : "", offset, addr, is_return); 192 perror(" :"); 193 return -1; 194 } 195 if ((is_return && fd_type != expected_ret_fd_type) || 196 (!is_return && fd_type != expected_fd_type)) { 197 printf("FAIL: %s, incorrect fd_type %u\n", 198 __func__, fd_type); 199 return -1; 200 } 201 if (name) { 202 if (strcmp(name, buf) != 0) { 203 printf("FAIL: %s, incorrect buf %s\n", __func__, buf); 204 return -1; 205 } 206 if (probe_offset != offset) { 207 printf("FAIL: %s, incorrect probe_offset 0x%llx\n", 208 __func__, probe_offset); 209 return -1; 210 } 211 } else { 212 if (buf_len != 0) { 213 printf("FAIL: %s, incorrect buf %p\n", 214 __func__, buf); 215 return -1; 216 } 217 218 if (probe_addr != addr) { 219 printf("FAIL: %s, incorrect probe_addr 0x%llx\n", 220 __func__, probe_addr); 221 return -1; 222 } 223 } 224 return 0; 225 } 226 227 static int test_debug_fs_uprobe(char *binary_path, long offset, bool is_return) 228 { 229 char buf[256], event_alias[sizeof("test_1234567890")]; 230 const char *event_type = "uprobe"; 231 struct perf_event_attr attr = {}; 232 __u64 probe_offset, probe_addr; 233 __u32 len, prog_id, fd_type; 234 int err = -1, res, kfd, efd; 235 struct bpf_link *link; 236 ssize_t bytes; 237 238 snprintf(buf, sizeof(buf), "/sys/kernel/tracing/%s_events", 239 event_type); 240 kfd = open(buf, O_WRONLY | O_TRUNC, 0); 241 CHECK_PERROR_RET(kfd < 0); 242 243 res = snprintf(event_alias, sizeof(event_alias), "test_%d", getpid()); 244 CHECK_PERROR_RET(res < 0 || res >= sizeof(event_alias)); 245 246 res = snprintf(buf, sizeof(buf), "%c:%ss/%s %s:0x%lx", 247 is_return ? 'r' : 'p', event_type, event_alias, 248 binary_path, offset); 249 CHECK_PERROR_RET(res < 0 || res >= sizeof(buf)); 250 CHECK_PERROR_RET(write(kfd, buf, strlen(buf)) < 0); 251 252 close(kfd); 253 kfd = -1; 254 255 snprintf(buf, sizeof(buf), "/sys/kernel/tracing/events/%ss/%s/id", 256 event_type, event_alias); 257 efd = open(buf, O_RDONLY, 0); 258 CHECK_PERROR_RET(efd < 0); 259 260 bytes = read(efd, buf, sizeof(buf)); 261 CHECK_PERROR_RET(bytes <= 0 || bytes >= sizeof(buf)); 262 close(efd); 263 buf[bytes] = '\0'; 264 265 attr.config = strtol(buf, NULL, 0); 266 attr.type = PERF_TYPE_TRACEPOINT; 267 attr.sample_period = 1; 268 attr.wakeup_events = 1; 269 270 kfd = sys_perf_event_open(&attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); 271 link = bpf_program__attach_perf_event(progs[0], kfd); 272 if (libbpf_get_error(link)) { 273 printf("ERROR: bpf_program__attach_perf_event failed\n"); 274 link = NULL; 275 close(kfd); 276 goto cleanup; 277 } 278 279 len = sizeof(buf); 280 err = bpf_task_fd_query(getpid(), kfd, 0, buf, &len, 281 &prog_id, &fd_type, &probe_offset, 282 &probe_addr); 283 if (err < 0) { 284 printf("FAIL: %s, binary_path %s\n", __func__, binary_path); 285 perror(" :"); 286 return -1; 287 } 288 if ((is_return && fd_type != BPF_FD_TYPE_URETPROBE) || 289 (!is_return && fd_type != BPF_FD_TYPE_UPROBE)) { 290 printf("FAIL: %s, incorrect fd_type %u\n", __func__, 291 fd_type); 292 return -1; 293 } 294 if (strcmp(binary_path, buf) != 0) { 295 printf("FAIL: %s, incorrect buf %s\n", __func__, buf); 296 return -1; 297 } 298 if (probe_offset != offset) { 299 printf("FAIL: %s, incorrect probe_offset 0x%llx\n", __func__, 300 probe_offset); 301 return -1; 302 } 303 err = 0; 304 305 cleanup: 306 bpf_link__destroy(link); 307 return err; 308 } 309 310 int main(int argc, char **argv) 311 { 312 extern char __executable_start; 313 char filename[256], buf[256]; 314 __u64 uprobe_file_offset; 315 struct bpf_program *prog; 316 struct bpf_object *obj; 317 int i = 0, err = -1; 318 319 if (load_kallsyms()) { 320 printf("failed to process /proc/kallsyms\n"); 321 return err; 322 } 323 324 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 325 obj = bpf_object__open_file(filename, NULL); 326 if (libbpf_get_error(obj)) { 327 fprintf(stderr, "ERROR: opening BPF object file failed\n"); 328 return err; 329 } 330 331 /* load BPF program */ 332 if (bpf_object__load(obj)) { 333 fprintf(stderr, "ERROR: loading BPF object file failed\n"); 334 goto cleanup; 335 } 336 337 bpf_object__for_each_program(prog, obj) { 338 progs[i] = prog; 339 links[i] = bpf_program__attach(progs[i]); 340 if (libbpf_get_error(links[i])) { 341 fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 342 links[i] = NULL; 343 goto cleanup; 344 } 345 i++; 346 } 347 348 /* test two functions in the corresponding *_kern.c file */ 349 CHECK_AND_RET(test_debug_fs_kprobe(0, "blk_mq_start_request", 350 BPF_FD_TYPE_KPROBE)); 351 CHECK_AND_RET(test_debug_fs_kprobe(1, "__blk_account_io_done", 352 BPF_FD_TYPE_KRETPROBE)); 353 354 /* test nondebug fs kprobe */ 355 CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x0, 0x0, 356 false, BPF_FD_TYPE_KPROBE, 357 BPF_FD_TYPE_KRETPROBE, 358 buf, sizeof(buf))); 359 #ifdef __x86_64__ 360 /* set a kprobe on "bpf_check + 0x5", which is x64 specific */ 361 CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x5, 0x0, 362 false, BPF_FD_TYPE_KPROBE, 363 BPF_FD_TYPE_KRETPROBE, 364 buf, sizeof(buf))); 365 #endif 366 CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x0, 0x0, 367 true, BPF_FD_TYPE_KPROBE, 368 BPF_FD_TYPE_KRETPROBE, 369 buf, sizeof(buf))); 370 CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0, 371 ksym_get_addr("bpf_check"), false, 372 BPF_FD_TYPE_KPROBE, 373 BPF_FD_TYPE_KRETPROBE, 374 buf, sizeof(buf))); 375 CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0, 376 ksym_get_addr("bpf_check"), false, 377 BPF_FD_TYPE_KPROBE, 378 BPF_FD_TYPE_KRETPROBE, 379 NULL, 0)); 380 CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0, 381 ksym_get_addr("bpf_check"), true, 382 BPF_FD_TYPE_KPROBE, 383 BPF_FD_TYPE_KRETPROBE, 384 buf, sizeof(buf))); 385 CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0, 386 ksym_get_addr("bpf_check"), true, 387 BPF_FD_TYPE_KPROBE, 388 BPF_FD_TYPE_KRETPROBE, 389 0, 0)); 390 391 /* test nondebug fs uprobe */ 392 /* the calculation of uprobe file offset is based on gcc 7.3.1 on x64 393 * and the default linker script, which defines __executable_start as 394 * the start of the .text section. The calculation could be different 395 * on different systems with different compilers. The right way is 396 * to parse the ELF file. We took a shortcut here. 397 */ 398 uprobe_file_offset = (unsigned long)main - (unsigned long)&__executable_start; 399 CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0], 400 uprobe_file_offset, 0x0, false, 401 BPF_FD_TYPE_UPROBE, 402 BPF_FD_TYPE_URETPROBE, 403 buf, sizeof(buf))); 404 CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0], 405 uprobe_file_offset, 0x0, true, 406 BPF_FD_TYPE_UPROBE, 407 BPF_FD_TYPE_URETPROBE, 408 buf, sizeof(buf))); 409 410 /* test debug fs uprobe */ 411 CHECK_AND_RET(test_debug_fs_uprobe((char *)argv[0], uprobe_file_offset, 412 false)); 413 CHECK_AND_RET(test_debug_fs_uprobe((char *)argv[0], uprobe_file_offset, 414 true)); 415 err = 0; 416 417 cleanup: 418 for (i--; i >= 0; i--) 419 bpf_link__destroy(links[i]); 420 421 bpf_object__close(obj); 422 return err; 423 } 424