Add bpf_per_cpu_ptr() to help bpf programs access percpu vars. bpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the kernel except that it may return NULL. This happens when the cpu parameter is out of range. So the caller must check the returned value.
Unified · Split
| @@ -293,6 +293,7 @@ enum bpf_arg_type { · 292 unmodified lines | |||
| 293 | ARG_PTR_TO_ALLOC_MEM_OR_NULL, /* pointer to dynamically allocated memory or NULL */ | 293 | ARG_PTR_TO_ALLOC_MEM_OR_NULL, /* pointer to dynamically allocated memory or NULL */ |
| 294 | ARG_CONST_ALLOC_SIZE_OR_ZERO, /* number of allocated bytes requested */ | 294 | ARG_CONST_ALLOC_SIZE_OR_ZERO, /* number of allocated bytes requested */ |
| 295 | ARG_PTR_TO_BTF_ID_SOCK_COMMON, /* pointer to in-kernel sock_common or bpf-mirrored bpf_sock */ | 295 | ARG_PTR_TO_BTF_ID_SOCK_COMMON, /* pointer to in-kernel sock_common or bpf-mirrored bpf_sock */ |
| 296 | ARG_PTR_TO_PERCPU_BTF_ID, /* pointer to in-kernel percpu type */ | ||
| 296 | __BPF_ARG_TYPE_MAX, | 297 | __BPF_ARG_TYPE_MAX, |
| 297 | }; | 298 | }; |
| 298 | 299 | ||
| @@ -307,6 +308,7 @@ enum bpf_return_type { · 8 unmodified lines | |||
| 307 | RET_PTR_TO_SOCK_COMMON_OR_NULL, /* returns a pointer to a sock_common or NULL */ | 308 | RET_PTR_TO_SOCK_COMMON_OR_NULL, /* returns a pointer to a sock_common or NULL */ |
| 308 | RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */ | 309 | RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */ |
| 309 | RET_PTR_TO_BTF_ID_OR_NULL, /* returns a pointer to a btf_id or NULL */ | 310 | RET_PTR_TO_BTF_ID_OR_NULL, /* returns a pointer to a btf_id or NULL */ |
| 311 | RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, /* returns a pointer to a valid memory or a btf_id or NULL */ | ||
| 310 | }; | 312 | }; |
| 311 | 313 | ||
| 312 | /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs | 314 | /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs |
| @@ -405,6 +407,7 @@ enum bpf_reg_type { · 92 unmodified lines | |||
| 405 | PTR_TO_RDONLY_BUF_OR_NULL, /* reg points to a readonly buffer or NULL */ | 407 | PTR_TO_RDONLY_BUF_OR_NULL, /* reg points to a readonly buffer or NULL */ |
| 406 | PTR_TO_RDWR_BUF, /* reg points to a read/write buffer */ | 408 | PTR_TO_RDWR_BUF, /* reg points to a read/write buffer */ |
| 407 | PTR_TO_RDWR_BUF_OR_NULL, /* reg points to a read/write buffer or NULL */ | 409 | PTR_TO_RDWR_BUF_OR_NULL, /* reg points to a read/write buffer or NULL */ |
| 410 | PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */ | ||
| 408 | }; | 411 | }; |
| 409 | 412 | ||
| 410 | /* The information passed from prog-specific *_is_valid_access | 413 | /* The information passed from prog-specific *_is_valid_access |
| @@ -1828,6 +1831,7 @@ extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto; · 1417 unmodified lines | |||
| 1828 | extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto; | 1831 | extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto; |
| 1829 | extern const struct bpf_func_proto bpf_copy_from_user_proto; | 1832 | extern const struct bpf_func_proto bpf_copy_from_user_proto; |
| 1830 | extern const struct bpf_func_proto bpf_snprintf_btf_proto; | 1833 | extern const struct bpf_func_proto bpf_snprintf_btf_proto; |
| 1834 | extern const struct bpf_func_proto bpf_per_cpu_ptr_proto; | ||
| 1831 | 1835 | ||
| 1832 | const struct bpf_func_proto *bpf_tracing_func_proto( | 1836 | const struct bpf_func_proto *bpf_tracing_func_proto( |
| 1833 | enum bpf_func_id func_id, const struct bpf_prog *prog); | 1837 | enum bpf_func_id func_id, const struct bpf_prog *prog); |
| @@ -110,6 +110,11 @@ btf_resolve_size(const struct btf *btf, const struct btf_type *type, · 109 unmodified lines | |||
| 110 | i < btf_type_vlen(struct_type); \ | 110 | i < btf_type_vlen(struct_type); \ |
| 111 | i++, member++) | 111 | i++, member++) |
| 112 | 112 | ||
| 113 | #define for_each_vsi(i, datasec_type, member) \ | ||
| 114 | for (i = 0, member = btf_type_var_secinfo(datasec_type); \ | ||
| 115 | i < btf_type_vlen(datasec_type); \ | ||
| 116 | i++, member++) | ||
| 117 | |||
| 113 | static inline bool btf_type_is_ptr(const struct btf_type *t) | 118 | static inline bool btf_type_is_ptr(const struct btf_type *t) |
| 114 | { | 119 | { |
| 115 | return BTF_INFO_KIND(t->info) == BTF_KIND_PTR; | 120 | return BTF_INFO_KIND(t->info) == BTF_KIND_PTR; |
| @@ -194,6 +199,12 @@ static inline const struct btf_member *btf_type_member(const struct btf_type *t) · 78 unmodified lines | |||
| 194 | return (const struct btf_member *)(t + 1); | 199 | return (const struct btf_member *)(t + 1); |
| 195 | } | 200 | } |
| 196 | 201 | ||
| 202 | static inline const struct btf_var_secinfo *btf_type_var_secinfo( | ||
| 203 | const struct btf_type *t) | ||
| 204 | { | ||
| 205 | return (const struct btf_var_secinfo *)(t + 1); | ||
| 206 | } | ||
| 207 | |||
| 197 | #ifdef CONFIG_BPF_SYSCALL | 208 | #ifdef CONFIG_BPF_SYSCALL |
| 198 | const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); | 209 | const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); |
| 199 | const char *btf_name_by_offset(const struct btf *btf, u32 offset); | 210 | const char *btf_name_by_offset(const struct btf *btf, u32 offset); |
| @@ -3686,6 +3686,23 @@ union bpf_attr { · 3685 unmodified lines | |||
| 3686 | * Return | 3686 | * Return |
| 3687 | * The helper returns **TC_ACT_REDIRECT** on success or | 3687 | * The helper returns **TC_ACT_REDIRECT** on success or |
| 3688 | * **TC_ACT_SHOT** on error. | 3688 | * **TC_ACT_SHOT** on error. |
| 3689 | * | ||
| 3690 | * void *bpf_per_cpu_ptr(const void *percpu_ptr, u32 cpu) | ||
| 3691 | * Description | ||
| 3692 | * Take a pointer to a percpu ksym, *percpu_ptr*, and return a | ||
| 3693 | * pointer to the percpu kernel variable on *cpu*. A ksym is an | ||
| 3694 | * extern variable decorated with '__ksym'. For ksym, there is a | ||
| 3695 | * global var (either static or global) defined of the same name | ||
| 3696 | * in the kernel. The ksym is percpu if the global var is percpu. | ||
| 3697 | * The returned pointer points to the global percpu var on *cpu*. | ||
| 3698 | * | ||
| 3699 | * bpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the | ||
| 3700 | * kernel, except that bpf_per_cpu_ptr() may return NULL. This | ||
| 3701 | * happens if *cpu* is larger than nr_cpu_ids. The caller of | ||
| 3702 | * bpf_per_cpu_ptr() must check the returned value. | ||
| 3703 | * Return | ||
| 3704 | * A pointer pointing to the kernel percpu variable on *cpu*, or | ||
| 3705 | * NULL, if *cpu* is invalid. | ||
| 3689 | */ | 3706 | */ |
| 3690 | #define __BPF_FUNC_MAPPER(FN) \ | 3707 | #define __BPF_FUNC_MAPPER(FN) \ |
| 3691 | FN(unspec), \ | 3708 | FN(unspec), \ |
| @@ -3841,6 +3858,7 @@ union bpf_attr { · 149 unmodified lines | |||
| 3841 | FN(seq_printf_btf), \ | 3858 | FN(seq_printf_btf), \ |
| 3842 | FN(skb_cgroup_classid), \ | 3859 | FN(skb_cgroup_classid), \ |
| 3843 | FN(redirect_neigh), \ | 3860 | FN(redirect_neigh), \ |
| 3861 | FN(bpf_per_cpu_ptr), \ | ||
| 3844 | /* */ | 3862 | /* */ |
| 3845 | 3863 | ||
| 3846 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper | 3864 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
| @@ -188,11 +188,6 @@ · 187 unmodified lines | |||
| 188 | i < btf_type_vlen(struct_type); \ | 188 | i < btf_type_vlen(struct_type); \ |
| 189 | i++, member++) | 189 | i++, member++) |
| 190 | 190 | ||
| 191 | #define for_each_vsi(i, struct_type, member) \ | ||
| 192 | for (i = 0, member = btf_type_var_secinfo(struct_type); \ | ||
| 193 | i < btf_type_vlen(struct_type); \ | ||
| 194 | i++, member++) | ||
| 195 | |||
| 196 | #define for_each_vsi_from(i, from, struct_type, member) \ | 191 | #define for_each_vsi_from(i, from, struct_type, member) \ |
| 197 | for (i = from, member = btf_type_var_secinfo(struct_type) + from; \ | 192 | for (i = from, member = btf_type_var_secinfo(struct_type) + from; \ |
| 198 | i < btf_type_vlen(struct_type); \ | 193 | i < btf_type_vlen(struct_type); \ |
| @@ -598,11 +593,6 @@ static const struct btf_var *btf_type_var(const struct btf_type *t) · 399 unmodified lines | |||
| 598 | return (const struct btf_var *)(t + 1); | 593 | return (const struct btf_var *)(t + 1); |
| 599 | } | 594 | } |
| 600 | 595 | ||
| 601 | static const struct btf_var_secinfo *btf_type_var_secinfo(const struct btf_type *t) | ||
| 602 | { | ||
| 603 | return (const struct btf_var_secinfo *)(t + 1); | ||
| 604 | } | ||
| 605 | |||
| 606 | static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) | 596 | static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) |
| 607 | { | 597 | { |
| 608 | return kind_ops[BTF_INFO_KIND(t->info)]; | 598 | return kind_ops[BTF_INFO_KIND(t->info)]; |
| @@ -623,6 +623,22 @@ const struct bpf_func_proto bpf_copy_from_user_proto = { · 622 unmodified lines | |||
| 623 | .arg3_type = ARG_ANYTHING, | 623 | .arg3_type = ARG_ANYTHING, |
| 624 | }; | 624 | }; |
| 625 | 625 | ||
| 626 | BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu) | ||
| 627 | { | ||
| 628 | if (cpu >= nr_cpu_ids) | ||
| 629 | return (unsigned long)NULL; | ||
| 630 | |||
| 631 | return (unsigned long)per_cpu_ptr((const void __percpu *)ptr, cpu); | ||
| 632 | } | ||
| 633 | |||
| 634 | const struct bpf_func_proto bpf_per_cpu_ptr_proto = { | ||
| 635 | .func = bpf_per_cpu_ptr, | ||
| 636 | .gpl_only = false, | ||
| 637 | .ret_type = RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, | ||
| 638 | .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, | ||
| 639 | .arg2_type = ARG_ANYTHING, | ||
| 640 | }; | ||
| 641 | |||
| 626 | const struct bpf_func_proto bpf_get_current_task_proto __weak; | 642 | const struct bpf_func_proto bpf_get_current_task_proto __weak; |
| 627 | const struct bpf_func_proto bpf_probe_read_user_proto __weak; | 643 | const struct bpf_func_proto bpf_probe_read_user_proto __weak; |
| 628 | const struct bpf_func_proto bpf_probe_read_user_str_proto __weak; | 644 | const struct bpf_func_proto bpf_probe_read_user_str_proto __weak; |
| @@ -689,6 +705,8 @@ bpf_base_func_proto(enum bpf_func_id func_id) · 60 unmodified lines | |||
| 689 | return &bpf_snprintf_btf_proto; | 705 | return &bpf_snprintf_btf_proto; |
| 690 | case BPF_FUNC_jiffies64: | 706 | case BPF_FUNC_jiffies64: |
| 691 | return &bpf_jiffies64_proto; | 707 | return &bpf_jiffies64_proto; |
| 708 | case BPF_FUNC_bpf_per_cpu_ptr: | ||
| 709 | return &bpf_per_cpu_ptr_proto; | ||
| 692 | default: | 710 | default: |
| 693 | break; | 711 | break; |
| 694 | } | 712 | } |
| @@ -238,6 +238,8 @@ struct bpf_call_arg_meta { · 237 unmodified lines | |||
| 238 | u64 msize_max_value; | 238 | u64 msize_max_value; |
| 239 | int ref_obj_id; | 239 | int ref_obj_id; |
| 240 | int func_id; | 240 | int func_id; |
| 241 | u32 btf_id; | ||
| 242 | u32 ret_btf_id; | ||
| 241 | }; | 243 | }; |
| 242 | 244 | ||
| 243 | struct btf *btf_vmlinux; | 245 | struct btf *btf_vmlinux; |
| @@ -517,6 +519,7 @@ static const char * const reg_type_str[] = { · 273 unmodified lines | |||
| 517 | [PTR_TO_XDP_SOCK] = "xdp_sock", | 519 | [PTR_TO_XDP_SOCK] = "xdp_sock", |
| 518 | [PTR_TO_BTF_ID] = "ptr_", | 520 | [PTR_TO_BTF_ID] = "ptr_", |
| 519 | [PTR_TO_BTF_ID_OR_NULL] = "ptr_or_null_", | 521 | [PTR_TO_BTF_ID_OR_NULL] = "ptr_or_null_", |
| 522 | [PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_", | ||
| 520 | [PTR_TO_MEM] = "mem", | 523 | [PTR_TO_MEM] = "mem", |
| 521 | [PTR_TO_MEM_OR_NULL] = "mem_or_null", | 524 | [PTR_TO_MEM_OR_NULL] = "mem_or_null", |
| 522 | [PTR_TO_RDONLY_BUF] = "rdonly_buf", | 525 | [PTR_TO_RDONLY_BUF] = "rdonly_buf", |
| @@ -583,7 +586,9 @@ static void print_verifier_state(struct bpf_verifier_env *env, · 60 unmodified lines | |||
| 583 | /* reg->off should be 0 for SCALAR_VALUE */ | 586 | /* reg->off should be 0 for SCALAR_VALUE */ |
| 584 | verbose(env, "%lld", reg->var_off.value + reg->off); | 587 | verbose(env, "%lld", reg->var_off.value + reg->off); |
| 585 | } else { | 588 | } else { |
| 586 | if (t == PTR_TO_BTF_ID || t == PTR_TO_BTF_ID_OR_NULL) | 589 | if (t == PTR_TO_BTF_ID || |
| 590 | t == PTR_TO_BTF_ID_OR_NULL || | ||
| 591 | t == PTR_TO_PERCPU_BTF_ID) | ||
| 587 | verbose(env, "%s", kernel_type_name(reg->btf_id)); | 592 | verbose(env, "%s", kernel_type_name(reg->btf_id)); |
| 588 | verbose(env, "(id=%d", reg->id); | 593 | verbose(env, "(id=%d", reg->id); |
| 589 | if (reg_type_may_be_refcounted_or_null(t)) | 594 | if (reg_type_may_be_refcounted_or_null(t)) |
| @@ -2204,6 +2209,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type) · 1614 unmodified lines | |||
| 2204 | case PTR_TO_RDONLY_BUF_OR_NULL: | 2209 | case PTR_TO_RDONLY_BUF_OR_NULL: |
| 2205 | case PTR_TO_RDWR_BUF: | 2210 | case PTR_TO_RDWR_BUF: |
| 2206 | case PTR_TO_RDWR_BUF_OR_NULL: | 2211 | case PTR_TO_RDWR_BUF_OR_NULL: |
| 2212 | case PTR_TO_PERCPU_BTF_ID: | ||
| 2207 | return true; | 2213 | return true; |
| 2208 | default: | 2214 | default: |
| 2209 | return false; | 2215 | return false; |
| @@ -4017,6 +4023,7 @@ static const struct bpf_reg_types alloc_mem_types = { .types = { PTR_TO_MEM } }; · 1807 unmodified lines | |||
| 4017 | static const struct bpf_reg_types const_map_ptr_types = { .types = { CONST_PTR_TO_MAP } }; | 4023 | static const struct bpf_reg_types const_map_ptr_types = { .types = { CONST_PTR_TO_MAP } }; |
| 4018 | static const struct bpf_reg_types btf_ptr_types = { .types = { PTR_TO_BTF_ID } }; | 4024 | static const struct bpf_reg_types btf_ptr_types = { .types = { PTR_TO_BTF_ID } }; |
| 4019 | static const struct bpf_reg_types spin_lock_types = { .types = { PTR_TO_MAP_VALUE } }; | 4025 | static const struct bpf_reg_types spin_lock_types = { .types = { PTR_TO_MAP_VALUE } }; |
| 4026 | static const struct bpf_reg_types percpu_btf_ptr_types = { .types = { PTR_TO_PERCPU_BTF_ID } }; | ||
| 4020 | 4027 | ||
| 4021 | static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { | 4028 | static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { |
| 4022 | [ARG_PTR_TO_MAP_KEY] = &map_key_value_types, | 4029 | [ARG_PTR_TO_MAP_KEY] = &map_key_value_types, |
| @@ -4042,6 +4049,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { · 19 unmodified lines | |||
| 4042 | [ARG_PTR_TO_ALLOC_MEM_OR_NULL] = &alloc_mem_types, | 4049 | [ARG_PTR_TO_ALLOC_MEM_OR_NULL] = &alloc_mem_types, |
| 4043 | [ARG_PTR_TO_INT] = &int_ptr_types, | 4050 | [ARG_PTR_TO_INT] = &int_ptr_types, |
| 4044 | [ARG_PTR_TO_LONG] = &int_ptr_types, | 4051 | [ARG_PTR_TO_LONG] = &int_ptr_types, |
| 4052 | [ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types, | ||
| 4045 | }; | 4053 | }; |
| 4046 | 4054 | ||
| 4047 | static int check_reg_type(struct bpf_verifier_env *env, u32 regno, | 4055 | static int check_reg_type(struct bpf_verifier_env *env, u32 regno, |
| @@ -4205,6 +4213,12 @@ skip_type_check: · 157 unmodified lines | |||
| 4205 | err = check_helper_mem_access(env, regno, | 4213 | err = check_helper_mem_access(env, regno, |
| 4206 | meta->map_ptr->value_size, false, | 4214 | meta->map_ptr->value_size, false, |
| 4207 | meta); | 4215 | meta); |
| 4216 | } else if (arg_type == ARG_PTR_TO_PERCPU_BTF_ID) { | ||
| 4217 | if (!reg->btf_id) { | ||
| 4218 | verbose(env, "Helper has invalid btf_id in R%d\n", regno); | ||
| 4219 | return -EACCES; | ||
| 4220 | } | ||
| 4221 | meta->ret_btf_id = reg->btf_id; | ||
| 4208 | } else if (arg_type == ARG_PTR_TO_SPIN_LOCK) { | 4222 | } else if (arg_type == ARG_PTR_TO_SPIN_LOCK) { |
| 4209 | if (meta->func_id == BPF_FUNC_spin_lock) { | 4223 | if (meta->func_id == BPF_FUNC_spin_lock) { |
| 4210 | if (process_spin_lock(env, regno, true)) | 4224 | if (process_spin_lock(env, regno, true)) |
| @@ -5114,6 +5128,30 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn · 903 unmodified lines | |||
| 5114 | regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; | 5128 | regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; |
| 5115 | regs[BPF_REG_0].id = ++env->id_gen; | 5129 | regs[BPF_REG_0].id = ++env->id_gen; |
| 5116 | regs[BPF_REG_0].mem_size = meta.mem_size; | 5130 | regs[BPF_REG_0].mem_size = meta.mem_size; |
| 5131 | } else if (fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL) { | ||
| 5132 | const struct btf_type *t; | ||
| 5133 | |||
| 5134 | mark_reg_known_zero(env, regs, BPF_REG_0); | ||
| 5135 | t = btf_type_skip_modifiers(btf_vmlinux, meta.ret_btf_id, NULL); | ||
| 5136 | if (!btf_type_is_struct(t)) { | ||
| 5137 | u32 tsize; | ||
| 5138 | const struct btf_type *ret; | ||
| 5139 | const char *tname; | ||
| 5140 | |||
| 5141 | /* resolve the type size of ksym. */ | ||
| 5142 | ret = btf_resolve_size(btf_vmlinux, t, &tsize); | ||
| 5143 | if (IS_ERR(ret)) { | ||
| 5144 | tname = btf_name_by_offset(btf_vmlinux, t->name_off); | ||
| 5145 | verbose(env, "unable to resolve the size of type '%s': %ld\n", | ||
| 5146 | tname, PTR_ERR(ret)); | ||
| 5147 | return -EINVAL; | ||
| 5148 | } | ||
| 5149 | regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; | ||
| 5150 | regs[BPF_REG_0].mem_size = tsize; | ||
| 5151 | } else { | ||
| 5152 | regs[BPF_REG_0].type = PTR_TO_BTF_ID_OR_NULL; | ||
| 5153 | regs[BPF_REG_0].btf_id = meta.ret_btf_id; | ||
| 5154 | } | ||
| 5117 | } else if (fn->ret_type == RET_PTR_TO_BTF_ID_OR_NULL) { | 5155 | } else if (fn->ret_type == RET_PTR_TO_BTF_ID_OR_NULL) { |
| 5118 | int ret_btf_id; | 5156 | int ret_btf_id; |
| 5119 | 5157 | ||
| @@ -7523,6 +7561,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn) · 2403 unmodified lines | |||
| 7523 | dst_reg->mem_size = aux->btf_var.mem_size; | 7561 | dst_reg->mem_size = aux->btf_var.mem_size; |
| 7524 | break; | 7562 | break; |
| 7525 | case PTR_TO_BTF_ID: | 7563 | case PTR_TO_BTF_ID: |
| 7564 | case PTR_TO_PERCPU_BTF_ID: | ||
| 7526 | dst_reg->btf_id = aux->btf_var.btf_id; | 7565 | dst_reg->btf_id = aux->btf_var.btf_id; |
| 7527 | break; | 7566 | break; |
| 7528 | default: | 7567 | default: |
| @@ -9449,10 +9488,14 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env, · 1920 unmodified lines | |||
| 9449 | struct bpf_insn *insn, | 9488 | struct bpf_insn *insn, |
| 9450 | struct bpf_insn_aux_data *aux) | 9489 | struct bpf_insn_aux_data *aux) |
| 9451 | { | 9490 | { |
| 9452 | u32 type, id = insn->imm; | 9491 | u32 datasec_id, type, id = insn->imm; |
| 9492 | const struct btf_var_secinfo *vsi; | ||
| 9493 | const struct btf_type *datasec; | ||
| 9453 | const struct btf_type *t; | 9494 | const struct btf_type *t; |
| 9454 | const char *sym_name; | 9495 | const char *sym_name; |
| 9496 | bool percpu = false; | ||
| 9455 | u64 addr; | 9497 | u64 addr; |
| 9498 | int i; | ||
| 9456 | 9499 | ||
| 9457 | if (!btf_vmlinux) { | 9500 | if (!btf_vmlinux) { |
| 9458 | verbose(env, "kernel is missing BTF, make sure CONFIG_DEBUG_INFO_BTF=y is specified in Kconfig.\n"); | 9501 | verbose(env, "kernel is missing BTF, make sure CONFIG_DEBUG_INFO_BTF=y is specified in Kconfig.\n"); |
| @@ -9484,12 +9527,27 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env, · 25 unmodified lines | |||
| 9484 | return -ENOENT; | 9527 | return -ENOENT; |
| 9485 | } | 9528 | } |
| 9486 | 9529 | ||
| 9530 | datasec_id = btf_find_by_name_kind(btf_vmlinux, ".data..percpu", | ||
| 9531 | BTF_KIND_DATASEC); | ||
| 9532 | if (datasec_id > 0) { | ||
| 9533 | datasec = btf_type_by_id(btf_vmlinux, datasec_id); | ||
| 9534 | for_each_vsi(i, datasec, vsi) { | ||
| 9535 | if (vsi->type == id) { | ||
| 9536 | percpu = true; | ||
| 9537 | break; | ||
| 9538 | } | ||
| 9539 | } | ||
| 9540 | } | ||
| 9541 | |||
| 9487 | insn[0].imm = (u32)addr; | 9542 | insn[0].imm = (u32)addr; |
| 9488 | insn[1].imm = addr >> 32; | 9543 | insn[1].imm = addr >> 32; |
| 9489 | 9544 | ||
| 9490 | type = t->type; | 9545 | type = t->type; |
| 9491 | t = btf_type_skip_modifiers(btf_vmlinux, type, NULL); | 9546 | t = btf_type_skip_modifiers(btf_vmlinux, type, NULL); |
| 9492 | if (!btf_type_is_struct(t)) { | 9547 | if (percpu) { |
| 9548 | aux->btf_var.reg_type = PTR_TO_PERCPU_BTF_ID; | ||
| 9549 | aux->btf_var.btf_id = type; | ||
| 9550 | } else if (!btf_type_is_struct(t)) { | ||
| 9493 | const struct btf_type *ret; | 9551 | const struct btf_type *ret; |
| 9494 | const char *tname; | 9552 | const char *tname; |
| 9495 | u32 tsize; | 9553 | u32 tsize; |
| @@ -1327,6 +1327,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 1326 unmodified lines | |||
| 1327 | return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL; | 1327 | return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL; |
| 1328 | case BPF_FUNC_snprintf_btf: | 1328 | case BPF_FUNC_snprintf_btf: |
| 1329 | return &bpf_snprintf_btf_proto; | 1329 | return &bpf_snprintf_btf_proto; |
| 1330 | case BPF_FUNC_bpf_per_cpu_ptr: | ||
| 1331 | return &bpf_per_cpu_ptr_proto; | ||
| 1330 | default: | 1332 | default: |
| 1331 | return NULL; | 1333 | return NULL; |
| 1332 | } | 1334 | } |
| @@ -3686,6 +3686,23 @@ union bpf_attr { · 3685 unmodified lines | |||
| 3686 | * Return | 3686 | * Return |
| 3687 | * The helper returns **TC_ACT_REDIRECT** on success or | 3687 | * The helper returns **TC_ACT_REDIRECT** on success or |
| 3688 | * **TC_ACT_SHOT** on error. | 3688 | * **TC_ACT_SHOT** on error. |
| 3689 | * | ||
| 3690 | * void *bpf_per_cpu_ptr(const void *percpu_ptr, u32 cpu) | ||
| 3691 | * Description | ||
| 3692 | * Take a pointer to a percpu ksym, *percpu_ptr*, and return a | ||
| 3693 | * pointer to the percpu kernel variable on *cpu*. A ksym is an | ||
| 3694 | * extern variable decorated with '__ksym'. For ksym, there is a | ||
| 3695 | * global var (either static or global) defined of the same name | ||
| 3696 | * in the kernel. The ksym is percpu if the global var is percpu. | ||
| 3697 | * The returned pointer points to the global percpu var on *cpu*. | ||
| 3698 | * | ||
| 3699 | * bpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the | ||
| 3700 | * kernel, except that bpf_per_cpu_ptr() may return NULL. This | ||
| 3701 | * happens if *cpu* is larger than nr_cpu_ids. The caller of | ||
| 3702 | * bpf_per_cpu_ptr() must check the returned value. | ||
| 3703 | * Return | ||
| 3704 | * A pointer pointing to the kernel percpu variable on *cpu*, or | ||
| 3705 | * NULL, if *cpu* is invalid. | ||
| 3689 | */ | 3706 | */ |
| 3690 | #define __BPF_FUNC_MAPPER(FN) \ | 3707 | #define __BPF_FUNC_MAPPER(FN) \ |
| 3691 | FN(unspec), \ | 3708 | FN(unspec), \ |
| @@ -3841,6 +3858,7 @@ union bpf_attr { · 149 unmodified lines | |||
| 3841 | FN(seq_printf_btf), \ | 3858 | FN(seq_printf_btf), \ |
| 3842 | FN(skb_cgroup_classid), \ | 3859 | FN(skb_cgroup_classid), \ |
| 3843 | FN(redirect_neigh), \ | 3860 | FN(redirect_neigh), \ |
| 3861 | FN(bpf_per_cpu_ptr), \ | ||
| 3844 | /* */ | 3862 | /* */ |
| 3845 | 3863 | ||
| 3846 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper | 3864 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |