@@ -238,6 +238,8 @@ struct bpf_call_arg_meta {
238238 u64 msize_max_value ;
239239 int ref_obj_id ;
240240 int func_id ;
241+ u32 btf_id ;
242+ u32 ret_btf_id ;
241243};
242244
243245struct btf * btf_vmlinux ;
@@ -517,6 +519,7 @@ static const char * const reg_type_str[] = {
517519 [PTR_TO_XDP_SOCK ] = "xdp_sock" ,
518520 [PTR_TO_BTF_ID ] = "ptr_" ,
519521 [PTR_TO_BTF_ID_OR_NULL ] = "ptr_or_null_" ,
522+ [PTR_TO_PERCPU_BTF_ID ] = "percpu_ptr_" ,
520523 [PTR_TO_MEM ] = "mem" ,
521524 [PTR_TO_MEM_OR_NULL ] = "mem_or_null" ,
522525 [PTR_TO_RDONLY_BUF ] = "rdonly_buf" ,
@@ -583,7 +586,9 @@ static void print_verifier_state(struct bpf_verifier_env *env,
583586 /* reg->off should be 0 for SCALAR_VALUE */
584587 verbose (env , "%lld" , reg -> var_off .value + reg -> off );
585588 } 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 )
587592 verbose (env , "%s" , kernel_type_name (reg -> btf_id ));
588593 verbose (env , "(id=%d" , reg -> id );
589594 if (reg_type_may_be_refcounted_or_null (t ))
@@ -2204,6 +2209,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
22042209 case PTR_TO_RDONLY_BUF_OR_NULL :
22052210 case PTR_TO_RDWR_BUF :
22062211 case PTR_TO_RDWR_BUF_OR_NULL :
2212+ case PTR_TO_PERCPU_BTF_ID :
22072213 return true;
22082214 default :
22092215 return false;
@@ -4017,6 +4023,7 @@ static const struct bpf_reg_types alloc_mem_types = { .types = { PTR_TO_MEM } };
40174023static const struct bpf_reg_types const_map_ptr_types = { .types = { CONST_PTR_TO_MAP } };
40184024static const struct bpf_reg_types btf_ptr_types = { .types = { PTR_TO_BTF_ID } };
40194025static 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 } };
40204027
40214028static const struct bpf_reg_types * compatible_reg_types [__BPF_ARG_TYPE_MAX ] = {
40224029 [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] = {
40424049 [ARG_PTR_TO_ALLOC_MEM_OR_NULL ] = & alloc_mem_types ,
40434050 [ARG_PTR_TO_INT ] = & int_ptr_types ,
40444051 [ARG_PTR_TO_LONG ] = & int_ptr_types ,
4052+ [ARG_PTR_TO_PERCPU_BTF_ID ] = & percpu_btf_ptr_types ,
40454053};
40464054
40474055static int check_reg_type (struct bpf_verifier_env * env , u32 regno ,
@@ -4205,6 +4213,12 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
42054213 err = check_helper_mem_access (env , regno ,
42064214 meta -> map_ptr -> value_size , false,
42074215 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 ;
42084222 } else if (arg_type == ARG_PTR_TO_SPIN_LOCK ) {
42094223 if (meta -> func_id == BPF_FUNC_spin_lock ) {
42104224 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
51145128 regs [BPF_REG_0 ].type = PTR_TO_MEM_OR_NULL ;
51155129 regs [BPF_REG_0 ].id = ++ env -> id_gen ;
51165130 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+ }
51175155 } else if (fn -> ret_type == RET_PTR_TO_BTF_ID_OR_NULL ) {
51185156 int ret_btf_id ;
51195157
@@ -7523,6 +7561,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
75237561 dst_reg -> mem_size = aux -> btf_var .mem_size ;
75247562 break ;
75257563 case PTR_TO_BTF_ID :
7564+ case PTR_TO_PERCPU_BTF_ID :
75267565 dst_reg -> btf_id = aux -> btf_var .btf_id ;
75277566 break ;
75287567 default :
@@ -9449,10 +9488,14 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
94499488 struct bpf_insn * insn ,
94509489 struct bpf_insn_aux_data * aux )
94519490{
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 ;
94539494 const struct btf_type * t ;
94549495 const char * sym_name ;
9496+ bool percpu = false;
94559497 u64 addr ;
9498+ int i ;
94569499
94579500 if (!btf_vmlinux ) {
94589501 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,
94849527 return - ENOENT ;
94859528 }
94869529
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+
94879542 insn [0 ].imm = (u32 )addr ;
94889543 insn [1 ].imm = addr >> 32 ;
94899544
94909545 type = t -> type ;
94919546 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 )) {
94939551 const struct btf_type * ret ;
94949552 const char * tname ;
94959553 u32 tsize ;
0 commit comments