| @@ -238,6 +238,8 @@ struct bpf_call_arg_meta { · 237 unmodified lines |
| 238 | 238 | u64 msize_max_value; |
| 239 | 239 | int ref_obj_id; |
| 240 | 240 | int func_id; |
| 241 | + u32 btf_id; |
| 242 | + u32 ret_btf_id; |
| 241 | 243 | }; |
| 242 | 244 | |
| 243 | 245 | struct btf *btf_vmlinux; |
| @@ -517,6 +519,7 @@ static const char * const reg_type_str[] = { · 273 unmodified lines |
| 517 | 519 | [PTR_TO_XDP_SOCK] = "xdp_sock", |
| 518 | 520 | [PTR_TO_BTF_ID] = "ptr_", |
| 519 | 521 | [PTR_TO_BTF_ID_OR_NULL] = "ptr_or_null_", |
| 522 | + [PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_", |
| 520 | 523 | [PTR_TO_MEM] = "mem", |
| 521 | 524 | [PTR_TO_MEM_OR_NULL] = "mem_or_null", |
| 522 | 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 | 586 | /* reg->off should be 0 for SCALAR_VALUE */ |
| 584 | 587 | verbose(env, "%lld", reg->var_off.value + reg->off); |
| 585 | 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 | 592 | verbose(env, "%s", kernel_type_name(reg->btf_id)); |
| 588 | 593 | verbose(env, "(id=%d", reg->id); |
| 589 | 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 | 2209 | case PTR_TO_RDONLY_BUF_OR_NULL: |
| 2205 | 2210 | case PTR_TO_RDWR_BUF: |
| 2206 | 2211 | case PTR_TO_RDWR_BUF_OR_NULL: |
| 2212 | + case PTR_TO_PERCPU_BTF_ID: |
| 2207 | 2213 | return true; |
| 2208 | 2214 | default: |
| 2209 | 2215 | return false; |
| @@ -4017,6 +4023,7 @@ static const struct bpf_reg_types alloc_mem_types = { .types = { PTR_TO_MEM } }; · 1807 unmodified lines |
| 4017 | 4023 | static const struct bpf_reg_types const_map_ptr_types = { .types = { CONST_PTR_TO_MAP } }; |
| 4018 | 4024 | static const struct bpf_reg_types btf_ptr_types = { .types = { PTR_TO_BTF_ID } }; |
| 4019 | 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 | 4028 | static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { |
| 4022 | 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 | 4049 | [ARG_PTR_TO_ALLOC_MEM_OR_NULL] = &alloc_mem_types, |
| 4043 | 4050 | [ARG_PTR_TO_INT] = &int_ptr_types, |
| 4044 | 4051 | [ARG_PTR_TO_LONG] = &int_ptr_types, |
| 4052 | + [ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types, |
| 4045 | 4053 | }; |
| 4046 | 4054 | |
| 4047 | 4055 | static int check_reg_type(struct bpf_verifier_env *env, u32 regno, |
| @@ -4205,6 +4213,12 @@ skip_type_check: · 157 unmodified lines |
| 4205 | 4213 | err = check_helper_mem_access(env, regno, |
| 4206 | 4214 | meta->map_ptr->value_size, false, |
| 4207 | 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 | 4222 | } else if (arg_type == ARG_PTR_TO_SPIN_LOCK) { |
| 4209 | 4223 | if (meta->func_id == BPF_FUNC_spin_lock) { |
| 4210 | 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 | 5128 | regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; |
| 5115 | 5129 | regs[BPF_REG_0].id = ++env->id_gen; |
| 5116 | 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 | 5155 | } else if (fn->ret_type == RET_PTR_TO_BTF_ID_OR_NULL) { |
| 5118 | 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 | 7561 | dst_reg->mem_size = aux->btf_var.mem_size; |
| 7524 | 7562 | break; |
| 7525 | 7563 | case PTR_TO_BTF_ID: |
| 7564 | + case PTR_TO_PERCPU_BTF_ID: |
| 7526 | 7565 | dst_reg->btf_id = aux->btf_var.btf_id; |
| 7527 | 7566 | break; |
| 7528 | 7567 | default: |
| @@ -9449,10 +9488,14 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env, · 1920 unmodified lines |
| 9449 | 9488 | struct bpf_insn *insn, |
| 9450 | 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 | 9494 | const struct btf_type *t; |
| 9454 | 9495 | const char *sym_name; |
| 9496 | + bool percpu = false; |
| 9455 | 9497 | u64 addr; |
| 9498 | + int i; |
| 9456 | 9499 | |
| 9457 | 9500 | if (!btf_vmlinux) { |
| 9458 | 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 | 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 | 9542 | insn[0].imm = (u32)addr; |
| 9488 | 9543 | insn[1].imm = addr >> 32; |
| 9489 | 9544 | |
| 9490 | 9545 | type = t->type; |
| 9491 | 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 | 9551 | const struct btf_type *ret; |
| 9494 | 9552 | const char *tname; |
| 9495 | 9553 | u32 tsize; |