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 | BIT(BPF_REG_AX)); | 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 | static bool is_axreg(u32 reg) | 174 | static bool is_axreg(u32 reg) |
| 162 | { | 175 | { |
| 163 | return reg == BPF_REG_0; | 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 | switch (size) { | 611 | switch (size) { |
| 599 | case BPF_B: | 612 | case BPF_B: |
| 600 | /* Emit 'mov byte ptr [rax + off], al' */ | 613 | /* Emit 'mov byte ptr [rax + off], al' */ |
| 601 | if (is_ereg(dst_reg) || is_ereg(src_reg) || | 614 | if (is_ereg(dst_reg) || is_ereg_8l(src_reg)) |
| 602 | /* We have to add extra byte for x86 SIL, DIL regs */ | 615 | /* Add extra byte for eregs or SIL,DIL,BPL in src_reg */ |
| 603 | src_reg == BPF_REG_1 || src_reg == BPF_REG_2) | ||
| 604 | EMIT2(add_2mod(0x40, dst_reg, src_reg), 0x88); | 616 | EMIT2(add_2mod(0x40, dst_reg, src_reg), 0x88); |
| 605 | else | 617 | else |
| 606 | EMIT1(0x88); | 618 | EMIT1(0x88); |
| @@ -1847,14 +1847,16 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 1846 unmodified lines | |||
| 1847 | case BPF_B: | 1847 | case BPF_B: |
| 1848 | case BPF_H: | 1848 | case BPF_H: |
| 1849 | case BPF_W: | 1849 | case BPF_W: |
| 1850 | if (!bpf_prog->aux->verifier_zext) | 1850 | if (bpf_prog->aux->verifier_zext) |
| 1851 | break; | 1851 | break; |
| 1852 | if (dstk) { | 1852 | if (dstk) { |
| 1853 | EMIT3(0xC7, add_1reg(0x40, IA32_EBP), | 1853 | EMIT3(0xC7, add_1reg(0x40, IA32_EBP), |
| 1854 | STACK_VAR(dst_hi)); | 1854 | STACK_VAR(dst_hi)); |
| 1855 | EMIT(0x0, 4); | 1855 | EMIT(0x0, 4); |
| 1856 | } else { | 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 | break; | 1861 | break; |
| 1860 | case BPF_DW: | 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 | case BPF_JMP | BPF_JSET | BPF_X: | 2015 | case BPF_JMP | BPF_JSET | BPF_X: |
| 2014 | case BPF_JMP32 | BPF_JSET | BPF_X: { | 2016 | case BPF_JMP32 | BPF_JSET | BPF_X: { |
| 2015 | bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; | 2017 | bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; |
| 2016 | u8 dreg_lo = dstk ? IA32_EAX : dst_lo; | 2018 | u8 dreg_lo = IA32_EAX; |
| 2017 | u8 dreg_hi = dstk ? IA32_EDX : dst_hi; | 2019 | u8 dreg_hi = IA32_EDX; |
| 2018 | u8 sreg_lo = sstk ? IA32_ECX : src_lo; | 2020 | u8 sreg_lo = sstk ? IA32_ECX : src_lo; |
| 2019 | u8 sreg_hi = sstk ? IA32_EBX : src_hi; | 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 | add_2reg(0x40, IA32_EBP, | 2028 | add_2reg(0x40, IA32_EBP, |
| 2027 | IA32_EDX), | 2029 | IA32_EDX), |
| 2028 | STACK_VAR(dst_hi)); | 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 | if (sstk) { | 2040 | if (sstk) { |
| @@ -2050,8 +2059,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 18 unmodified lines | |||
| 2050 | case BPF_JMP | BPF_JSET | BPF_K: | 2059 | case BPF_JMP | BPF_JSET | BPF_K: |
| 2051 | case BPF_JMP32 | BPF_JSET | BPF_K: { | 2060 | case BPF_JMP32 | BPF_JSET | BPF_K: { |
| 2052 | bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; | 2061 | bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; |
| 2053 | u8 dreg_lo = dstk ? IA32_EAX : dst_lo; | 2062 | u8 dreg_lo = IA32_EAX; |
| 2054 | u8 dreg_hi = dstk ? IA32_EDX : dst_hi; | 2063 | u8 dreg_hi = IA32_EDX; |
| 2055 | u8 sreg_lo = IA32_ECX; | 2064 | u8 sreg_lo = IA32_ECX; |
| 2056 | u8 sreg_hi = IA32_EBX; | 2065 | u8 sreg_hi = IA32_EBX; |
| 2057 | u32 hi; | 2066 | u32 hi; |
| @@ -2064,6 +2073,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 6 unmodified lines | |||
| 2064 | add_2reg(0x40, IA32_EBP, | 2073 | add_2reg(0x40, IA32_EBP, |
| 2065 | IA32_EDX), | 2074 | IA32_EDX), |
| 2066 | STACK_VAR(dst_hi)); | 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 | /* mov ecx,imm32 */ | 2085 | /* mov ecx,imm32 */ |
| @@ -1642,7 +1642,7 @@ union bpf_attr { · 1641 unmodified lines | |||
| 1642 | * ifindex, but doesn't require a map to do so. | 1642 | * ifindex, but doesn't require a map to do so. |
| 1643 | * Return | 1643 | * Return |
| 1644 | * **XDP_REDIRECT** on success, or the value of the two lower bits | 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 | * int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags) | 1647 | * int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags) |
| 1648 | * Description | 1648 | * Description |
| @@ -469,7 +469,7 @@ static int cpu_map_update_elem(struct bpf_map *map, void *key, void *value, · 468 unmodified lines | |||
| 469 | return -EOVERFLOW; | 469 | return -EOVERFLOW; |
| 470 | 470 | ||
| 471 | /* Make sure CPU is a valid possible cpu */ | 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 | return -ENODEV; | 473 | return -ENODEV; |
| 474 | 474 | ||
| 475 | if (qsize == 0) { | 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 | #endif | 2284 | #endif |
| 2285 | 2285 | ||
| 2286 | const struct file_operations bpf_link_fops = { | 2286 | static const struct file_operations bpf_link_fops = { |
| 2287 | #ifdef CONFIG_PROC_FS | 2287 | #ifdef CONFIG_PROC_FS |
| 2288 | .show_fdinfo = bpf_link_show_fdinfo, | 2288 | .show_fdinfo = bpf_link_show_fdinfo, |
| 2289 | #endif | 2289 | #endif |
| @@ -3628,8 +3628,10 @@ static int link_update(union bpf_attr *attr) · 1338 unmodified lines | |||
| 3628 | return PTR_ERR(link); | 3628 | return PTR_ERR(link); |
| 3629 | 3629 | ||
| 3630 | new_prog = bpf_prog_get(attr->link_update.new_prog_fd); | 3630 | new_prog = bpf_prog_get(attr->link_update.new_prog_fd); |
| 3631 | if (IS_ERR(new_prog)) | 3631 | if (IS_ERR(new_prog)) { |
| 3632 | return PTR_ERR(new_prog); | 3632 | ret = PTR_ERR(new_prog); |
| 3633 | goto out_put_link; | ||
| 3634 | } | ||
| 3633 | 3635 | ||
| 3634 | if (flags & BPF_F_REPLACE) { | 3636 | if (flags & BPF_F_REPLACE) { |
| 3635 | old_prog = bpf_prog_get(attr->link_update.old_prog_fd); | 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 | old_prog = NULL; | 3640 | old_prog = NULL; |
| 3639 | goto out_put_progs; | 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 | #ifdef CONFIG_CGROUP_BPF | 3648 | #ifdef CONFIG_CGROUP_BPF |
| @@ -3653,6 +3658,8 @@ out_put_progs: · 9 unmodified lines | |||
| 3653 | bpf_prog_put(old_prog); | 3658 | bpf_prog_put(old_prog); |
| 3654 | if (ret) | 3659 | if (ret) |
| 3655 | bpf_prog_put(new_prog); | 3660 | bpf_prog_put(new_prog); |
| 3661 | out_put_link: | ||
| 3662 | bpf_link_put(link); | ||
| 3656 | return ret; | 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 | return reg->type == SCALAR_VALUE && tnum_is_const(reg->var_off); | 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 | static void save_register_state(struct bpf_func_state *state, | 2130 | static void save_register_state(struct bpf_func_state *state, |
| 2122 | int spi, struct bpf_reg_state *reg) | 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 | * which resets stack/reg liveness for state transitions | 2317 | * which resets stack/reg liveness for state transitions |
| 2309 | */ | 2318 | */ |
| 2310 | state->regs[value_regno].live |= REG_LIVE_WRITTEN; | 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 | mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64); | 2331 | mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64); |
| 2313 | } else { | 2332 | } else { |
| @@ -2673,15 +2692,6 @@ static int check_sock_access(struct bpf_verifier_env *env, int insn_idx, · 359 unmodified lines | |||
| 2673 | return -EACCES; | 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 | static struct bpf_reg_state *reg_state(struct bpf_verifier_env *env, int regno) | 2695 | static struct bpf_reg_state *reg_state(struct bpf_verifier_env *env, int regno) |
| 2686 | { | 2696 | { |
| 2687 | return cur_regs(env) + regno; | 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 | if (ret < 0) | 3099 | if (ret < 0) |
| 3090 | return ret; | 3100 | return ret; |
| 3091 | 3101 | ||
| 3092 | if (atype == BPF_READ) { | 3102 | if (atype == BPF_READ && value_regno >= 0) { |
| 3093 | if (ret == SCALAR_VALUE) { | 3103 | if (ret == SCALAR_VALUE) { |
| 3094 | mark_reg_unknown(env, regs, value_regno); | 3104 | mark_reg_unknown(env, regs, value_regno); |
| 3095 | return 0; | 3105 | return 0; |
| @@ -10487,6 +10497,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) · 7391 unmodified lines | |||
| 10487 | return -EINVAL; | 10497 | return -EINVAL; |
| 10488 | } | 10498 | } |
| 10489 | env->ops = bpf_verifier_ops[tgt_prog->type]; | 10499 | env->ops = bpf_verifier_ops[tgt_prog->type]; |
| 10500 | prog->expected_attach_type = tgt_prog->expected_attach_type; | ||
| 10490 | } | 10501 | } |
| 10491 | if (!tgt_prog->jited) { | 10502 | if (!tgt_prog->jited) { |
| 10492 | verbose(env, "Can attach to only JITed progs\n"); | 10503 | verbose(env, "Can attach to only JITed progs\n"); |
| @@ -10831,6 +10842,13 @@ err_release_maps: · 338 unmodified lines | |||
| 10831 | * them now. Otherwise free_used_maps() will release them. | 10842 | * them now. Otherwise free_used_maps() will release them. |
| 10832 | */ | 10843 | */ |
| 10833 | release_maps(env); | 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 | *prog = env->prog; | 10852 | *prog = env->prog; |
| 10835 | err_unlock: | 10853 | err_unlock: |
| 10836 | if (!is_priv) | 10854 | if (!is_priv) |
| @@ -479,6 +479,7 @@ static int do_unregister(int argc, char **argv) · 478 unmodified lines | |||
| 479 | 479 | ||
| 480 | static int do_register(int argc, char **argv) | 480 | static int do_register(int argc, char **argv) |
| 481 | { | 481 | { |
| 482 | struct bpf_object_load_attr load_attr = {}; | ||
| 482 | const struct bpf_map_def *def; | 483 | const struct bpf_map_def *def; |
| 483 | struct bpf_map_info info = {}; | 484 | struct bpf_map_info info = {}; |
| 484 | __u32 info_len = sizeof(info); | 485 | __u32 info_len = sizeof(info); |
| @@ -499,7 +500,12 @@ static int do_register(int argc, char **argv) · 14 unmodified lines | |||
| 499 | 500 | ||
| 500 | set_max_rlimit(); | 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 | bpf_object__close(obj); | 509 | bpf_object__close(obj); |
| 504 | return -1; | 510 | return -1; |
| 505 | } | 511 | } |
| @@ -8,7 +8,7 @@ BPFTOOL ?= $(DEFAULT_BPFTOOL) · 7 unmodified lines | |||
| 8 | LIBBPF_SRC := $(abspath ../../lib/bpf) | 8 | LIBBPF_SRC := $(abspath ../../lib/bpf) |
| 9 | BPFOBJ := $(OUTPUT)/libbpf.a | 9 | BPFOBJ := $(OUTPUT)/libbpf.a |
| 10 | BPF_INCLUDE := $(OUTPUT) | 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 | CFLAGS := -g -Wall | 12 | CFLAGS := -g -Wall |
| 13 | 13 | ||
| 14 | # Try to detect best kernel BTF source | 14 | # Try to detect best kernel BTF source |
| @@ -1642,7 +1642,7 @@ union bpf_attr { · 1641 unmodified lines | |||
| 1642 | * ifindex, but doesn't require a map to do so. | 1642 | * ifindex, but doesn't require a map to do so. |
| 1643 | * Return | 1643 | * Return |
| 1644 | * **XDP_REDIRECT** on success, or the value of the two lower bits | 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 | * int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags) | 1647 | * int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags) |
| 1648 | * Description | 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 | static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags) | 322 | static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags) |
| 323 | { | 323 | { |
| 324 | flags &= XDP_FLAGS_MODES; | ||
| 325 | |||
| 324 | if (info->attach_mode != XDP_ATTACHED_MULTI && !flags) | 326 | if (info->attach_mode != XDP_ATTACHED_MULTI && !flags) |
| 325 | return info->prog_id; | 327 | return info->prog_id; |
| 326 | if (flags & XDP_FLAGS_DRV_MODE) | 328 | if (flags & XDP_FLAGS_DRV_MODE) |
| @@ -5,7 +5,8 @@ · 4 unmodified lines | |||
| 5 | static void test_fexit_bpf2bpf_common(const char *obj_file, | 5 | static void test_fexit_bpf2bpf_common(const char *obj_file, |
| 6 | const char *target_obj_file, | 6 | const char *target_obj_file, |
| 7 | int prog_cnt, | 7 | int prog_cnt, |
| 8 | const char **prog_name) | 8 | const char **prog_name, |
| 9 | bool run_prog) | ||
| 9 | { | 10 | { |
| 10 | struct bpf_object *obj = NULL, *pkt_obj; | 11 | struct bpf_object *obj = NULL, *pkt_obj; |
| 11 | int err, pkt_fd, i; | 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 | err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC, | 20 | err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC, |
| 20 | &pkt_obj, &pkt_fd); | 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 | return; | 24 | return; |
| 23 | DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, | 25 | DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, |
| 24 | .attach_prog_fd = pkt_fd, | 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 | obj = bpf_object__open_file(obj_file, &opts); | 36 | obj = bpf_object__open_file(obj_file, &opts); |
| 35 | if (CHECK(IS_ERR_OR_NULL(obj), "obj_open", | 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 | PTR_ERR(obj))) | 39 | PTR_ERR(obj))) |
| 38 | goto close_prog; | 40 | goto close_prog; |
| 39 | 41 | ||
| @@ -49,6 +51,10 @@ static void test_fexit_bpf2bpf_common(const char *obj_file, · 9 unmodified lines | |||
| 49 | if (CHECK(IS_ERR(link[i]), "attach_trace", "failed to link\n")) | 51 | if (CHECK(IS_ERR(link[i]), "attach_trace", "failed to link\n")) |
| 50 | goto close_prog; | 52 | goto close_prog; |
| 51 | } | 53 | } |
| 54 | |||
| 55 | if (!run_prog) | ||
| 56 | goto close_prog; | ||
| 57 | |||
| 52 | data_map = bpf_object__find_map_by_name(obj, "fexit_bp.bss"); | 58 | data_map = bpf_object__find_map_by_name(obj, "fexit_bp.bss"); |
| 53 | if (CHECK(!data_map, "find_data_map", "data map not found\n")) | 59 | if (CHECK(!data_map, "find_data_map", "data map not found\n")) |
| 54 | goto close_prog; | 60 | goto close_prog; |
| @@ -89,7 +95,7 @@ static void test_target_no_callees(void) · 34 unmodified lines | |||
| 89 | test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o", | 95 | test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o", |
| 90 | "./test_pkt_md_access.o", | 96 | "./test_pkt_md_access.o", |
| 91 | ARRAY_SIZE(prog_name), | 97 | ARRAY_SIZE(prog_name), |
| 92 | prog_name); | 98 | prog_name, true); |
| 93 | } | 99 | } |
| 94 | 100 | ||
| 95 | static void test_target_yes_callees(void) | 101 | static void test_target_yes_callees(void) |
| @@ -103,7 +109,7 @@ static void test_target_yes_callees(void) · 7 unmodified lines | |||
| 103 | test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", | 109 | test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", |
| 104 | "./test_pkt_access.o", | 110 | "./test_pkt_access.o", |
| 105 | ARRAY_SIZE(prog_name), | 111 | ARRAY_SIZE(prog_name), |
| 106 | prog_name); | 112 | prog_name, true); |
| 107 | } | 113 | } |
| 108 | 114 | ||
| 109 | static void test_func_replace(void) | 115 | static void test_func_replace(void) |
| @@ -120,7 +126,18 @@ static void test_func_replace(void) · 10 unmodified lines | |||
| 120 | test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", | 126 | test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", |
| 121 | "./test_pkt_access.o", | 127 | "./test_pkt_access.o", |
| 122 | ARRAY_SIZE(prog_name), | 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 | void test_fexit_bpf2bpf(void) | 143 | void test_fexit_bpf2bpf(void) |
| @@ -128,4 +145,5 @@ void test_fexit_bpf2bpf(void) · 1 unmodified line | |||
| 128 | test_target_no_callees(); | 145 | test_target_no_callees(); |
| 129 | test_target_yes_callees(); | 146 | test_target_yes_callees(); |
| 130 | test_func_replace(); | 147 | test_func_replace(); |
| 148 | test_func_replace_verify(); | ||
| 131 | } | 149 | } |
| @@ -18,11 +18,25 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | int _version SEC("version") = 1; | 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 | SEC("cgroup/connect4") | 36 | SEC("cgroup/connect4") |
| 22 | int connect_v4_prog(struct bpf_sock_addr *ctx) | 37 | int connect_v4_prog(struct bpf_sock_addr *ctx) |
| 23 | { | 38 | { |
| 24 | struct bpf_sock_tuple tuple = {}; | 39 | struct bpf_sock_tuple tuple = {}; |
| 25 | struct sockaddr_in sa; | ||
| 26 | struct bpf_sock *sk; | 40 | struct bpf_sock *sk; |
| 27 | 41 | ||
| 28 | /* Verify that new destination is available. */ | 42 | /* Verify that new destination is available. */ |
| @@ -56,17 +70,7 @@ int connect_v4_prog(struct bpf_sock_addr *ctx) · 27 unmodified lines | |||
| 56 | ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4); | 70 | ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4); |
| 57 | ctx->user_port = bpf_htons(DST_REWRITE_PORT4); | 71 | ctx->user_port = bpf_htons(DST_REWRITE_PORT4); |
| 58 | 72 | ||
| 59 | /* Rewrite source. */ | 73 | return do_bind(ctx) ? 1 : 0; |
| 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; | ||
| 70 | } | 74 | } |
| 71 | 75 | ||
| 72 | char _license[] SEC("license") = "GPL"; | 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 | BPF_ANNOTATE_KV_PAIR(btf_map, int, struct ipv_counts); | 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 | __attribute__((noinline)) | 23 | __attribute__((noinline)) |
| 29 | int test_long_fname_2(struct dummy_tracepoint_args *arg) | 24 | int test_long_fname_2(void) |
| 30 | { | 25 | { |
| 31 | struct ipv_counts *counts; | 26 | struct ipv_counts *counts; |
| 32 | int key = 0; | 27 | int key = 0; |
| 33 | 28 | ||
| 34 | if (!arg->sock) | ||
| 35 | return 0; | ||
| 36 | |||
| 37 | counts = bpf_map_lookup_elem(&btf_map, &key); | 29 | counts = bpf_map_lookup_elem(&btf_map, &key); |
| 38 | if (!counts) | 30 | if (!counts) |
| 39 | return 0; | 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 | __attribute__((noinline)) | 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 | SEC("dummy_tracepoint") | 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 | char _license[] SEC("license") = "GPL"; | 50 | char _license[] SEC("license") = "GPL"; |
| @@ -28,20 +28,12 @@ struct { · 27 unmodified lines | |||
| 28 | __type(value, struct ipv_counts); | 28 | __type(value, struct ipv_counts); |
| 29 | } btf_map SEC(".maps"); | 29 | } btf_map SEC(".maps"); |
| 30 | 30 | ||
| 31 | struct dummy_tracepoint_args { | ||
| 32 | unsigned long long pad; | ||
| 33 | struct sock *sock; | ||
| 34 | }; | ||
| 35 | |||
| 36 | __attribute__((noinline)) | 31 | __attribute__((noinline)) |
| 37 | int test_long_fname_2(struct dummy_tracepoint_args *arg) | 32 | int test_long_fname_2(void) |
| 38 | { | 33 | { |
| 39 | struct ipv_counts *counts; | 34 | struct ipv_counts *counts; |
| 40 | int key = 0; | 35 | int key = 0; |
| 41 | 36 | ||
| 42 | if (!arg->sock) | ||
| 43 | return 0; | ||
| 44 | |||
| 45 | counts = bpf_map_lookup_elem(&btf_map, &key); | 37 | counts = bpf_map_lookup_elem(&btf_map, &key); |
| 46 | if (!counts) | 38 | if (!counts) |
| 47 | return 0; | 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 | __attribute__((noinline)) | 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 | SEC("dummy_tracepoint") | 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 | char _license[] SEC("license") = "GPL"; | 63 | char _license[] SEC("license") = "GPL"; |
| @@ -17,20 +17,12 @@ struct bpf_map_def SEC("maps") btf_map = { · 16 unmodified lines | |||
| 17 | .max_entries = 4, | 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 | __attribute__((noinline)) | 20 | __attribute__((noinline)) |
| 26 | int test_long_fname_2(struct dummy_tracepoint_args *arg) | 21 | int test_long_fname_2(void) |
| 27 | { | 22 | { |
| 28 | struct ipv_counts *counts; | 23 | struct ipv_counts *counts; |
| 29 | int key = 0; | 24 | int key = 0; |
| 30 | 25 | ||
| 31 | if (!arg->sock) | ||
| 32 | return 0; | ||
| 33 | |||
| 34 | counts = bpf_map_lookup_elem(&btf_map, &key); | 26 | counts = bpf_map_lookup_elem(&btf_map, &key); |
| 35 | if (!counts) | 27 | if (!counts) |
| 36 | return 0; | 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 | __attribute__((noinline)) | 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 | SEC("dummy_tracepoint") | 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 | char _license[] SEC("license") = "GPL"; | 47 | char _license[] SEC("license") = "GPL"; |
| @@ -2854,7 +2854,7 @@ static struct btf_raw_test raw_tests[] = { · 2853 unmodified lines | |||
| 2854 | .value_type_id = 1, | 2854 | .value_type_id = 1, |
| 2855 | .max_entries = 4, | 2855 | .max_entries = 4, |
| 2856 | .btf_load_err = true, | 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 | .result = ACCEPT, | 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 | BPF_EXIT_INSN(), | 88 | BPF_EXIT_INSN(), |
| 89 | }, | 89 | }, |
| 90 | .fixup_map_hash_48b = { 3 }, | 90 | .fixup_map_hash_48b = { 3 }, |
| 91 | .errstr_unpriv = "leaking pointer from stack off -8", | ||
| 91 | .errstr = "R0 invalid mem access 'inv'", | 92 | .errstr = "R0 invalid mem access 'inv'", |
| 92 | .result = REJECT, | 93 | .result = REJECT, |
| 93 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 94 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |