Alexei Starovoitov says: ==================== pull-request: bpf 2020-04-24 The following pull-request contains BPF updates for your *net* tree. We've added 17 non-merge commits during the last 5 day(s) which contain a total of 19 files changed, 203 insertions(+), 85 deletions(-). The main changes are: 1) link_update fix, from Andrii. 2) libbpf get_xdp_id fix, from David. 3) xadd verifier fix, from Jann. 4) x86-32 JIT fixes, from Luke and Wang. 5) test_btf fix, from Stanislav. 6) freplace verifier fix, from Toke. ====================
Unified · Split
| @@ -158,6 +158,19 @@ static bool is_ereg(u32 reg) · 157 unmodified lines | ||
| 158 | 158 | BIT(BPF_REG_AX)); |
| 159 | 159 | } |
| 160 | 160 | |
| 161 | +/* | |
| 162 | + * is_ereg_8l() == true if BPF register 'reg' is mapped to access x86-64 | |
| 163 | + * lower 8-bit registers dil,sil,bpl,spl,r8b..r15b, which need extra byte | |
| 164 | + * of encoding. al,cl,dl,bl have simpler encoding. | |
| 165 | + */ | |
| 166 | +static bool is_ereg_8l(u32 reg) | |
| 167 | +{ | |
| 168 | + return is_ereg(reg) || | |
| 169 | + (1 << reg) & (BIT(BPF_REG_1) | | |
| 170 | + BIT(BPF_REG_2) | | |
| 171 | + BIT(BPF_REG_FP)); | |
| 172 | +} | |
| 173 | + | |
| 161 | 174 | static bool is_axreg(u32 reg) |
| 162 | 175 | { |
| 163 | 176 | return reg == BPF_REG_0; |
| @@ -598,9 +611,8 @@ static void emit_stx(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off) · 434 unmodified lines | ||
| 598 | 611 | switch (size) { |
| 599 | 612 | case BPF_B: |
| 600 | 613 | /* Emit 'mov byte ptr [rax + off], al' */ |
| 601 | − if (is_ereg(dst_reg) || is_ereg(src_reg) || | |
| 602 | − /* We have to add extra byte for x86 SIL, DIL regs */ | |
| 603 | − src_reg == BPF_REG_1 || src_reg == BPF_REG_2) | |
| 614 | + if (is_ereg(dst_reg) || is_ereg_8l(src_reg)) | |
| 615 | + /* Add extra byte for eregs or SIL,DIL,BPL in src_reg */ | |
| 604 | 616 | EMIT2(add_2mod(0x40, dst_reg, src_reg), 0x88); |
| 605 | 617 | else |
| 606 | 618 | EMIT1(0x88); |
| @@ -1847,14 +1847,16 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 1846 unmodified lines | ||
| 1847 | 1847 | case BPF_B: |
| 1848 | 1848 | case BPF_H: |
| 1849 | 1849 | case BPF_W: |
| 1850 | − if (!bpf_prog->aux->verifier_zext) | |
| 1850 | + if (bpf_prog->aux->verifier_zext) | |
| 1851 | 1851 | break; |
| 1852 | 1852 | if (dstk) { |
| 1853 | 1853 | EMIT3(0xC7, add_1reg(0x40, IA32_EBP), |
| 1854 | 1854 | STACK_VAR(dst_hi)); |
| 1855 | 1855 | EMIT(0x0, 4); |
| 1856 | 1856 | } else { |
| 1857 | − EMIT3(0xC7, add_1reg(0xC0, dst_hi), 0); | |
| 1857 | + /* xor dst_hi,dst_hi */ | |
| 1858 | + EMIT2(0x33, | |
| 1859 | + add_2reg(0xC0, dst_hi, dst_hi)); | |
| 1858 | 1860 | } |
| 1859 | 1861 | break; |
| 1860 | 1862 | case BPF_DW: |
| @@ -2013,8 +2015,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 152 unmodified lines | ||
| 2013 | 2015 | case BPF_JMP | BPF_JSET | BPF_X: |
| 2014 | 2016 | case BPF_JMP32 | BPF_JSET | BPF_X: { |
| 2015 | 2017 | bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; |
| 2016 | − u8 dreg_lo = dstk ? IA32_EAX : dst_lo; | |
| 2017 | − u8 dreg_hi = dstk ? IA32_EDX : dst_hi; | |
| 2018 | + u8 dreg_lo = IA32_EAX; | |
| 2019 | + u8 dreg_hi = IA32_EDX; | |
| 2018 | 2020 | u8 sreg_lo = sstk ? IA32_ECX : src_lo; |
| 2019 | 2021 | u8 sreg_hi = sstk ? IA32_EBX : src_hi; |
| 2020 | 2022 | |
| @@ -2026,6 +2028,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 5 unmodified lines | ||
| 2026 | 2028 | add_2reg(0x40, IA32_EBP, |
| 2027 | 2029 | IA32_EDX), |
| 2028 | 2030 | STACK_VAR(dst_hi)); |
| 2031 | + } else { | |
| 2032 | + /* mov dreg_lo,dst_lo */ | |
| 2033 | + EMIT2(0x89, add_2reg(0xC0, dreg_lo, dst_lo)); | |
| 2034 | + if (is_jmp64) | |
| 2035 | + /* mov dreg_hi,dst_hi */ | |
| 2036 | + EMIT2(0x89, | |
| 2037 | + add_2reg(0xC0, dreg_hi, dst_hi)); | |
| 2029 | 2038 | } |
| 2030 | 2039 | |
| 2031 | 2040 | if (sstk) { |
| @@ -2050,8 +2059,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 18 unmodified lines | ||
| 2050 | 2059 | case BPF_JMP | BPF_JSET | BPF_K: |
| 2051 | 2060 | case BPF_JMP32 | BPF_JSET | BPF_K: { |
| 2052 | 2061 | bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; |
| 2053 | − u8 dreg_lo = dstk ? IA32_EAX : dst_lo; | |
| 2054 | − u8 dreg_hi = dstk ? IA32_EDX : dst_hi; | |
| 2062 | + u8 dreg_lo = IA32_EAX; | |
| 2063 | + u8 dreg_hi = IA32_EDX; | |
| 2055 | 2064 | u8 sreg_lo = IA32_ECX; |
| 2056 | 2065 | u8 sreg_hi = IA32_EBX; |
| 2057 | 2066 | u32 hi; |
| @@ -2064,6 +2073,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 6 unmodified lines | ||
| 2064 | 2073 | add_2reg(0x40, IA32_EBP, |
| 2065 | 2074 | IA32_EDX), |
| 2066 | 2075 | STACK_VAR(dst_hi)); |
| 2076 | + } else { | |
| 2077 | + /* mov dreg_lo,dst_lo */ | |
| 2078 | + EMIT2(0x89, add_2reg(0xC0, dreg_lo, dst_lo)); | |
| 2079 | + if (is_jmp64) | |
| 2080 | + /* mov dreg_hi,dst_hi */ | |
| 2081 | + EMIT2(0x89, | |
| 2082 | + add_2reg(0xC0, dreg_hi, dst_hi)); | |
| 2067 | 2083 | } |
| 2068 | 2084 | |
| 2069 | 2085 | /* mov ecx,imm32 */ |
| @@ -1642,7 +1642,7 @@ union bpf_attr { · 1641 unmodified lines | ||
| 1642 | 1642 | * ifindex, but doesn't require a map to do so. |
| 1643 | 1643 | * Return |
| 1644 | 1644 | * **XDP_REDIRECT** on success, or the value of the two lower bits |
| 1645 | − * of the **flags* argument on error. | |
| 1645 | + * of the *flags* argument on error. | |
| 1646 | 1646 | * |
| 1647 | 1647 | * int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags) |
| 1648 | 1648 | * Description |
| @@ -469,7 +469,7 @@ static int cpu_map_update_elem(struct bpf_map *map, void *key, void *value, · 468 unmodified lines | ||
| 469 | 469 | return -EOVERFLOW; |
| 470 | 470 | |
| 471 | 471 | /* Make sure CPU is a valid possible cpu */ |
| 472 | − if (!cpu_possible(key_cpu)) | |
| 472 | + if (key_cpu >= nr_cpumask_bits || !cpu_possible(key_cpu)) | |
| 473 | 473 | return -ENODEV; |
| 474 | 474 | |
| 475 | 475 | if (qsize == 0) { |
| @@ -2283,7 +2283,7 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) · 2282 unmodified lines | ||
| 2283 | 2283 | } |
| 2284 | 2284 | #endif |
| 2285 | 2285 | |
| 2286 | −const struct file_operations bpf_link_fops = { | |
| 2286 | +static const struct file_operations bpf_link_fops = { | |
| 2287 | 2287 | #ifdef CONFIG_PROC_FS |
| 2288 | 2288 | .show_fdinfo = bpf_link_show_fdinfo, |
| 2289 | 2289 | #endif |
| @@ -3628,8 +3628,10 @@ static int link_update(union bpf_attr *attr) · 1338 unmodified lines | ||
| 3628 | 3628 | return PTR_ERR(link); |
| 3629 | 3629 | |
| 3630 | 3630 | new_prog = bpf_prog_get(attr->link_update.new_prog_fd); |
| 3631 | − if (IS_ERR(new_prog)) | |
| 3632 | − return PTR_ERR(new_prog); | |
| 3631 | + if (IS_ERR(new_prog)) { | |
| 3632 | + ret = PTR_ERR(new_prog); | |
| 3633 | + goto out_put_link; | |
| 3634 | + } | |
| 3633 | 3635 | |
| 3634 | 3636 | if (flags & BPF_F_REPLACE) { |
| 3635 | 3637 | old_prog = bpf_prog_get(attr->link_update.old_prog_fd); |
| @@ -3638,6 +3640,9 @@ static int link_update(union bpf_attr *attr) · 2 unmodified lines | ||
| 3638 | 3640 | old_prog = NULL; |
| 3639 | 3641 | goto out_put_progs; |
| 3640 | 3642 | } |
| 3643 | + } else if (attr->link_update.old_prog_fd) { | |
| 3644 | + ret = -EINVAL; | |
| 3645 | + goto out_put_progs; | |
| 3641 | 3646 | } |
| 3642 | 3647 | |
| 3643 | 3648 | #ifdef CONFIG_CGROUP_BPF |
| @@ -3653,6 +3658,8 @@ out_put_progs: · 9 unmodified lines | ||
| 3653 | 3658 | bpf_prog_put(old_prog); |
| 3654 | 3659 | if (ret) |
| 3655 | 3660 | bpf_prog_put(new_prog); |
| 3661 | +out_put_link: | |
| 3662 | + bpf_link_put(link); | |
| 3656 | 3663 | return ret; |
| 3657 | 3664 | } |
| 3658 | 3665 | |
| @@ -2118,6 +2118,15 @@ static bool register_is_const(struct bpf_reg_state *reg) · 2117 unmodified lines | ||
| 2118 | 2118 | return reg->type == SCALAR_VALUE && tnum_is_const(reg->var_off); |
| 2119 | 2119 | } |
| 2120 | 2120 | |
| 2121 | +static bool __is_pointer_value(bool allow_ptr_leaks, | |
| 2122 | + const struct bpf_reg_state *reg) | |
| 2123 | +{ | |
| 2124 | + if (allow_ptr_leaks) | |
| 2125 | + return false; | |
| 2126 | + | |
| 2127 | + return reg->type != SCALAR_VALUE; | |
| 2128 | +} | |
| 2129 | + | |
| 2121 | 2130 | static void save_register_state(struct bpf_func_state *state, |
| 2122 | 2131 | int spi, struct bpf_reg_state *reg) |
| 2123 | 2132 | { |
| @@ -2308,6 +2317,16 @@ static int check_stack_read(struct bpf_verifier_env *env, · 184 unmodified lines | ||
| 2308 | 2317 | * which resets stack/reg liveness for state transitions |
| 2309 | 2318 | */ |
| 2310 | 2319 | state->regs[value_regno].live |= REG_LIVE_WRITTEN; |
| 2320 | + } else if (__is_pointer_value(env->allow_ptr_leaks, reg)) { | |
| 2321 | + /* If value_regno==-1, the caller is asking us whether | |
| 2322 | + * it is acceptable to use this value as a SCALAR_VALUE | |
| 2323 | + * (e.g. for XADD). | |
| 2324 | + * We must not allow unprivileged callers to do that | |
| 2325 | + * with spilled pointers. | |
| 2326 | + */ | |
| 2327 | + verbose(env, "leaking pointer from stack off %d\n", | |
| 2328 | + off); | |
| 2329 | + return -EACCES; | |
| 2311 | 2330 | } |
| 2312 | 2331 | mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64); |
| 2313 | 2332 | } else { |
| @@ -2673,15 +2692,6 @@ static int check_sock_access(struct bpf_verifier_env *env, int insn_idx, · 359 unmodified lines | ||
| 2673 | 2692 | return -EACCES; |
| 2674 | 2693 | } |
| 2675 | 2694 | |
| 2676 | −static bool __is_pointer_value(bool allow_ptr_leaks, | |
| 2677 | − const struct bpf_reg_state *reg) | |
| 2678 | −{ | |
| 2679 | − if (allow_ptr_leaks) | |
| 2680 | − return false; | |
| 2681 | − | |
| 2682 | − return reg->type != SCALAR_VALUE; | |
| 2683 | −} | |
| 2684 | − | |
| 2685 | 2695 | static struct bpf_reg_state *reg_state(struct bpf_verifier_env *env, int regno) |
| 2686 | 2696 | { |
| 2687 | 2697 | return cur_regs(env) + regno; |
| @@ -3089,7 +3099,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, · 401 unmodified lines | ||
| 3089 | 3099 | if (ret < 0) |
| 3090 | 3100 | return ret; |
| 3091 | 3101 | |
| 3092 | − if (atype == BPF_READ) { | |
| 3102 | + if (atype == BPF_READ && value_regno >= 0) { | |
| 3093 | 3103 | if (ret == SCALAR_VALUE) { |
| 3094 | 3104 | mark_reg_unknown(env, regs, value_regno); |
| 3095 | 3105 | return 0; |
| @@ -10487,6 +10497,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) · 7391 unmodified lines | ||
| 10487 | 10497 | return -EINVAL; |
| 10488 | 10498 | } |
| 10489 | 10499 | env->ops = bpf_verifier_ops[tgt_prog->type]; |
| 10500 | + prog->expected_attach_type = tgt_prog->expected_attach_type; | |
| 10490 | 10501 | } |
| 10491 | 10502 | if (!tgt_prog->jited) { |
| 10492 | 10503 | verbose(env, "Can attach to only JITed progs\n"); |
| @@ -10831,6 +10842,13 @@ err_release_maps: · 338 unmodified lines | ||
| 10831 | 10842 | * them now. Otherwise free_used_maps() will release them. |
| 10832 | 10843 | */ |
| 10833 | 10844 | release_maps(env); |
| 10845 | + | |
| 10846 | + /* extension progs temporarily inherit the attach_type of their targets | |
| 10847 | + for verification purposes, so set it back to zero before returning | |
| 10848 | + */ | |
| 10849 | + if (env->prog->type == BPF_PROG_TYPE_EXT) | |
| 10850 | + env->prog->expected_attach_type = 0; | |
| 10851 | + | |
| 10834 | 10852 | *prog = env->prog; |
| 10835 | 10853 | err_unlock: |
| 10836 | 10854 | if (!is_priv) |
| @@ -479,6 +479,7 @@ static int do_unregister(int argc, char **argv) · 478 unmodified lines | ||
| 479 | 479 | |
| 480 | 480 | static int do_register(int argc, char **argv) |
| 481 | 481 | { |
| 482 | + struct bpf_object_load_attr load_attr = {}; | |
| 482 | 483 | const struct bpf_map_def *def; |
| 483 | 484 | struct bpf_map_info info = {}; |
| 484 | 485 | __u32 info_len = sizeof(info); |
| @@ -499,7 +500,12 @@ static int do_register(int argc, char **argv) · 14 unmodified lines | ||
| 499 | 500 | |
| 500 | 501 | set_max_rlimit(); |
| 501 | 502 | |
| 502 | − if (bpf_object__load(obj)) { | |
| 503 | + load_attr.obj = obj; | |
| 504 | + if (verifier_logs) | |
| 505 | + /* log_level1 + log_level2 + stats, but not stable UAPI */ | |
| 506 | + load_attr.log_level = 1 + 2 + 4; | |
| 507 | + | |
| 508 | + if (bpf_object__load_xattr(&load_attr)) { | |
| 503 | 509 | bpf_object__close(obj); |
| 504 | 510 | return -1; |
| 505 | 511 | } |
| @@ -8,7 +8,7 @@ BPFTOOL ?= $(DEFAULT_BPFTOOL) · 7 unmodified lines | ||
| 8 | 8 | LIBBPF_SRC := $(abspath ../../lib/bpf) |
| 9 | 9 | BPFOBJ := $(OUTPUT)/libbpf.a |
| 10 | 10 | BPF_INCLUDE := $(OUTPUT) |
| 11 | −INCLUDES := -I$(BPF_INCLUDE) -I$(OUTPUT) -I$(abspath ../../lib) | |
| 11 | +INCLUDES := -I$(OUTPUT) -I$(BPF_INCLUDE) -I$(abspath ../../lib) | |
| 12 | 12 | CFLAGS := -g -Wall |
| 13 | 13 | |
| 14 | 14 | # Try to detect best kernel BTF source |
| @@ -1642,7 +1642,7 @@ union bpf_attr { · 1641 unmodified lines | ||
| 1642 | 1642 | * ifindex, but doesn't require a map to do so. |
| 1643 | 1643 | * Return |
| 1644 | 1644 | * **XDP_REDIRECT** on success, or the value of the two lower bits |
| 1645 | − * of the **flags* argument on error. | |
| 1645 | + * of the *flags* argument on error. | |
| 1646 | 1646 | * |
| 1647 | 1647 | * int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags) |
| 1648 | 1648 | * Description |
| @@ -321,6 +321,8 @@ int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info, · 320 unmodified lines | ||
| 321 | 321 | |
| 322 | 322 | static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags) |
| 323 | 323 | { |
| 324 | + flags &= XDP_FLAGS_MODES; | |
| 325 | + | |
| 324 | 326 | if (info->attach_mode != XDP_ATTACHED_MULTI && !flags) |
| 325 | 327 | return info->prog_id; |
| 326 | 328 | if (flags & XDP_FLAGS_DRV_MODE) |
| @@ -5,7 +5,8 @@ · 4 unmodified lines | ||
| 5 | 5 | static void test_fexit_bpf2bpf_common(const char *obj_file, |
| 6 | 6 | const char *target_obj_file, |
| 7 | 7 | int prog_cnt, |
| 8 | − const char **prog_name) | |
| 8 | + const char **prog_name, | |
| 9 | + bool run_prog) | |
| 9 | 10 | { |
| 10 | 11 | struct bpf_object *obj = NULL, *pkt_obj; |
| 11 | 12 | int err, pkt_fd, i; |
| @@ -18,7 +19,8 @@ static void test_fexit_bpf2bpf_common(const char *obj_file, · 6 unmodified lines | ||
| 18 | 19 | |
| 19 | 20 | err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC, |
| 20 | 21 | &pkt_obj, &pkt_fd); |
| 21 | − if (CHECK(err, "prog_load sched cls", "err %d errno %d\n", err, errno)) | |
| 22 | + if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n", | |
| 23 | + target_obj_file, err, errno)) | |
| 22 | 24 | return; |
| 23 | 25 | DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, |
| 24 | 26 | .attach_prog_fd = pkt_fd, |
| @@ -33,7 +35,7 @@ static void test_fexit_bpf2bpf_common(const char *obj_file, · 8 unmodified lines | ||
| 33 | 35 | |
| 34 | 36 | obj = bpf_object__open_file(obj_file, &opts); |
| 35 | 37 | if (CHECK(IS_ERR_OR_NULL(obj), "obj_open", |
| 36 | − "failed to open fexit_bpf2bpf: %ld\n", | |
| 38 | + "failed to open %s: %ld\n", obj_file, | |
| 37 | 39 | PTR_ERR(obj))) |
| 38 | 40 | goto close_prog; |
| 39 | 41 | |
| @@ -49,6 +51,10 @@ static void test_fexit_bpf2bpf_common(const char *obj_file, · 9 unmodified lines | ||
| 49 | 51 | if (CHECK(IS_ERR(link[i]), "attach_trace", "failed to link\n")) |
| 50 | 52 | goto close_prog; |
| 51 | 53 | } |
| 54 | + | |
| 55 | + if (!run_prog) | |
| 56 | + goto close_prog; | |
| 57 | + | |
| 52 | 58 | data_map = bpf_object__find_map_by_name(obj, "fexit_bp.bss"); |
| 53 | 59 | if (CHECK(!data_map, "find_data_map", "data map not found\n")) |
| 54 | 60 | goto close_prog; |
| @@ -89,7 +95,7 @@ static void test_target_no_callees(void) · 34 unmodified lines | ||
| 89 | 95 | test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o", |
| 90 | 96 | "./test_pkt_md_access.o", |
| 91 | 97 | ARRAY_SIZE(prog_name), |
| 92 | − prog_name); | |
| 98 | + prog_name, true); | |
| 93 | 99 | } |
| 94 | 100 | |
| 95 | 101 | static void test_target_yes_callees(void) |
| @@ -103,7 +109,7 @@ static void test_target_yes_callees(void) · 7 unmodified lines | ||
| 103 | 109 | test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", |
| 104 | 110 | "./test_pkt_access.o", |
| 105 | 111 | ARRAY_SIZE(prog_name), |
| 106 | − prog_name); | |
| 112 | + prog_name, true); | |
| 107 | 113 | } |
| 108 | 114 | |
| 109 | 115 | static void test_func_replace(void) |
| @@ -120,7 +126,18 @@ static void test_func_replace(void) · 10 unmodified lines | ||
| 120 | 126 | test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", |
| 121 | 127 | "./test_pkt_access.o", |
| 122 | 128 | ARRAY_SIZE(prog_name), |
| 123 | − prog_name); | |
| 129 | + prog_name, true); | |
| 130 | +} | |
| 131 | + | |
| 132 | +static void test_func_replace_verify(void) | |
| 133 | +{ | |
| 134 | + const char *prog_name[] = { | |
| 135 | + "freplace/do_bind", | |
| 136 | + }; | |
| 137 | + test_fexit_bpf2bpf_common("./freplace_connect4.o", | |
| 138 | + "./connect4_prog.o", | |
| 139 | + ARRAY_SIZE(prog_name), | |
| 140 | + prog_name, false); | |
| 124 | 141 | } |
| 125 | 142 | |
| 126 | 143 | void test_fexit_bpf2bpf(void) |
| @@ -128,4 +145,5 @@ void test_fexit_bpf2bpf(void) · 1 unmodified line | ||
| 128 | 145 | test_target_no_callees(); |
| 129 | 146 | test_target_yes_callees(); |
| 130 | 147 | test_func_replace(); |
| 148 | + test_func_replace_verify(); | |
| 131 | 149 | } |
| @@ -18,11 +18,25 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | int _version SEC("version") = 1; |
| 20 | 20 | |
| 21 | +__attribute__ ((noinline)) | |
| 22 | +int do_bind(struct bpf_sock_addr *ctx) | |
| 23 | +{ | |
| 24 | + struct sockaddr_in sa = {}; | |
| 25 | + | |
| 26 | + sa.sin_family = AF_INET; | |
| 27 | + sa.sin_port = bpf_htons(0); | |
| 28 | + sa.sin_addr.s_addr = bpf_htonl(SRC_REWRITE_IP4); | |
| 29 | + | |
| 30 | + if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) | |
| 31 | + return 0; | |
| 32 | + | |
| 33 | + return 1; | |
| 34 | +} | |
| 35 | + | |
| 21 | 36 | SEC("cgroup/connect4") |
| 22 | 37 | int connect_v4_prog(struct bpf_sock_addr *ctx) |
| 23 | 38 | { |
| 24 | 39 | struct bpf_sock_tuple tuple = {}; |
| 25 | − struct sockaddr_in sa; | |
| 26 | 40 | struct bpf_sock *sk; |
| 27 | 41 | |
| 28 | 42 | /* Verify that new destination is available. */ |
| @@ -56,17 +70,7 @@ int connect_v4_prog(struct bpf_sock_addr *ctx) · 27 unmodified lines | ||
| 56 | 70 | ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4); |
| 57 | 71 | ctx->user_port = bpf_htons(DST_REWRITE_PORT4); |
| 58 | 72 | |
| 59 | − /* Rewrite source. */ | |
| 60 | − memset(&sa, 0, sizeof(sa)); | |
| 61 | − | |
| 62 | − sa.sin_family = AF_INET; | |
| 63 | − sa.sin_port = bpf_htons(0); | |
| 64 | − sa.sin_addr.s_addr = bpf_htonl(SRC_REWRITE_IP4); | |
| 65 | − | |
| 66 | − if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) | |
| 67 | − return 0; | |
| 68 | − | |
| 69 | − return 1; | |
| 73 | + return do_bind(ctx) ? 1 : 0; | |
| 70 | 74 | } |
| 71 | 75 | |
| 72 | 76 | char _license[] SEC("license") = "GPL"; |
| @@ -0,0 +1,18 @@ | ||
| 1 | +#include <linux/stddef.h> | |
| 2 | +#include <linux/ipv6.h> | |
| 3 | +#include <linux/bpf.h> | |
| 4 | +#include <linux/in.h> | |
| 5 | +#include <sys/socket.h> | |
| 6 | +#include <bpf/bpf_helpers.h> | |
| 7 | +#include <bpf/bpf_endian.h> | |
| 8 | + | |
| 9 | +SEC("freplace/do_bind") | |
| 10 | +int new_do_bind(struct bpf_sock_addr *ctx) | |
| 11 | +{ | |
| 12 | + struct sockaddr_in sa = {}; | |
| 13 | + | |
| 14 | + bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)); | |
| 15 | + return 0; | |
| 16 | +} | |
| 17 | + | |
| 18 | +char _license[] SEC("license") = "GPL"; | |
| @@ -20,20 +20,12 @@ struct bpf_map_def SEC("maps") btf_map = { · 19 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | BPF_ANNOTATE_KV_PAIR(btf_map, int, struct ipv_counts); |
| 22 | 22 | |
| 23 | −struct dummy_tracepoint_args { | |
| 24 | − unsigned long long pad; | |
| 25 | − struct sock *sock; | |
| 26 | −}; | |
| 27 | − | |
| 28 | 23 | __attribute__((noinline)) |
| 29 | −int test_long_fname_2(struct dummy_tracepoint_args *arg) | |
| 24 | +int test_long_fname_2(void) | |
| 30 | 25 | { |
| 31 | 26 | struct ipv_counts *counts; |
| 32 | 27 | int key = 0; |
| 33 | 28 | |
| 34 | − if (!arg->sock) | |
| 35 | − return 0; | |
| 36 | − | |
| 37 | 29 | counts = bpf_map_lookup_elem(&btf_map, &key); |
| 38 | 30 | if (!counts) |
| 39 | 31 | return 0; |
| @@ -44,15 +36,15 @@ int test_long_fname_2(struct dummy_tracepoint_args *arg) · 4 unmodified lines | ||
| 44 | 36 | } |
| 45 | 37 | |
| 46 | 38 | __attribute__((noinline)) |
| 47 | −int test_long_fname_1(struct dummy_tracepoint_args *arg) | |
| 39 | +int test_long_fname_1(void) | |
| 48 | 40 | { |
| 49 | − return test_long_fname_2(arg); | |
| 41 | + return test_long_fname_2(); | |
| 50 | 42 | } |
| 51 | 43 | |
| 52 | 44 | SEC("dummy_tracepoint") |
| 53 | −int _dummy_tracepoint(struct dummy_tracepoint_args *arg) | |
| 45 | +int _dummy_tracepoint(void *arg) | |
| 54 | 46 | { |
| 55 | − return test_long_fname_1(arg); | |
| 47 | + return test_long_fname_1(); | |
| 56 | 48 | } |
| 57 | 49 | |
| 58 | 50 | char _license[] SEC("license") = "GPL"; |
| @@ -28,20 +28,12 @@ struct { · 27 unmodified lines | ||
| 28 | 28 | __type(value, struct ipv_counts); |
| 29 | 29 | } btf_map SEC(".maps"); |
| 30 | 30 | |
| 31 | −struct dummy_tracepoint_args { | |
| 32 | − unsigned long long pad; | |
| 33 | − struct sock *sock; | |
| 34 | −}; | |
| 35 | − | |
| 36 | 31 | __attribute__((noinline)) |
| 37 | −int test_long_fname_2(struct dummy_tracepoint_args *arg) | |
| 32 | +int test_long_fname_2(void) | |
| 38 | 33 | { |
| 39 | 34 | struct ipv_counts *counts; |
| 40 | 35 | int key = 0; |
| 41 | 36 | |
| 42 | − if (!arg->sock) | |
| 43 | − return 0; | |
| 44 | − | |
| 45 | 37 | counts = bpf_map_lookup_elem(&btf_map, &key); |
| 46 | 38 | if (!counts) |
| 47 | 39 | return 0; |
| @@ -57,15 +49,15 @@ int test_long_fname_2(struct dummy_tracepoint_args *arg) · 9 unmodified lines | ||
| 57 | 49 | } |
| 58 | 50 | |
| 59 | 51 | __attribute__((noinline)) |
| 60 | −int test_long_fname_1(struct dummy_tracepoint_args *arg) | |
| 52 | +int test_long_fname_1(void) | |
| 61 | 53 | { |
| 62 | − return test_long_fname_2(arg); | |
| 54 | + return test_long_fname_2(); | |
| 63 | 55 | } |
| 64 | 56 | |
| 65 | 57 | SEC("dummy_tracepoint") |
| 66 | −int _dummy_tracepoint(struct dummy_tracepoint_args *arg) | |
| 58 | +int _dummy_tracepoint(void *arg) | |
| 67 | 59 | { |
| 68 | − return test_long_fname_1(arg); | |
| 60 | + return test_long_fname_1(); | |
| 69 | 61 | } |
| 70 | 62 | |
| 71 | 63 | char _license[] SEC("license") = "GPL"; |
| @@ -17,20 +17,12 @@ struct bpf_map_def SEC("maps") btf_map = { · 16 unmodified lines | ||
| 17 | 17 | .max_entries = 4, |
| 18 | 18 | }; |
| 19 | 19 | |
| 20 | −struct dummy_tracepoint_args { | |
| 21 | − unsigned long long pad; | |
| 22 | − struct sock *sock; | |
| 23 | −}; | |
| 24 | − | |
| 25 | 20 | __attribute__((noinline)) |
| 26 | −int test_long_fname_2(struct dummy_tracepoint_args *arg) | |
| 21 | +int test_long_fname_2(void) | |
| 27 | 22 | { |
| 28 | 23 | struct ipv_counts *counts; |
| 29 | 24 | int key = 0; |
| 30 | 25 | |
| 31 | − if (!arg->sock) | |
| 32 | − return 0; | |
| 33 | − | |
| 34 | 26 | counts = bpf_map_lookup_elem(&btf_map, &key); |
| 35 | 27 | if (!counts) |
| 36 | 28 | return 0; |
| @@ -41,15 +33,15 @@ int test_long_fname_2(struct dummy_tracepoint_args *arg) · 4 unmodified lines | ||
| 41 | 33 | } |
| 42 | 34 | |
| 43 | 35 | __attribute__((noinline)) |
| 44 | −int test_long_fname_1(struct dummy_tracepoint_args *arg) | |
| 36 | +int test_long_fname_1(void) | |
| 45 | 37 | { |
| 46 | − return test_long_fname_2(arg); | |
| 38 | + return test_long_fname_2(); | |
| 47 | 39 | } |
| 48 | 40 | |
| 49 | 41 | SEC("dummy_tracepoint") |
| 50 | −int _dummy_tracepoint(struct dummy_tracepoint_args *arg) | |
| 42 | +int _dummy_tracepoint(void *arg) | |
| 51 | 43 | { |
| 52 | − return test_long_fname_1(arg); | |
| 44 | + return test_long_fname_1(); | |
| 53 | 45 | } |
| 54 | 46 | |
| 55 | 47 | char _license[] SEC("license") = "GPL"; |
| @@ -2854,7 +2854,7 @@ static struct btf_raw_test raw_tests[] = { · 2853 unmodified lines | ||
| 2854 | 2854 | .value_type_id = 1, |
| 2855 | 2855 | .max_entries = 4, |
| 2856 | 2856 | .btf_load_err = true, |
| 2857 | − .err_str = "vlen != 0", | |
| 2857 | + .err_str = "Invalid func linkage", | |
| 2858 | 2858 | }, |
| 2859 | 2859 | |
| 2860 | 2860 | { |
| @@ -315,3 +315,43 @@ · 314 unmodified lines | ||
| 315 | 315 | }, |
| 316 | 316 | .result = ACCEPT, |
| 317 | 317 | }, |
| 318 | +{ | |
| 319 | + "store PTR_TO_STACK in R10 to array map using BPF_B", | |
| 320 | + .insns = { | |
| 321 | + /* Load pointer to map. */ | |
| 322 | + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
| 323 | + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
| 324 | + BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | |
| 325 | + BPF_LD_MAP_FD(BPF_REG_1, 0), | |
| 326 | + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | |
| 327 | + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), | |
| 328 | + BPF_MOV64_IMM(BPF_REG_0, 2), | |
| 329 | + BPF_EXIT_INSN(), | |
| 330 | + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | |
| 331 | + /* Copy R10 to R9. */ | |
| 332 | + BPF_MOV64_REG(BPF_REG_9, BPF_REG_10), | |
| 333 | + /* Pollute other registers with unaligned values. */ | |
| 334 | + BPF_MOV64_IMM(BPF_REG_2, -1), | |
| 335 | + BPF_MOV64_IMM(BPF_REG_3, -1), | |
| 336 | + BPF_MOV64_IMM(BPF_REG_4, -1), | |
| 337 | + BPF_MOV64_IMM(BPF_REG_5, -1), | |
| 338 | + BPF_MOV64_IMM(BPF_REG_6, -1), | |
| 339 | + BPF_MOV64_IMM(BPF_REG_7, -1), | |
| 340 | + BPF_MOV64_IMM(BPF_REG_8, -1), | |
| 341 | + /* Store both R9 and R10 with BPF_B and read back. */ | |
| 342 | + BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_10, 0), | |
| 343 | + BPF_LDX_MEM(BPF_B, BPF_REG_2, BPF_REG_1, 0), | |
| 344 | + BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_9, 0), | |
| 345 | + BPF_LDX_MEM(BPF_B, BPF_REG_3, BPF_REG_1, 0), | |
| 346 | + /* Should read back as same value. */ | |
| 347 | + BPF_JMP_REG(BPF_JEQ, BPF_REG_2, BPF_REG_3, 2), | |
| 348 | + BPF_MOV64_IMM(BPF_REG_0, 1), | |
| 349 | + BPF_EXIT_INSN(), | |
| 350 | + BPF_MOV64_IMM(BPF_REG_0, 42), | |
| 351 | + BPF_EXIT_INSN(), | |
| 352 | + }, | |
| 353 | + .fixup_map_array_48b = { 3 }, | |
| 354 | + .result = ACCEPT, | |
| 355 | + .retval = 42, | |
| 356 | + .prog_type = BPF_PROG_TYPE_SCHED_CLS, | |
| 357 | +}, | |
| @@ -88,6 +88,7 @@ · 87 unmodified lines | ||
| 88 | 88 | BPF_EXIT_INSN(), |
| 89 | 89 | }, |
| 90 | 90 | .fixup_map_hash_48b = { 3 }, |
| 91 | + .errstr_unpriv = "leaking pointer from stack off -8", | |
| 91 | 92 | .errstr = "R0 invalid mem access 'inv'", |
| 92 | 93 | .result = REJECT, |
| 93 | 94 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |