@@ -8431,34 +8431,59 @@ static int process_spin_lock(struct bpf_verifier_env *env, int regno, int flags)
84318431 return 0;
84328432}
84338433
8434- static int process_timer_func(struct bpf_verifier_env *env, int regno,
8435- struct bpf_call_arg_meta *meta)
8434+ /* Check if @regno is a pointer to a specific field in a map value */
8435+ static int check_map_field_pointer(struct bpf_verifier_env *env, u32 regno,
8436+ enum btf_field_type field_type)
84368437{
84378438 struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno];
84388439 bool is_const = tnum_is_const(reg->var_off);
84398440 struct bpf_map *map = reg->map_ptr;
84408441 u64 val = reg->var_off.value;
8442+ const char *struct_name = btf_field_type_name(field_type);
8443+ int field_off = -1;
84418444
84428445 if (!is_const) {
84438446 verbose(env,
8444- "R%d doesn't have constant offset. bpf_timer has to be at the constant offset\n",
8445- regno);
8447+ "R%d doesn't have constant offset. %s has to be at the constant offset\n",
8448+ regno, struct_name );
84468449 return -EINVAL;
84478450 }
84488451 if (!map->btf) {
8449- verbose(env, "map '%s' has to have BTF in order to use bpf_timer \n",
8450- map->name );
8452+ verbose(env, "map '%s' has to have BTF in order to use %s \n", map->name ,
8453+ struct_name );
84518454 return -EINVAL;
84528455 }
8453- if (!btf_record_has_field(map->record, BPF_TIMER )) {
8454- verbose(env, "map '%s' has no valid bpf_timer \n", map->name);
8456+ if (!btf_record_has_field(map->record, field_type )) {
8457+ verbose(env, "map '%s' has no valid %s \n", map->name, struct_name );
84558458 return -EINVAL;
84568459 }
8457- if (map->record->timer_off != val + reg->off) {
8458- verbose(env, "off %lld doesn't point to 'struct bpf_timer' that is at %d\n",
8459- val + reg->off, map->record->timer_off);
8460+ switch (field_type) {
8461+ case BPF_TIMER:
8462+ field_off = map->record->timer_off;
8463+ break;
8464+ default:
8465+ verifier_bug(env, "unsupported BTF field type: %s\n", struct_name);
84608466 return -EINVAL;
84618467 }
8468+ if (field_off != val + reg->off) {
8469+ verbose(env, "off %lld doesn't point to 'struct %s' that is at %d\n",
8470+ val + reg->off, struct_name, field_off);
8471+ return -EINVAL;
8472+ }
8473+ return 0;
8474+ }
8475+
8476+ static int process_timer_func(struct bpf_verifier_env *env, int regno,
8477+ struct bpf_call_arg_meta *meta)
8478+ {
8479+ struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno];
8480+ struct bpf_map *map = reg->map_ptr;
8481+ int err;
8482+
8483+ err = check_map_field_pointer(env, regno, BPF_TIMER);
8484+ if (err)
8485+ return err;
8486+
84628487 if (meta->map_ptr) {
84638488 verifier_bug(env, "Two map pointers in a timer helper");
84648489 return -EFAULT;
0 commit comments