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