]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: add plumbing for file-backed dynptr
authorMykyta Yatsenko <yatsenko@meta.com>
Sun, 26 Oct 2025 20:38:49 +0000 (20:38 +0000)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 27 Oct 2025 16:56:27 +0000 (09:56 -0700)
Add the necessary verifier plumbing for the new file-backed dynptr type.
Introduce two kfuncs for its lifecycle management:
 * bpf_dynptr_from_file() for initialization
 * bpf_dynptr_file_discard() for destruction

Currently there is no mechanism for kfunc to release dynptr, this patch
add one:
 * Dynptr release function sets meta->release_regno
 * Call unmark_stack_slots_dynptr() if meta->release_regno is set and
 dynptr ref_obj_id is set as well.

Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20251026203853.135105-7-mykyta.yatsenko5@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/bpf.h
kernel/bpf/helpers.c
kernel/bpf/log.c
kernel/bpf/verifier.c

index 907c692952938b98b689645183e478d5e9fbd9d4..14f800773997b8689a554625b1981c8c0b835826 100644 (file)
@@ -792,12 +792,15 @@ enum bpf_type_flag {
        /* DYNPTR points to skb_metadata_end()-skb_metadata_len() */
        DYNPTR_TYPE_SKB_META    = BIT(19 + BPF_BASE_TYPE_BITS),
 
+       /* DYNPTR points to file */
+       DYNPTR_TYPE_FILE        = BIT(20 + BPF_BASE_TYPE_BITS),
+
        __BPF_TYPE_FLAG_MAX,
        __BPF_TYPE_LAST_FLAG    = __BPF_TYPE_FLAG_MAX - 1,
 };
 
 #define DYNPTR_TYPE_FLAG_MASK  (DYNPTR_TYPE_LOCAL | DYNPTR_TYPE_RINGBUF | DYNPTR_TYPE_SKB \
-                                | DYNPTR_TYPE_XDP | DYNPTR_TYPE_SKB_META)
+                                | DYNPTR_TYPE_XDP | DYNPTR_TYPE_SKB_META | DYNPTR_TYPE_FILE)
 
 /* Max number of base types. */
 #define BPF_BASE_TYPE_LIMIT    (1UL << BPF_BASE_TYPE_BITS)
@@ -1385,6 +1388,8 @@ enum bpf_dynptr_type {
        BPF_DYNPTR_TYPE_XDP,
        /* Points to skb_metadata_end()-skb_metadata_len() */
        BPF_DYNPTR_TYPE_SKB_META,
+       /* Underlying data is a file */
+       BPF_DYNPTR_TYPE_FILE,
 };
 
 int bpf_dynptr_check_size(u64 size);
index a2ce17ea5edbfef4dafd188a603d8494ab0bcacb..bf65b7fb761f58569fba0f2e24835f91250d951e 100644 (file)
@@ -4252,6 +4252,16 @@ __bpf_kfunc int bpf_task_work_schedule_resume(struct task_struct *task, struct b
        return bpf_task_work_schedule(task, tw, map__map, callback, aux__prog, TWA_RESUME);
 }
 
+__bpf_kfunc int bpf_dynptr_from_file(struct file *file, u32 flags, struct bpf_dynptr *ptr__uninit)
+{
+       return 0;
+}
+
+__bpf_kfunc int bpf_dynptr_file_discard(struct bpf_dynptr *dynptr)
+{
+       return 0;
+}
+
 __bpf_kfunc_end_defs();
 
 static void bpf_task_work_cancel_scheduled(struct irq_work *irq_work)
@@ -4429,6 +4439,8 @@ BTF_ID_FLAGS(func, bpf_cgroup_read_xattr, KF_RCU)
 BTF_ID_FLAGS(func, bpf_stream_vprintk, KF_TRUSTED_ARGS)
 BTF_ID_FLAGS(func, bpf_task_work_schedule_signal, KF_TRUSTED_ARGS)
 BTF_ID_FLAGS(func, bpf_task_work_schedule_resume, KF_TRUSTED_ARGS)
+BTF_ID_FLAGS(func, bpf_dynptr_from_file, KF_TRUSTED_ARGS)
+BTF_ID_FLAGS(func, bpf_dynptr_file_discard)
 BTF_KFUNCS_END(common_btf_ids)
 
 static const struct btf_kfunc_id_set common_kfunc_set = {
index f50533169cc34ed5410b5c5a658d5778dd958b75..70221aafc35c0ae5c28360d57dcdd7026cbf40a3 100644 (file)
@@ -500,6 +500,8 @@ const char *dynptr_type_str(enum bpf_dynptr_type type)
                return "xdp";
        case BPF_DYNPTR_TYPE_SKB_META:
                return "skb_meta";
+       case BPF_DYNPTR_TYPE_FILE:
+               return "file";
        case BPF_DYNPTR_TYPE_INVALID:
                return "<invalid>";
        default:
index f60cfab952307ec18e209074816b7d5dc072d091..cd48ead852a04f7aacba8ee1c66c10f30194b2b0 100644 (file)
@@ -692,6 +692,8 @@ static enum bpf_dynptr_type arg_to_dynptr_type(enum bpf_arg_type arg_type)
                return BPF_DYNPTR_TYPE_XDP;
        case DYNPTR_TYPE_SKB_META:
                return BPF_DYNPTR_TYPE_SKB_META;
+       case DYNPTR_TYPE_FILE:
+               return BPF_DYNPTR_TYPE_FILE;
        default:
                return BPF_DYNPTR_TYPE_INVALID;
        }
@@ -710,6 +712,8 @@ static enum bpf_type_flag get_dynptr_type_flag(enum bpf_dynptr_type type)
                return DYNPTR_TYPE_XDP;
        case BPF_DYNPTR_TYPE_SKB_META:
                return DYNPTR_TYPE_SKB_META;
+       case BPF_DYNPTR_TYPE_FILE:
+               return DYNPTR_TYPE_FILE;
        default:
                return 0;
        }
@@ -717,7 +721,7 @@ static enum bpf_type_flag get_dynptr_type_flag(enum bpf_dynptr_type type)
 
 static bool dynptr_type_refcounted(enum bpf_dynptr_type type)
 {
-       return type == BPF_DYNPTR_TYPE_RINGBUF;
+       return type == BPF_DYNPTR_TYPE_RINGBUF || type == BPF_DYNPTR_TYPE_FILE;
 }
 
 static void __mark_dynptr_reg(struct bpf_reg_state *reg,
@@ -12291,6 +12295,8 @@ enum special_kfunc_type {
        KF_bpf_res_spin_unlock,
        KF_bpf_res_spin_lock_irqsave,
        KF_bpf_res_spin_unlock_irqrestore,
+       KF_bpf_dynptr_from_file,
+       KF_bpf_dynptr_file_discard,
        KF___bpf_trap,
        KF_bpf_task_work_schedule_signal,
        KF_bpf_task_work_schedule_resume,
@@ -12363,6 +12369,8 @@ BTF_ID(func, bpf_res_spin_lock)
 BTF_ID(func, bpf_res_spin_unlock)
 BTF_ID(func, bpf_res_spin_lock_irqsave)
 BTF_ID(func, bpf_res_spin_unlock_irqrestore)
+BTF_ID(func, bpf_dynptr_from_file)
+BTF_ID(func, bpf_dynptr_file_discard)
 BTF_ID(func, __bpf_trap)
 BTF_ID(func, bpf_task_work_schedule_signal)
 BTF_ID(func, bpf_task_work_schedule_resume)
@@ -13326,6 +13334,11 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
                                dynptr_arg_type |= DYNPTR_TYPE_XDP;
                        } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb_meta]) {
                                dynptr_arg_type |= DYNPTR_TYPE_SKB_META;
+                       } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_file]) {
+                               dynptr_arg_type |= DYNPTR_TYPE_FILE;
+                       } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_file_discard]) {
+                               dynptr_arg_type |= DYNPTR_TYPE_FILE;
+                               meta->release_regno = regno;
                        } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_clone] &&
                                   (dynptr_arg_type & MEM_UNINIT)) {
                                enum bpf_dynptr_type parent_type = meta->initialized_dynptr.type;
@@ -14006,12 +14019,18 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
         * PTR_TO_BTF_ID in bpf_kfunc_arg_meta, do the release now.
         */
        if (meta.release_regno) {
-               err = release_reference(env, regs[meta.release_regno].ref_obj_id);
-               if (err) {
-                       verbose(env, "kfunc %s#%d reference has not been acquired before\n",
-                               func_name, meta.func_id);
-                       return err;
+               struct bpf_reg_state *reg = &regs[meta.release_regno];
+
+               if (meta.initialized_dynptr.ref_obj_id) {
+                       err = unmark_stack_slots_dynptr(env, reg);
+               } else {
+                       err = release_reference(env, reg->ref_obj_id);
+                       if (err)
+                               verbose(env, "kfunc %s#%d reference has not been acquired before\n",
+                                       func_name, meta.func_id);
                }
+               if (err)
+                       return err;
        }
 
        if (meta.func_id == special_kfunc_list[KF_bpf_list_push_front_impl] ||