Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include <stdio.h>
0004 #include <stdlib.h>
0005 #include <signal.h>
0006 #include <unistd.h>
0007 #include <stdbool.h>
0008 #include <string.h>
0009 #include <stdint.h>
0010 #include <fcntl.h>
0011 #include <linux/bpf.h>
0012 #include <sys/ioctl.h>
0013 #include <sys/types.h>
0014 #include <sys/stat.h>
0015 #include <linux/perf_event.h>
0016 
0017 #include <bpf/bpf.h>
0018 #include <bpf/libbpf.h>
0019 #include "bpf_util.h"
0020 #include "perf-sys.h"
0021 #include "trace_helpers.h"
0022 
0023 static struct bpf_program *progs[2];
0024 static struct bpf_link *links[2];
0025 
0026 #define CHECK_PERROR_RET(condition) ({          \
0027     int __ret = !!(condition);          \
0028     if (__ret) {                    \
0029         printf("FAIL: %s:\n", __func__);    \
0030         perror("    ");         \
0031         return -1;              \
0032     }                       \
0033 })
0034 
0035 #define CHECK_AND_RET(condition) ({         \
0036     int __ret = !!(condition);          \
0037     if (__ret)                  \
0038         return -1;              \
0039 })
0040 
0041 static __u64 ptr_to_u64(void *ptr)
0042 {
0043     return (__u64) (unsigned long) ptr;
0044 }
0045 
0046 #define PMU_TYPE_FILE "/sys/bus/event_source/devices/%s/type"
0047 static int bpf_find_probe_type(const char *event_type)
0048 {
0049     char buf[256];
0050     int fd, ret;
0051 
0052     ret = snprintf(buf, sizeof(buf), PMU_TYPE_FILE, event_type);
0053     CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));
0054 
0055     fd = open(buf, O_RDONLY);
0056     CHECK_PERROR_RET(fd < 0);
0057 
0058     ret = read(fd, buf, sizeof(buf));
0059     close(fd);
0060     CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));
0061 
0062     errno = 0;
0063     ret = (int)strtol(buf, NULL, 10);
0064     CHECK_PERROR_RET(errno);
0065     return ret;
0066 }
0067 
0068 #define PMU_RETPROBE_FILE "/sys/bus/event_source/devices/%s/format/retprobe"
0069 static int bpf_get_retprobe_bit(const char *event_type)
0070 {
0071     char buf[256];
0072     int fd, ret;
0073 
0074     ret = snprintf(buf, sizeof(buf), PMU_RETPROBE_FILE, event_type);
0075     CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));
0076 
0077     fd = open(buf, O_RDONLY);
0078     CHECK_PERROR_RET(fd < 0);
0079 
0080     ret = read(fd, buf, sizeof(buf));
0081     close(fd);
0082     CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));
0083     CHECK_PERROR_RET(strlen(buf) < strlen("config:"));
0084 
0085     errno = 0;
0086     ret = (int)strtol(buf + strlen("config:"), NULL, 10);
0087     CHECK_PERROR_RET(errno);
0088     return ret;
0089 }
0090 
0091 static int test_debug_fs_kprobe(int link_idx, const char *fn_name,
0092                 __u32 expected_fd_type)
0093 {
0094     __u64 probe_offset, probe_addr;
0095     __u32 len, prog_id, fd_type;
0096     int err, event_fd;
0097     char buf[256];
0098 
0099     len = sizeof(buf);
0100     event_fd = bpf_link__fd(links[link_idx]);
0101     err = bpf_task_fd_query(getpid(), event_fd, 0, buf, &len,
0102                 &prog_id, &fd_type, &probe_offset,
0103                 &probe_addr);
0104     if (err < 0) {
0105         printf("FAIL: %s, for event_fd idx %d, fn_name %s\n",
0106                __func__, link_idx, fn_name);
0107         perror("    :");
0108         return -1;
0109     }
0110     if (strcmp(buf, fn_name) != 0 ||
0111         fd_type != expected_fd_type ||
0112         probe_offset != 0x0 || probe_addr != 0x0) {
0113         printf("FAIL: bpf_trace_event_query(event_fd[%d]):\n",
0114                link_idx);
0115         printf("buf: %s, fd_type: %u, probe_offset: 0x%llx,"
0116                " probe_addr: 0x%llx\n",
0117                buf, fd_type, probe_offset, probe_addr);
0118         return -1;
0119     }
0120     return 0;
0121 }
0122 
0123 static int test_nondebug_fs_kuprobe_common(const char *event_type,
0124     const char *name, __u64 offset, __u64 addr, bool is_return,
0125     char *buf, __u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
0126     __u64 *probe_offset, __u64 *probe_addr)
0127 {
0128     int is_return_bit = bpf_get_retprobe_bit(event_type);
0129     int type = bpf_find_probe_type(event_type);
0130     struct perf_event_attr attr = {};
0131     struct bpf_link *link;
0132     int fd, err = -1;
0133 
0134     if (type < 0 || is_return_bit < 0) {
0135         printf("FAIL: %s incorrect type (%d) or is_return_bit (%d)\n",
0136             __func__, type, is_return_bit);
0137         return err;
0138     }
0139 
0140     attr.sample_period = 1;
0141     attr.wakeup_events = 1;
0142     if (is_return)
0143         attr.config |= 1 << is_return_bit;
0144 
0145     if (name) {
0146         attr.config1 = ptr_to_u64((void *)name);
0147         attr.config2 = offset;
0148     } else {
0149         attr.config1 = 0;
0150         attr.config2 = addr;
0151     }
0152     attr.size = sizeof(attr);
0153     attr.type = type;
0154 
0155     fd = sys_perf_event_open(&attr, -1, 0, -1, 0);
0156     link = bpf_program__attach_perf_event(progs[0], fd);
0157     if (libbpf_get_error(link)) {
0158         printf("ERROR: bpf_program__attach_perf_event failed\n");
0159         link = NULL;
0160         close(fd);
0161         goto cleanup;
0162     }
0163 
0164     CHECK_PERROR_RET(bpf_task_fd_query(getpid(), fd, 0, buf, buf_len,
0165              prog_id, fd_type, probe_offset, probe_addr) < 0);
0166     err = 0;
0167 
0168 cleanup:
0169     bpf_link__destroy(link);
0170     return err;
0171 }
0172 
0173 static int test_nondebug_fs_probe(const char *event_type, const char *name,
0174                   __u64 offset, __u64 addr, bool is_return,
0175                   __u32 expected_fd_type,
0176                   __u32 expected_ret_fd_type,
0177                   char *buf, __u32 buf_len)
0178 {
0179     __u64 probe_offset, probe_addr;
0180     __u32 prog_id, fd_type;
0181     int err;
0182 
0183     err = test_nondebug_fs_kuprobe_common(event_type, name,
0184                           offset, addr, is_return,
0185                           buf, &buf_len, &prog_id,
0186                           &fd_type, &probe_offset,
0187                           &probe_addr);
0188     if (err < 0) {
0189         printf("FAIL: %s, "
0190                "for name %s, offset 0x%llx, addr 0x%llx, is_return %d\n",
0191                __func__, name ? name : "", offset, addr, is_return);
0192         perror("    :");
0193         return -1;
0194     }
0195     if ((is_return && fd_type != expected_ret_fd_type) ||
0196         (!is_return && fd_type != expected_fd_type)) {
0197         printf("FAIL: %s, incorrect fd_type %u\n",
0198                __func__, fd_type);
0199         return -1;
0200     }
0201     if (name) {
0202         if (strcmp(name, buf) != 0) {
0203             printf("FAIL: %s, incorrect buf %s\n", __func__, buf);
0204             return -1;
0205         }
0206         if (probe_offset != offset) {
0207             printf("FAIL: %s, incorrect probe_offset 0x%llx\n",
0208                    __func__, probe_offset);
0209             return -1;
0210         }
0211     } else {
0212         if (buf_len != 0) {
0213             printf("FAIL: %s, incorrect buf %p\n",
0214                    __func__, buf);
0215             return -1;
0216         }
0217 
0218         if (probe_addr != addr) {
0219             printf("FAIL: %s, incorrect probe_addr 0x%llx\n",
0220                    __func__, probe_addr);
0221             return -1;
0222         }
0223     }
0224     return 0;
0225 }
0226 
0227 static int test_debug_fs_uprobe(char *binary_path, long offset, bool is_return)
0228 {
0229     char buf[256], event_alias[sizeof("test_1234567890")];
0230     const char *event_type = "uprobe";
0231     struct perf_event_attr attr = {};
0232     __u64 probe_offset, probe_addr;
0233     __u32 len, prog_id, fd_type;
0234     int err = -1, res, kfd, efd;
0235     struct bpf_link *link;
0236     ssize_t bytes;
0237 
0238     snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events",
0239          event_type);
0240     kfd = open(buf, O_WRONLY | O_TRUNC, 0);
0241     CHECK_PERROR_RET(kfd < 0);
0242 
0243     res = snprintf(event_alias, sizeof(event_alias), "test_%d", getpid());
0244     CHECK_PERROR_RET(res < 0 || res >= sizeof(event_alias));
0245 
0246     res = snprintf(buf, sizeof(buf), "%c:%ss/%s %s:0x%lx",
0247                is_return ? 'r' : 'p', event_type, event_alias,
0248                binary_path, offset);
0249     CHECK_PERROR_RET(res < 0 || res >= sizeof(buf));
0250     CHECK_PERROR_RET(write(kfd, buf, strlen(buf)) < 0);
0251 
0252     close(kfd);
0253     kfd = -1;
0254 
0255     snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s/id",
0256          event_type, event_alias);
0257     efd = open(buf, O_RDONLY, 0);
0258     CHECK_PERROR_RET(efd < 0);
0259 
0260     bytes = read(efd, buf, sizeof(buf));
0261     CHECK_PERROR_RET(bytes <= 0 || bytes >= sizeof(buf));
0262     close(efd);
0263     buf[bytes] = '\0';
0264 
0265     attr.config = strtol(buf, NULL, 0);
0266     attr.type = PERF_TYPE_TRACEPOINT;
0267     attr.sample_period = 1;
0268     attr.wakeup_events = 1;
0269 
0270     kfd = sys_perf_event_open(&attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC);
0271     link = bpf_program__attach_perf_event(progs[0], kfd);
0272     if (libbpf_get_error(link)) {
0273         printf("ERROR: bpf_program__attach_perf_event failed\n");
0274         link = NULL;
0275         close(kfd);
0276         goto cleanup;
0277     }
0278 
0279     len = sizeof(buf);
0280     err = bpf_task_fd_query(getpid(), kfd, 0, buf, &len,
0281                 &prog_id, &fd_type, &probe_offset,
0282                 &probe_addr);
0283     if (err < 0) {
0284         printf("FAIL: %s, binary_path %s\n", __func__, binary_path);
0285         perror("    :");
0286         return -1;
0287     }
0288     if ((is_return && fd_type != BPF_FD_TYPE_URETPROBE) ||
0289         (!is_return && fd_type != BPF_FD_TYPE_UPROBE)) {
0290         printf("FAIL: %s, incorrect fd_type %u\n", __func__,
0291                fd_type);
0292         return -1;
0293     }
0294     if (strcmp(binary_path, buf) != 0) {
0295         printf("FAIL: %s, incorrect buf %s\n", __func__, buf);
0296         return -1;
0297     }
0298     if (probe_offset != offset) {
0299         printf("FAIL: %s, incorrect probe_offset 0x%llx\n", __func__,
0300                probe_offset);
0301         return -1;
0302     }
0303     err = 0;
0304 
0305 cleanup:
0306     bpf_link__destroy(link);
0307     return err;
0308 }
0309 
0310 int main(int argc, char **argv)
0311 {
0312     extern char __executable_start;
0313     char filename[256], buf[256];
0314     __u64 uprobe_file_offset;
0315     struct bpf_program *prog;
0316     struct bpf_object *obj;
0317     int i = 0, err = -1;
0318 
0319     if (load_kallsyms()) {
0320         printf("failed to process /proc/kallsyms\n");
0321         return err;
0322     }
0323 
0324     snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
0325     obj = bpf_object__open_file(filename, NULL);
0326     if (libbpf_get_error(obj)) {
0327         fprintf(stderr, "ERROR: opening BPF object file failed\n");
0328         return err;
0329     }
0330 
0331     /* load BPF program */
0332     if (bpf_object__load(obj)) {
0333         fprintf(stderr, "ERROR: loading BPF object file failed\n");
0334         goto cleanup;
0335     }
0336 
0337     bpf_object__for_each_program(prog, obj) {
0338         progs[i] = prog;
0339         links[i] = bpf_program__attach(progs[i]);
0340         if (libbpf_get_error(links[i])) {
0341             fprintf(stderr, "ERROR: bpf_program__attach failed\n");
0342             links[i] = NULL;
0343             goto cleanup;
0344         }
0345         i++;
0346     }
0347 
0348     /* test two functions in the corresponding *_kern.c file */
0349     CHECK_AND_RET(test_debug_fs_kprobe(0, "blk_mq_start_request",
0350                        BPF_FD_TYPE_KPROBE));
0351     CHECK_AND_RET(test_debug_fs_kprobe(1, "blk_account_io_done",
0352                        BPF_FD_TYPE_KRETPROBE));
0353 
0354     /* test nondebug fs kprobe */
0355     CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x0, 0x0,
0356                          false, BPF_FD_TYPE_KPROBE,
0357                          BPF_FD_TYPE_KRETPROBE,
0358                          buf, sizeof(buf)));
0359 #ifdef __x86_64__
0360     /* set a kprobe on "bpf_check + 0x5", which is x64 specific */
0361     CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x5, 0x0,
0362                          false, BPF_FD_TYPE_KPROBE,
0363                          BPF_FD_TYPE_KRETPROBE,
0364                          buf, sizeof(buf)));
0365 #endif
0366     CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x0, 0x0,
0367                          true, BPF_FD_TYPE_KPROBE,
0368                          BPF_FD_TYPE_KRETPROBE,
0369                          buf, sizeof(buf)));
0370     CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,
0371                          ksym_get_addr("bpf_check"), false,
0372                          BPF_FD_TYPE_KPROBE,
0373                          BPF_FD_TYPE_KRETPROBE,
0374                          buf, sizeof(buf)));
0375     CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,
0376                          ksym_get_addr("bpf_check"), false,
0377                          BPF_FD_TYPE_KPROBE,
0378                          BPF_FD_TYPE_KRETPROBE,
0379                          NULL, 0));
0380     CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,
0381                          ksym_get_addr("bpf_check"), true,
0382                          BPF_FD_TYPE_KPROBE,
0383                          BPF_FD_TYPE_KRETPROBE,
0384                          buf, sizeof(buf)));
0385     CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,
0386                          ksym_get_addr("bpf_check"), true,
0387                          BPF_FD_TYPE_KPROBE,
0388                          BPF_FD_TYPE_KRETPROBE,
0389                          0, 0));
0390 
0391     /* test nondebug fs uprobe */
0392     /* the calculation of uprobe file offset is based on gcc 7.3.1 on x64
0393      * and the default linker script, which defines __executable_start as
0394      * the start of the .text section. The calculation could be different
0395      * on different systems with different compilers. The right way is
0396      * to parse the ELF file. We took a shortcut here.
0397      */
0398     uprobe_file_offset = (unsigned long)main - (unsigned long)&__executable_start;
0399     CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0],
0400                          uprobe_file_offset, 0x0, false,
0401                          BPF_FD_TYPE_UPROBE,
0402                          BPF_FD_TYPE_URETPROBE,
0403                          buf, sizeof(buf)));
0404     CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0],
0405                          uprobe_file_offset, 0x0, true,
0406                          BPF_FD_TYPE_UPROBE,
0407                          BPF_FD_TYPE_URETPROBE,
0408                          buf, sizeof(buf)));
0409 
0410     /* test debug fs uprobe */
0411     CHECK_AND_RET(test_debug_fs_uprobe((char *)argv[0], uprobe_file_offset,
0412                        false));
0413     CHECK_AND_RET(test_debug_fs_uprobe((char *)argv[0], uprobe_file_offset,
0414                        true));
0415     err = 0;
0416 
0417 cleanup:
0418     for (i--; i >= 0; i--)
0419         bpf_link__destroy(links[i]);
0420 
0421     bpf_object__close(obj);
0422     return err;
0423 }