static int check_env(void) { int err; unsigned int kver_int; char license[] = "GPL"; struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 1), BPF_EXIT_INSN(), }; err = fetch_kernel_version(&kver_int, NULL, 0); if (err) { pr_debug("Unable to get kernel version\n"); return err; } err = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns, sizeof(insns) / sizeof(insns[0]), license, kver_int, NULL, 0); if (err < 0) { pr_err("Missing basic BPF support, skip this test: %s\n", strerror(errno)); return err; } close(err); return 0; }
static int bpf_try_load_prog(int insns, int fd_map, void (*bpf_filler)(unsigned int insns, int fd_map)) { int fd_prog; bpf_filler(insns, fd_map); fd_prog = bpf_load_program(BPF_PROG_TYPE_SCHED_CLS, prog, insns, "", 0, NULL, 0); assert(fd_prog > 0); if (fd_map > 0) bpf_filler(insns, 0); return fd_prog; }
static int load_program(struct bpf_insn *insns, int insns_cnt, char *license, u32 kern_version, int *pfd) { int ret; char *log_buf; if (!insns || !insns_cnt) return -EINVAL; log_buf = malloc(BPF_LOG_BUF_SIZE); if (!log_buf) pr_warning("Alloc log buffer for bpf loader error, continue without log\n"); ret = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns, insns_cnt, license, kern_version, log_buf, BPF_LOG_BUF_SIZE); if (ret >= 0) { *pfd = ret; ret = 0; goto out; } ret = -LIBBPF_ERRNO__LOAD; pr_warning("load bpf program failed: %s\n", strerror(errno)); if (log_buf && log_buf[0] != '\0') { ret = -LIBBPF_ERRNO__VERIFY; pr_warning("-- BEGIN DUMP LOG ---\n"); pr_warning("\n%s\n", log_buf); pr_warning("-- END LOG --\n"); } else { if (insns_cnt >= BPF_MAXINSNS) { pr_warning("Program too large (%d insns), at most %d insns\n", insns_cnt, BPF_MAXINSNS); ret = -LIBBPF_ERRNO__PROG2BIG; } else if (log_buf) { pr_warning("log buffer is empty\n"); ret = -LIBBPF_ERRNO__KVER; } } out: free(log_buf); return ret; }
static int bpf_prog_create(const char *object) { static struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 1), BPF_EXIT_INSN(), }; size_t insns_cnt = sizeof(insns) / sizeof(struct bpf_insn); if (object) { assert(!load_bpf_file((char *)object)); return prog_fd[0]; } else { return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, insns, insns_cnt, "GPL", 0, bpf_log_buf, BPF_LOG_BUF_SIZE); } }
static int prog_load(int verdict) { int ret; struct bpf_insn prog[] = { BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */ BPF_EXIT_INSN(), }; size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn); ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB, prog, insns_cnt, "GPL", 0, bpf_log_buf, BPF_LOG_BUF_SIZE); if (ret < 0) { log_err("Loading program"); printf("Output from verifier:\n%s\n-------\n", bpf_log_buf); return 0; } return ret; }
static int prog_load_cnt(int verdict, int val) { int cgroup_storage_fd, percpu_cgroup_storage_fd; if (map_fd < 0) map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, 4, 8, 1, 0); if (map_fd < 0) { printf("failed to create map '%s'\n", strerror(errno)); return -1; } cgroup_storage_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, sizeof(struct bpf_cgroup_storage_key), 8, 0, 0); if (cgroup_storage_fd < 0) { printf("failed to create map '%s'\n", strerror(errno)); return -1; } percpu_cgroup_storage_fd = bpf_create_map( BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, sizeof(struct bpf_cgroup_storage_key), 8, 0, 0); if (percpu_cgroup_storage_fd < 0) { printf("failed to create map '%s'\n", strerror(errno)); return -1; } struct bpf_insn prog[] = { BPF_MOV32_IMM(BPF_REG_0, 0), BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */ BPF_LD_MAP_FD(BPF_REG_1, map_fd), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), BPF_MOV64_IMM(BPF_REG_1, val), /* r1 = 1 */ BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */ BPF_LD_MAP_FD(BPF_REG_1, cgroup_storage_fd), BPF_MOV64_IMM(BPF_REG_2, 0), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_local_storage), BPF_MOV64_IMM(BPF_REG_1, val), BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_W, BPF_REG_0, BPF_REG_1, 0, 0), BPF_LD_MAP_FD(BPF_REG_1, percpu_cgroup_storage_fd), BPF_MOV64_IMM(BPF_REG_2, 0), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_local_storage), BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x1), BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_3, 0), BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */ BPF_EXIT_INSN(), }; size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn); int ret; ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB, prog, insns_cnt, "GPL", 0, bpf_log_buf, BPF_LOG_BUF_SIZE); if (ret < 0) { log_err("Loading program"); printf("Output from verifier:\n%s\n-------\n", bpf_log_buf); return 0; } close(cgroup_storage_fd); return ret; }
static int load_and_attach(const char *event, struct bpf_insn *prog, int size) { bool is_socket = strncmp(event, "socket", 6) == 0; bool is_kprobe = strncmp(event, "kprobe/", 7) == 0; bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0; bool is_tracepoint = strncmp(event, "tracepoint/", 11) == 0; bool is_xdp = strncmp(event, "xdp", 3) == 0; bool is_perf_event = strncmp(event, "perf_event", 10) == 0; bool is_cgroup_skb = strncmp(event, "cgroup/skb", 10) == 0; bool is_cgroup_sk = strncmp(event, "cgroup/sock", 11) == 0; size_t insns_cnt = size / sizeof(struct bpf_insn); enum bpf_prog_type prog_type; char buf[256]; int fd, efd, err, id; struct perf_event_attr attr = {}; attr.type = PERF_TYPE_TRACEPOINT; attr.sample_type = PERF_SAMPLE_RAW; attr.sample_period = 1; attr.wakeup_events = 1; if (is_socket) { prog_type = BPF_PROG_TYPE_SOCKET_FILTER; } else if (is_kprobe || is_kretprobe) { prog_type = BPF_PROG_TYPE_KPROBE; } else if (is_tracepoint) { prog_type = BPF_PROG_TYPE_TRACEPOINT; } else if (is_xdp) { prog_type = BPF_PROG_TYPE_XDP; } else if (is_perf_event) { prog_type = BPF_PROG_TYPE_PERF_EVENT; } else if (is_cgroup_skb) { prog_type = BPF_PROG_TYPE_CGROUP_SKB; } else if (is_cgroup_sk) { prog_type = BPF_PROG_TYPE_CGROUP_SOCK; } else { printf("Unknown event '%s'\n", event); return -1; } fd = bpf_load_program(prog_type, prog, insns_cnt, license, kern_version, bpf_log_buf, BPF_LOG_BUF_SIZE); if (fd < 0) { printf("bpf_load_program() err=%d\n%s", errno, bpf_log_buf); return -1; } prog_fd[prog_cnt++] = fd; if (is_xdp || is_perf_event || is_cgroup_skb || is_cgroup_sk) return 0; if (is_socket) { event += 6; if (*event != '/') return 0; event++; if (!isdigit(*event)) { printf("invalid prog number\n"); return -1; } return populate_prog_array(event, fd); } if (is_kprobe || is_kretprobe) { if (is_kprobe) event += 7; else event += 10; if (*event == 0) { printf("event name cannot be empty\n"); return -1; } if (isdigit(*event)) return populate_prog_array(event, fd); snprintf(buf, sizeof(buf), "echo '%c:%s %s' >> /sys/kernel/debug/tracing/kprobe_events", is_kprobe ? 'p' : 'r', event, event); err = system(buf); if (err < 0) { printf("failed to create kprobe '%s' error '%s'\n", event, strerror(errno)); return -1; } strcpy(buf, DEBUGFS); strcat(buf, "events/kprobes/"); strcat(buf, event); strcat(buf, "/id"); } else if (is_tracepoint) { event += 11; if (*event == 0) { printf("event name cannot be empty\n"); return -1; } strcpy(buf, DEBUGFS); strcat(buf, "events/"); strcat(buf, event); strcat(buf, "/id"); } efd = open(buf, O_RDONLY, 0); if (efd < 0) { printf("failed to open event %s\n", event); return -1; } err = read(efd, buf, sizeof(buf)); if (err < 0 || err >= sizeof(buf)) { printf("read from '%s' failed '%s'\n", event, strerror(errno)); return -1; } close(efd); buf[err] = 0; id = atoi(buf); attr.config = id; efd = sys_perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0); if (efd < 0) { printf("event %d fd %d err %s\n", id, efd, strerror(errno)); return -1; } event_fd[prog_cnt - 1] = efd; ioctl(efd, PERF_EVENT_IOC_ENABLE, 0); ioctl(efd, PERF_EVENT_IOC_SET_BPF, fd); return 0; }