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