]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
bpf: extract generic helper from process_timer_func()
authorMykyta Yatsenko <yatsenko@meta.com>
Tue, 23 Sep 2025 11:23:57 +0000 (12:23 +0100)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 23 Sep 2025 14:34:38 +0000 (07:34 -0700)
Refactor the verifier by pulling the common logic from
process_timer_func() into a dedicated helper. This allows reusing
process_async_func() helper for verifying bpf_task_work struct in the
next patch.

Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://lore.kernel.org/r/20250923112404.668720-3-mykyta.yatsenko5@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index 1d4183bc3cd1e928676283c51e1e86a0adcd2b2f..c1b726fb22c8ee83f025065bd41c4e639daf6294 100644 (file)
@@ -8431,34 +8431,59 @@ static int process_spin_lock(struct bpf_verifier_env *env, int regno, int flags)
        return 0;
 }
 
-static int process_timer_func(struct bpf_verifier_env *env, int regno,
-                             struct bpf_call_arg_meta *meta)
+/* Check if @regno is a pointer to a specific field in a map value */
+static int check_map_field_pointer(struct bpf_verifier_env *env, u32 regno,
+                                  enum btf_field_type field_type)
 {
        struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
        bool is_const = tnum_is_const(reg->var_off);
        struct bpf_map *map = reg->map_ptr;
        u64 val = reg->var_off.value;
+       const char *struct_name = btf_field_type_name(field_type);
+       int field_off = -1;
 
        if (!is_const) {
                verbose(env,
-                       "R%d doesn't have constant offset. bpf_timer has to be at the constant offset\n",
-                       regno);
+                       "R%d doesn't have constant offset. %s has to be at the constant offset\n",
+                       regno, struct_name);
                return -EINVAL;
        }
        if (!map->btf) {
-               verbose(env, "map '%s' has to have BTF in order to use bpf_timer\n",
-                       map->name);
+               verbose(env, "map '%s' has to have BTF in order to use %s\n", map->name,
+                       struct_name);
                return -EINVAL;
        }
-       if (!btf_record_has_field(map->record, BPF_TIMER)) {
-               verbose(env, "map '%s' has no valid bpf_timer\n", map->name);
+       if (!btf_record_has_field(map->record, field_type)) {
+               verbose(env, "map '%s' has no valid %s\n", map->name, struct_name);
                return -EINVAL;
        }
-       if (map->record->timer_off != val + reg->off) {
-               verbose(env, "off %lld doesn't point to 'struct bpf_timer' that is at %d\n",
-                       val + reg->off, map->record->timer_off);
+       switch (field_type) {
+       case BPF_TIMER:
+               field_off = map->record->timer_off;
+               break;
+       default:
+               verifier_bug(env, "unsupported BTF field type: %s\n", struct_name);
                return -EINVAL;
        }
+       if (field_off != val + reg->off) {
+               verbose(env, "off %lld doesn't point to 'struct %s' that is at %d\n",
+                       val + reg->off, struct_name, field_off);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int process_timer_func(struct bpf_verifier_env *env, int regno,
+                             struct bpf_call_arg_meta *meta)
+{
+       struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
+       struct bpf_map *map = reg->map_ptr;
+       int err;
+
+       err = check_map_field_pointer(env, regno, BPF_TIMER);
+       if (err)
+               return err;
+
        if (meta->map_ptr) {
                verifier_bug(env, "Two map pointers in a timer helper");
                return -EFAULT;