AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/10/17 07:02 flow patch-triage
6m Args:
null

Results:
{
  "EnableConfigs": [
    "BPF_SYSCALL",
    "NET",
    "BPF_EVENTS",
    "KPROBE_EVENTS",
    "UPROBE_EVENTS",
    "IPV6_SEG6_LWTUNNEL"
  ],
  "FocusSymbols": [
    "bpf_iter_map_check_value_write",
    "bpf_iter_link_replace",
    "bpf_selem_unlink_nofail",
    "bpf_sk_storage_clone",
    "bpf_sk_storage_selem_get_sk",
    "htab_map_update_elem",
    "cpu_map_generic_redirect",
    "cpu_map_kthread_run",
    "bpf_token_create",
    "bpf_task_fd_query",
    "bpf_prog_test_run_sk_lookup",
    "__bpf_skb_store_bytes",
    "bpf_skb_net_grow",
    "bpf_lwt_seg6_action",
    "check_buffer_access",
    "check_kfunc_call",
    "check_map_func_compatibility",
    "push_callback_call"
  ],
  "KMSANReasoning": "The patch series addresses several issues across the BPF subsystem, including:\n1. Use-after-free and lifetime bugs: invalidating dynptr packet slices on skb writes, tracking moved packet headers in bpf_skb_store_bytes/bpf_skb_meta_store_bytes, deferring BPF JIT image freeing through RCU work, keeping net_device references in cpumap, and tracking socket references in bpf_sk_storage iterator.\n2. Memory leaks and reference counting: adding missing iput() on token creation error, adding kfree_const() for strings duplicated with kstrdup_const() in perf event info queries and fdinfo dumps.\n3. Concurrency and locking: using try_cmpxchg_local for per-cpu extra elems in hashtab, enforcing RCU critical sections for sleepable programs and iterator callbacks, and adding NOSLEEP restrictions on task_vma iterator.\n4. Verifier bounds checking: adding tracking for rdwr buffer writes (min_rdwr_write / max_rdwr_write) to prevent BPF programs from corrupting special BTF record fields (bpf_spin_lock, bpf_timer, etc.) in map values.\n\nKMSAN vs. KASAN analysis:\n- All new struct fields (such as min_rdwr_write, max_rdwr_write, sleepable_async_cb, rwork, in_rcu_callback_fn, dynptr_write_type, dead_sks, held, nr_held) reside within objects allocated with __GFP_ZERO or kzalloc (e.g., bpf_prog_aux, bpf_func_state, bpf_cpu_map_entry, seq_file private data).\n- The patch explicitly eliminates a potential uninitialized slab read in bpf_sk_storage_clone() by setting refcount_set(\u0026newsk-\u003esk_refcnt, 0) before linking elements.\n- No uninitialized data or struct padding is exposed or copied to user space. The changes touching user copy routines (bpf_perf_link_fill_common, bpf_task_fd_query) only ensure allocated buffers are properly freed with kfree_const().\n- The modified bounds checks and verifier logic tighten constraints rather than opening up uninitialized buffer reads.\n- The bugs targeted by these changes (UAF, memory leaks, concurrency races, refcount underflows) are comprehensively covered by KASAN, KMEMLEAK, and LOCKDEP in standard fuzzing builds.\n\nTherefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false,
  "Reasoning": "The patch series modifies core BPF subsystem logic, including the BPF verifier (dynptr writes, sleepable async callbacks, RCU callback tracking, buffer access ranges), BPF iterators (map/vma/sk_storage iteration, link replacement, program capability checks), map lifetime and concurrency (local storage refcounting/unlinking, hashtab extra elements, map-in-map), networking helpers (skb store bytes, seg6 actions, cpumap device reference holding), and syscall interfaces. These paths are directly reachable and exercisable from unprivileged or privileged userspace via the bpf() system call, socket operations, and perf/tracepoints. Fuzzing is warranted to uncover regressions, verification bypasses, or concurrency issues.",
  "WorthFuzzing": true
}

1/1 2026/10/17 07:02 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 1117fabc0498a30e4d022f35e627ac586b1db367\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Oct 17 07:02:07 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/include/linux/bpf.h b/include/linux/bpf.h\nindex 54144372281cb..c1d92fd10ef12 100644\n--- a/include/linux/bpf.h\n+++ b/include/linux/bpf.h\n@@ -341,6 +341,7 @@ struct bpf_map {\n \tbool frozen; /* write-once; write-protected by freeze_mutex */\n \tbool free_after_mult_rcu_gp;\n \tbool free_after_rcu_gp;\n+\tbool was_inner_map;\n \tatomic64_t sleepable_refcnt;\n \ts64 __percpu *elem_count;\n \tu64 cookie; /* write-once */\n@@ -1858,6 +1859,9 @@ struct bpf_prog_aux {\n \tu32 ctx_arg_info_size;\n \tu32 max_rdonly_access;\n \tu32 max_rdwr_access;\n+\t/* [min, max): the bytes of a rdwr buffer that may be written */\n+\tu32 min_rdwr_write;\n+\tu32 max_rdwr_write;\n \tu32 subprog_start;\n \tstruct btf *attach_btf;\n \tstruct bpf_ctx_arg_aux *ctx_arg_info;\n@@ -1873,6 +1877,7 @@ struct bpf_prog_aux {\n \tbool attach_btf_trace; /* true if attaching to BTF-enabled raw tp */\n \tbool attach_tracing_prog; /* true if tracing another tracing program */\n \tbool tramp_linked; /* true if it was ever linked to a trampoline */\n+\tbool sleepable_async_cb; /* has a bpf_wq or bpf_task_work callback */\n \tbool func_proto_unreliable;\n \tbool tail_call_reachable;\n \tbool xdp_has_frags;\n@@ -1958,6 +1963,7 @@ struct bpf_prog_aux {\n \tunion {\n \t\tstruct work_struct work;\n \t\tstruct rcu_head\trcu;\n+\t\tstruct rcu_work rwork;\n \t};\n \tstruct bpf_stream *stream[2];\n \tstruct mutex st_ops_assoc_mutex;\n@@ -2006,6 +2012,15 @@ struct bpf_prog {\n \t};\n };\n \n+/*\n+ * Does the program, or a callback of it, run under RCU Tasks Trace protection\n+ * only, outside of any RCU read side critical section?\n+ */\n+static inline bool bpf_prog_runs_sleepable(const struct bpf_prog *prog)\n+{\n+\treturn prog-\u003esleepable || prog-\u003eaux-\u003esleepable_async_cb;\n+}\n+\n struct bpf_array_aux {\n \t/* Programs with direct jumps into programs part of this array. */\n \tstruct list_head poke_progs;\n@@ -3128,6 +3143,8 @@ typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *prog,\n \t\t\t\t\tunion bpf_iter_link_info *linfo,\n \t\t\t\t\tstruct bpf_iter_aux_info *aux);\n typedef void (*bpf_iter_detach_target_t)(struct bpf_iter_aux_info *aux);\n+typedef int (*bpf_iter_check_prog_t)(const struct bpf_prog *prog,\n+\t\t\t\t     const struct bpf_iter_aux_info *aux);\n typedef void (*bpf_iter_show_fdinfo_t) (const struct bpf_iter_aux_info *aux,\n \t\t\t\t\tstruct seq_file *seq);\n typedef int (*bpf_iter_fill_link_info_t)(const struct bpf_iter_aux_info *aux,\n@@ -3137,7 +3154,8 @@ typedef const struct bpf_func_proto *\n \t\t\t     const struct bpf_prog *prog);\n \n enum bpf_iter_feature {\n-\tBPF_ITER_RESCHED\t= BIT(0),\n+\tBPF_ITER_RESCHED\t= BIT(0),\t/* may cond_resched() between objects */\n+\tBPF_ITER_NOSLEEP\t= BIT(1),\t/* -\u003eshow() can't run sleepable progs */\n };\n \n #define BPF_ITER_CTX_ARG_MAX 2\n@@ -3145,6 +3163,8 @@ struct bpf_iter_reg {\n \tconst char *target;\n \tbpf_iter_attach_target_t attach_target;\n \tbpf_iter_detach_target_t detach_target;\n+\t/* may the program run on what the link is attached to? */\n+\tbpf_iter_check_prog_t check_prog;\n \tbpf_iter_show_fdinfo_t show_fdinfo;\n \tbpf_iter_fill_link_info_t fill_link_info;\n \tbpf_iter_get_func_proto_t get_func_proto;\n@@ -3181,6 +3201,8 @@ void bpf_iter_map_show_fdinfo(const struct bpf_iter_aux_info *aux,\n \t\t\t      struct seq_file *seq);\n int bpf_iter_map_fill_link_info(const struct bpf_iter_aux_info *aux,\n \t\t\t\tstruct bpf_link_info *info);\n+int bpf_iter_map_check_value_write(const struct bpf_prog *prog,\n+\t\t\t\t   const struct bpf_map *map);\n \n int map_set_for_each_callback_args(struct bpf_verifier_env *env,\n \t\t\t\t   struct bpf_func_state *caller,\ndiff --git a/include/linux/bpf_local_storage.h b/include/linux/bpf_local_storage.h\nindex 9e4f5c45c974d..6c643ac510799 100644\n--- a/include/linux/bpf_local_storage.h\n+++ b/include/linux/bpf_local_storage.h\n@@ -104,6 +104,19 @@ struct bpf_local_storage {\n \trefcount_t owner_refcnt;/* Used to pin owner when map_free is uncharging */\n };\n \n+/*\n+ * Drop a reference got by refcount_inc_not_zero(\u0026local_storage-\u003eowner_refcnt).\n+ * bpf_local_storage_destroy() may have dropped the owner's reference meanwhile\n+ * and wait for the count to reach zero, so this one can be the last.\n+ */\n+static inline void\n+bpf_local_storage_unpin_owner(struct bpf_local_storage *local_storage)\n+{\n+\tbool last __maybe_unused;\n+\n+\tlast = refcount_dec_and_test(\u0026local_storage-\u003eowner_refcnt);\n+}\n+\n /* U16_MAX is much more than enough for sk local storage\n  * considering a tcp_sock is ~2k.\n  */\ndiff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h\nindex 112ca1511da4d..1ca03f8cfd838 100644\n--- a/include/linux/bpf_verifier.h\n+++ b/include/linux/bpf_verifier.h\n@@ -379,6 +379,11 @@ struct bpf_func_state {\n \tbool in_async_callback_fn;\n \tbool in_exception_callback_fn;\n \tbool no_stack_arg_load;\n+\t/*\n+\t * The helper invokes this callback under rcu_read_lock(), so the\n+\t * callback and its callees run in an RCU read-side critical section.\n+\t */\n+\tbool in_rcu_callback_fn;\n \t/* For callback calling functions that limit number of possible\n \t * callback executions (e.g. bpf_loop) keeps track of current\n \t * simulated iteration number.\n@@ -1796,6 +1801,8 @@ struct bpf_call_arg_meta {\n \tu32 kfunc_flags;\n \tconst char *func_name;\n \tstruct arg_constant_desc arg_constant;\n+\t/* The type of the dynptr that the kfunc writes through */\n+\tenum bpf_dynptr_type dynptr_write_type;\n \n \t/* arg_{btf,btf_id,owning_ref} are used by kfunc-specific handling,\n \t * generally to pass info about user-defined local kptr types to later\ndiff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c\nindex b40eb404adab9..5fd376bd210b0 100644\n--- a/kernel/bpf/bpf_iter.c\n+++ b/kernel/bpf/bpf_iter.c\n@@ -72,6 +72,15 @@ static inline bool bpf_iter_target_support_resched(const struct bpf_iter_target_\n \treturn tinfo-\u003ereg_info-\u003efeature \u0026 BPF_ITER_RESCHED;\n }\n \n+/* Only allow sleepable program for resched-able iterator that can run one */\n+static bool bpf_iter_target_support_prog(const struct bpf_iter_target_info *tinfo,\n+\t\t\t\t\t const struct bpf_prog *prog)\n+{\n+\treturn !prog-\u003esleepable ||\n+\t       (bpf_iter_target_support_resched(tinfo) \u0026\u0026\n+\t\t!(tinfo-\u003ereg_info-\u003efeature \u0026 BPF_ITER_NOSLEEP));\n+}\n+\n static bool bpf_iter_support_resched(struct seq_file *seq)\n {\n \tstruct bpf_iter_priv_data *iter_priv;\n@@ -342,6 +351,13 @@ int bpf_iter_prog_supported(struct bpf_prog *prog)\n \tconst char *prefix = BPF_ITER_FUNC_PREFIX;\n \tint prefix_len = strlen(prefix);\n \n+\t/*\n+\t * The attach function of an extension is a subprogram of the iterator\n+\t * program that it extends, whatever its name is.\n+\t */\n+\tif (prog-\u003etype == BPF_PROG_TYPE_EXT)\n+\t\treturn -EINVAL;\n+\n \tif (strncmp(attach_fname, prefix, prefix_len))\n \t\treturn -EINVAL;\n \n@@ -409,6 +425,8 @@ static int bpf_iter_link_replace(struct bpf_link *link,\n \t\t\t\t struct bpf_prog *new_prog,\n \t\t\t\t struct bpf_prog *old_prog)\n {\n+\tstruct bpf_iter_link *iter_link =\n+\t\tcontainer_of(link, struct bpf_iter_link, link);\n \tint ret = 0;\n \n \tmutex_lock(\u0026link_mutex);\n@@ -419,11 +437,19 @@ static int bpf_iter_link_replace(struct bpf_link *link,\n \n \tif (link-\u003eprog-\u003etype != new_prog-\u003etype ||\n \t    link-\u003eprog-\u003eexpected_attach_type != new_prog-\u003eexpected_attach_type ||\n-\t    link-\u003eprog-\u003eaux-\u003eattach_btf_id != new_prog-\u003eaux-\u003eattach_btf_id) {\n+\t    link-\u003eprog-\u003eaux-\u003eattach_btf_id != new_prog-\u003eaux-\u003eattach_btf_id ||\n+\t    !bpf_iter_target_support_prog(iter_link-\u003etinfo, new_prog)) {\n \t\tret = -EINVAL;\n \t\tgoto out_unlock;\n \t}\n \n+\tif (iter_link-\u003etinfo-\u003ereg_info-\u003echeck_prog) {\n+\t\tret = iter_link-\u003etinfo-\u003ereg_info-\u003echeck_prog(new_prog,\n+\t\t\t\t\t\t\t     \u0026iter_link-\u003eaux);\n+\t\tif (ret)\n+\t\t\tgoto out_unlock;\n+\t}\n+\n \told_prog = xchg(\u0026link-\u003eprog, new_prog);\n \tbpf_prog_put(old_prog);\n \n@@ -544,8 +570,7 @@ int bpf_iter_link_attach(const union bpf_attr *attr, bpfptr_t uattr,\n \tif (!tinfo)\n \t\treturn -ENOENT;\n \n-\t/* Only allow sleepable program for resched-able iterator */\n-\tif (prog-\u003esleepable \u0026\u0026 !bpf_iter_target_support_resched(tinfo))\n+\tif (!bpf_iter_target_support_prog(tinfo, prog))\n \t\treturn -EINVAL;\n \n \tlink = kzalloc_obj(*link, GFP_USER | __GFP_NOWARN);\ndiff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c\nindex 4642da062f0f8..3d0c455d258c2 100644\n--- a/kernel/bpf/bpf_local_storage.c\n+++ b/kernel/bpf/bpf_local_storage.c\n@@ -199,7 +199,7 @@ static void bpf_selem_unlink_storage_nolock_misc(struct bpf_local_storage_elem *\n \t}\n \n \tif (pin_owner)\n-\t\trefcount_dec(\u0026local_storage-\u003eowner_refcnt);\n+\t\tbpf_local_storage_unpin_owner(local_storage);\n }\n \n /* local_storage-\u003elock must be held and selem-\u003elocal_storage == local_storage.\n@@ -352,7 +352,7 @@ int bpf_selem_unlink(struct bpf_local_storage_elem *selem)\n static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,\n \t\t\t\t    struct bpf_local_storage_map_bucket *b)\n {\n-\tbool in_map_free = !!b, free_storage = false;\n+\tbool in_map_free = !!b, free_storage = false, sleepable_users = false;\n \tstruct bpf_local_storage *local_storage;\n \tstruct bpf_local_storage_map *smap;\n \tunsigned long flags;\n@@ -362,6 +362,10 @@ static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,\n \tsmap = rcu_dereference_check(SDATA(selem)-\u003esmap, bpf_rcu_lock_held());\n \n \tif (smap) {\n+\t\t/* A map that is freed, or NULL here, has no program left. */\n+\t\tsleepable_users = !in_map_free \u0026\u0026\n+\t\t\t\t  (atomic64_read(\u0026smap-\u003emap.sleepable_refcnt) ||\n+\t\t\t\t   READ_ONCE(smap-\u003emap.was_inner_map));\n \t\tb = b ? : select_bucket(smap, local_storage);\n \t\terr = raw_res_spin_lock_irqsave(\u0026b-\u003elock, flags);\n \t\tif (!err) {\n@@ -431,13 +435,18 @@ static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,\n \t * then freed after an RCU grace period. However, if destroy() and map_free() are\n \t * racing or rqspinlock returns errors in unlikely situations (unlink != 2), free\n \t * the selem only after both map_free() and destroy() see the selem.\n+\t *\n+\t * The owner that map_free() takes an selem from is alive: sleepable code, which\n+\t * is in no RCU read side critical section, may be walking its list for another\n+\t * map.  And it can still use a value that it got before it let go of an owner\n+\t * that destroy() is called for.\n \t */\n \tif (unlink == 2 ||\n \t    atomic_cmpxchg(\u0026selem-\u003estate, SELEM_UNLINKED, SELEM_TOFREE) == SELEM_UNLINKED)\n-\t\tbpf_selem_free(selem, true);\n+\t\tbpf_selem_free(selem, !in_map_free \u0026\u0026 !sleepable_users);\n \n \tif (free_storage)\n-\t\tbpf_local_storage_free(local_storage, true);\n+\t\tbpf_local_storage_free(local_storage, !in_map_free);\n }\n \n void __bpf_local_storage_insert_cache(struct bpf_local_storage *local_storage,\n@@ -753,8 +762,8 @@ u32 bpf_local_storage_destroy(struct bpf_local_storage *local_storage)\n \t\twhile (refcount_read(\u0026local_storage-\u003eowner_refcnt))\n \t\t\tcpu_relax();\n \t\t/*\n-\t\t * Paired with refcount_dec() in bpf_selem_unlink_nofail()\n-\t\t * to make sure destroy() sees the correct local_storage-\u003emem_charge.\n+\t\t * Paired with bpf_local_storage_unpin_owner() to make sure\n+\t\t * destroy() sees the correct local_storage-\u003emem_charge.\n \t\t */\n \t\tsmp_mb();\n \t}\ndiff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c\nindex 64c78434fa050..a9bf4c3c0a273 100644\n--- a/kernel/bpf/btf.c\n+++ b/kernel/bpf/btf.c\n@@ -1081,6 +1081,8 @@ static const struct btf_type *btf_type_skip_qualifiers(const struct btf *btf,\n }\n \n #define BTF_SHOW_MAX_ITER\t10\n+/* nested structs and arrays shown; __btf_show_indent() has as many columns */\n+#define BTF_SHOW_MAX_DEPTH\t32\n \n #define BTF_KIND_BIT(kind)\t(1ULL \u003c\u003c kind)\n \n@@ -1474,8 +1476,18 @@ static void *btf_show_start_aggr_type(struct btf_show *show,\n \t\t\t\t      const struct btf_type *t,\n \t\t\t\t      u32 type_id, void *data)\n {\n-\tvoid *safe_data = btf_show_start_type(show, t, type_id, data);\n+\tvoid *safe_data;\n \n+\t/*\n+\t * Structs and arrays are shown by recursion.  BTF loading bounds the\n+\t * depth of one resolve walk, not how deep resolved types may nest.\n+\t */\n+\tif (show-\u003estate.depth \u003e= BTF_SHOW_MAX_DEPTH) {\n+\t\tshow-\u003estate.status = -E2BIG;\n+\t\treturn NULL;\n+\t}\n+\n+\tsafe_data = btf_show_start_type(show, t, type_id, data);\n \tif (!safe_data)\n \t\treturn safe_data;\n \ndiff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c\nindex bce7b5abcfda3..2ee950e9ac829 100644\n--- a/kernel/bpf/cfg.c\n+++ b/kernel/bpf/cfg.c\n@@ -598,7 +598,9 @@ static int visit_insn(int t, struct bpf_verifier_env *env)\n \t\t\t */\n \t\t\tif (ret == 0 \u0026\u0026 fp-\u003emight_sleep)\n \t\t\t\tmark_subprog_might_sleep(env, t);\n-\t\t\tif (bpf_helper_changes_pkt_data(insn-\u003eimm))\n+\t\t\t/* nobody knows yet whether the dynptr is that of an skb */\n+\t\t\tif (bpf_helper_changes_pkt_data(insn-\u003eimm) ||\n+\t\t\t    insn-\u003eimm == BPF_FUNC_dynptr_write)\n \t\t\t\tmark_subprog_changes_pkt_data(env, t);\n \t\t} else if (insn-\u003esrc_reg == BPF_PSEUDO_KFUNC_CALL) {\n \t\t\tstruct bpf_call_arg_meta meta;\ndiff --git a/kernel/bpf/core.c b/kernel/bpf/core.c\nindex 642f0ab8eb2d8..956555fc5e9f5 100644\n--- a/kernel/bpf/core.c\n+++ b/kernel/bpf/core.c\n@@ -269,6 +269,8 @@ struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,\n \t\tmemcpy(fp, fp_old, fp_old-\u003epages * PAGE_SIZE);\n \t\tfp-\u003epages = pages;\n \t\tfp-\u003eaux-\u003eprog = fp;\n+\t\tif (fp-\u003eaux-\u003eoffload)\n+\t\t\tfp-\u003eaux-\u003eoffload-\u003eprog = fp;\n \n \t\t/* We keep fp-\u003eaux from fp_old around in the new\n \t\t * reallocated structure.\n@@ -3042,7 +3044,7 @@ void __bpf_free_used_maps(struct bpf_prog_aux *aux,\n \tbool sleepable;\n \tu32 i;\n \n-\tsleepable = aux-\u003eprog-\u003esleepable;\n+\tsleepable = bpf_prog_runs_sleepable(aux-\u003eprog);\n \tfor (i = 0; i \u003c len; i++) {\n \t\tmap = used_maps[i];\n \t\tif (map-\u003eops-\u003emap_poke_untrack)\n@@ -3085,12 +3087,40 @@ static void bpf_free_used_btfs(struct bpf_prog_aux *aux)\n \tkfree(aux-\u003eused_btfs);\n }\n \n-static void bpf_prog_free_deferred(struct work_struct *work)\n+static void bpf_prog_free_images(struct work_struct *work)\n {\n \tstruct bpf_prog_aux *aux;\n \tint i;\n \n+\taux = container_of(to_rcu_work(work), struct bpf_prog_aux, rwork);\n+\tfor (i = 0; i \u003c aux-\u003ereal_func_cnt; i++) {\n+\t\t/* We can just unlink the subprog poke descriptor table as\n+\t\t * it was originally linked to the main program and is also\n+\t\t * released along with it.\n+\t\t */\n+\t\taux-\u003efunc[i]-\u003eaux-\u003epoke_tab = NULL;\n+\t\tbpf_jit_free(aux-\u003efunc[i]);\n+\t}\n+\tif (aux-\u003ereal_func_cnt) {\n+\t\tkfree(aux-\u003efunc);\n+\t\tbpf_prog_unlock_free(aux-\u003eprog);\n+\t} else {\n+\t\tbpf_jit_free(aux-\u003eprog);\n+\t}\n+}\n+\n+static void bpf_prog_free_deferred(struct work_struct *work)\n+{\n+\tstruct bpf_prog_aux *aux;\n+\tbool ksyms;\n+\n \taux = container_of(work, struct bpf_prog_aux, work);\n+\t/*\n+\t * A prog that still runs when its last reference goes needs its symbols,\n+\t * by which its exception table is found.  It has ended by now.\n+\t */\n+\tksyms = aux-\u003ereal_func_cnt || !list_empty(\u0026aux-\u003eksym.lnode);\n+\tbpf_prog_kallsyms_del_all(aux-\u003eprog);\n #ifdef CONFIG_BPF_SYSCALL\n \tbpf_free_kfunc_btf_tab(aux-\u003ekfunc_btf_tab);\n #endif\n@@ -3109,20 +3139,12 @@ static void bpf_prog_free_deferred(struct work_struct *work)\n #endif\n \tif (aux-\u003edst_trampoline)\n \t\tbpf_trampoline_put(aux-\u003edst_trampoline);\n-\tfor (i = 0; i \u003c aux-\u003ereal_func_cnt; i++) {\n-\t\t/* We can just unlink the subprog poke descriptor table as\n-\t\t * it was originally linked to the main program and is also\n-\t\t * released along with it.\n-\t\t */\n-\t\taux-\u003efunc[i]-\u003eaux-\u003epoke_tab = NULL;\n-\t\tbpf_jit_free(aux-\u003efunc[i]);\n-\t}\n-\tif (aux-\u003ereal_func_cnt) {\n-\t\tkfree(aux-\u003efunc);\n-\t\tbpf_prog_unlock_free(aux-\u003eprog);\n-\t} else {\n-\t\tbpf_jit_free(aux-\u003eprog);\n-\t}\n+\t/* The symbols are looked up under rcu_read_lock() */\n+\tINIT_RCU_WORK(\u0026aux-\u003erwork, bpf_prog_free_images);\n+\tif (ksyms)\n+\t\tqueue_rcu_work(system_percpu_wq, \u0026aux-\u003erwork);\n+\telse\n+\t\tbpf_prog_free_images(\u0026aux-\u003erwork.work);\n }\n \n void bpf_prog_free(struct bpf_prog *fp)\ndiff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c\nindex 5e59ab896f058..eb87131b1bef5 100644\n--- a/kernel/bpf/cpumap.c\n+++ b/kernel/bpf/cpumap.c\n@@ -45,6 +45,7 @@\n  */\n \n #define CPU_MAP_BULK_SIZE 8  /* 8 == one cacheline on 64-bit archs */\n+#define CPU_MAP_HELD_DEVS 2048\n struct bpf_cpu_map_entry;\n struct bpf_cpu_map;\n \n@@ -74,6 +75,13 @@ struct bpf_cpu_map_entry {\n \n \tstruct completion kthread_running;\n \tstruct rcu_work free_work;\n+\n+\t/*\n+\t * Every frame and skb in the queue holds a reference to its device.\n+\t * The kthread keeps it until nothing is left in GRO.\n+\t */\n+\tstruct net_device *held[CPU_MAP_HELD_DEVS];\n+\tu32 nr_held;\n };\n \n struct bpf_cpu_map {\n@@ -129,9 +137,11 @@ static void __cpu_map_ring_cleanup(struct ptr_ring *ring)\n \t\tWARN_ON_ONCE(1);\n \t\tif (unlikely(__ptr_test_bit(0, \u0026ptr))) {\n \t\t\t__ptr_clear_bit(0, \u0026ptr);\n+\t\t\tdev_put(((struct sk_buff *)ptr)-\u003edev);\n \t\t\tkfree_skb(ptr);\n \t\t\tcontinue;\n \t\t}\n+\t\tdev_put(((struct xdp_frame *)ptr)-\u003edev_rx);\n \t\txdp_return_frame(ptr);\n \t}\n }\n@@ -311,7 +321,7 @@ static int cpu_map_kthread_run(void *data)\n \t\tvoid *frames[CPUMAP_BATCH];\n \t\tvoid *skbs[CPUMAP_BATCH];\n \t\tu32 i, n, m;\n-\t\tbool empty;\n+\t\tbool empty, full;\n \n \t\t/* Release CPU reschedule checks */\n \t\tif (__ptr_ring_empty(rcpu-\u003equeue)) {\n@@ -344,10 +354,12 @@ static int cpu_map_kthread_run(void *data)\n \t\t\t\tstruct sk_buff *skb = f;\n \n \t\t\t\t__ptr_clear_bit(0, \u0026skb);\n+\t\t\t\trcpu-\u003eheld[rcpu-\u003enr_held++] = skb-\u003edev;\n \t\t\t\tskbs[ret.skb_n++] = skb;\n \t\t\t\tcontinue;\n \t\t\t}\n \n+\t\t\trcpu-\u003eheld[rcpu-\u003enr_held++] = ((struct xdp_frame *)f)-\u003edev_rx;\n \t\t\tframes[ret.xdp_n++] = f;\n \t\t\tpage = virt_to_page(f);\n \n@@ -398,10 +410,13 @@ static int cpu_map_kthread_run(void *data)\n \t\t/* Flush either every 64 packets or in case of empty ring */\n \t\tpackets += n;\n \t\tempty = __ptr_ring_empty(rcpu-\u003equeue);\n-\t\tif (packets \u003e= NAPI_POLL_WEIGHT || empty) {\n-\t\t\tcpu_map_gro_flush(rcpu, empty);\n+\t\tfull = empty || rcpu-\u003enr_held \u003e CPU_MAP_HELD_DEVS - CPUMAP_BATCH;\n+\t\tif (packets \u003e= NAPI_POLL_WEIGHT || full) {\n+\t\t\tcpu_map_gro_flush(rcpu, full);\n \t\t\tpackets = 0;\n \t\t}\n+\t\twhile (full \u0026\u0026 rcpu-\u003enr_held)\n+\t\t\tdev_put(rcpu-\u003eheld[--rcpu-\u003enr_held]);\n \n \t\tlocal_bh_enable(); /* resched point, may call do_softirq() */\n \t}\n@@ -738,12 +753,14 @@ static void bq_flush_to_queue(struct xdp_bulk_queue *bq)\n \n \tfor (i = 0; i \u003c bq-\u003ecount; i++) {\n \t\tstruct xdp_frame *xdpf = bq-\u003eq[i];\n-\t\tint err;\n \n-\t\terr = __ptr_ring_produce(q, xdpf);\n-\t\tif (err) {\n+\t\tif (__ptr_ring_full(q)) {\n \t\t\tdrops++;\n \t\t\txdp_return_frame_rx_napi(xdpf);\n+\t\t} else {\n+\t\t\t/* The device cannot go before the flush, from now on it can */\n+\t\t\tdev_hold(xdpf-\u003edev_rx);\n+\t\t\t__ptr_ring_produce(q, xdpf);\n \t\t}\n \t\tprocessed++;\n \t}\n@@ -807,11 +824,15 @@ int cpu_map_generic_redirect(struct bpf_cpu_map_entry *rcpu,\n \n \t__skb_pull(skb, skb-\u003emac_len);\n \tskb_set_redirected(skb, false);\n+\tdev_hold(skb-\u003edev);\n \t__ptr_set_bit(0, \u0026skb);\n \n \tret = ptr_ring_produce(rcpu-\u003equeue, skb);\n-\tif (ret \u003c 0)\n+\tif (ret \u003c 0) {\n+\t\t__ptr_clear_bit(0, \u0026skb);\n+\t\tdev_put(skb-\u003edev);\n \t\tgoto trace;\n+\t}\n \n \twake_up_process(rcpu-\u003ekthread);\n trace:\ndiff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c\nindex dc7b859e8bbfd..1b8f0d7f84552 100644\n--- a/kernel/bpf/devmap.c\n+++ b/kernel/bpf/devmap.c\n@@ -350,6 +350,7 @@ static int dev_map_bpf_prog_run(struct bpf_prog *xdp_prog,\n \n \t\txdp_convert_frame_to_buff(xdpf, \u0026xdp);\n \t\txdp.txq = \u0026txq;\n+\t\trxq.mem.type = xdpf-\u003emem_type;\n \t\txdp.rxq = \u0026rxq;\n \n \t\tact = bpf_prog_run_xdp(xdp_prog, \u0026xdp);\ndiff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c\nindex 608621d7f225c..fe59e3114d828 100644\n--- a/kernel/bpf/fixups.c\n+++ b/kernel/bpf/fixups.c\n@@ -2151,6 +2151,10 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)\n \t\t\tif (!bpf_allow_tail_call_in_subprogs(env))\n \t\t\t\tprog-\u003eaux-\u003estack_depth = MAX_BPF_STACK;\n \t\t\tprog-\u003eaux-\u003emax_pkt_offset = MAX_PACKET_OFF;\n+\t\t\tprog-\u003eaux-\u003emax_rdonly_access = U32_MAX;\n+\t\t\tprog-\u003eaux-\u003emax_rdwr_access = U32_MAX;\n+\t\t\tif (prog-\u003etype == BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE)\n+\t\t\t\tprog-\u003eaux-\u003emax_tp_access = U32_MAX;\n \n \t\t\t/* mark bpf_tail_call as different opcode to avoid\n \t\t\t * conditional branch in the interpreter for every normal\ndiff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c\nindex 9d4791ee17411..923fec694747b 100644\n--- a/kernel/bpf/hashtab.c\n+++ b/kernel/bpf/hashtab.c\n@@ -1279,11 +1279,17 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,\n \tif (prealloc) {\n \t\tif (old_elem) {\n \t\t\t/* if we're updating the existing element,\n-\t\t\t * use per-cpu extra elems to avoid freelist_pop/push\n+\t\t\t * use per-cpu extra elems to avoid freelist_pop/push.\n+\t\t\t * The caller puts old_elem into the slot once it is\n+\t\t\t * unlinked. Until then the slot is empty for an NMI\n+\t\t\t * or a kprobe that updates this map on this cpu.\n \t\t\t */\n \t\t\tpl_new = this_cpu_ptr(htab-\u003eextra_elems);\n-\t\t\tl_new = *pl_new;\n-\t\t\t*pl_new = old_elem;\n+\t\t\tl_new = READ_ONCE(*pl_new);\n+\t\t\tdo {\n+\t\t\t\tif (!l_new)\n+\t\t\t\t\treturn ERR_PTR(-EBUSY);\n+\t\t\t} while (!try_cmpxchg_local(pl_new, \u0026l_new, NULL));\n \t\t} else {\n \t\t\tstruct pcpu_freelist_node *l;\n \n@@ -1459,11 +1465,14 @@ static long htab_map_update_elem(struct bpf_map *map, void *key, void *value,\n \tif (l_old) {\n \t\thlist_nulls_del_rcu(\u0026l_old-\u003ehash_node);\n \n-\t\t/* l_old has already been stashed in htab-\u003eextra_elems, cancel\n-\t\t * its reusable special fields before it is available for reuse.\n+\t\t/* l_old replaces the extra element that alloc_htab_elem() took,\n+\t\t * cancel its reusable special fields before the next update on\n+\t\t * this cpu reuses it.\n \t\t */\n-\t\tif (htab_is_prealloc(htab))\n+\t\tif (htab_is_prealloc(htab)) {\n+\t\t\tWRITE_ONCE(*this_cpu_ptr(htab-\u003eextra_elems), l_old);\n \t\t\tcheck_and_cancel_fields(htab, l_old);\n+\t\t}\n \t}\n \thtab_unlock_bucket(b, flags);\n \tif (l_old \u0026\u0026 !htab_is_prealloc(htab))\ndiff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c\nindex 439370d73cc5f..648abe1ba63ae 100644\n--- a/kernel/bpf/helpers.c\n+++ b/kernel/bpf/helpers.c\n@@ -1262,18 +1262,21 @@ static void bpf_wq_work(struct work_struct *work)\n \n \tBTF_TYPE_EMIT(struct bpf_wq);\n \n+\t/* keeps the program that callback_fn belongs to */\n+\trcu_read_lock_trace();\n+\n \tcallback_fn = READ_ONCE(cb-\u003ecallback_fn);\n \tif (!callback_fn)\n-\t\treturn;\n+\t\tgoto out;\n \n \tkey = map_key_from_value(map, value, \u0026idx);\n \n-        rcu_read_lock_trace();\n-        migrate_disable();\n+\tmigrate_disable();\n \n \tcallback_fn((u64)(long)map, (u64)(long)key, (u64)(long)value, 0, 0);\n \n \tmigrate_enable();\n+out:\n \trcu_read_unlock_trace();\n }\n \ndiff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c\nindex 5ee8aae7435ba..0fa3f2ac0f992 100644\n--- a/kernel/bpf/map_in_map.c\n+++ b/kernel/bpf/map_in_map.c\n@@ -110,10 +110,13 @@ void *bpf_map_fd_get_ptr(struct bpf_map *map,\n \t\treturn ERR_PTR(-ENOTSUPP);\n \n \tinner_map_meta = map-\u003einner_map_meta;\n-\tif (inner_map_meta-\u003eops-\u003emap_meta_equal(inner_map_meta, inner_map))\n+\tif (inner_map_meta-\u003eops-\u003emap_meta_equal(inner_map_meta, inner_map)) {\n \t\tbpf_map_inc(inner_map);\n-\telse\n+\t\t/* Its users are those of the outer maps from now on */\n+\t\tWRITE_ONCE(inner_map-\u003ewas_inner_map, true);\n+\t} else {\n \t\tinner_map = ERR_PTR(-EINVAL);\n+\t}\n \n \treturn inner_map;\n }\ndiff --git a/kernel/bpf/map_iter.c b/kernel/bpf/map_iter.c\nindex 2077d46d167c7..a58c148692e6c 100644\n--- a/kernel/bpf/map_iter.c\n+++ b/kernel/bpf/map_iter.c\n@@ -97,13 +97,57 @@ static struct bpf_iter_reg bpf_map_reg_info = {\n \t.seq_info\t\t= \u0026bpf_map_seq_info,\n };\n \n+/*\n+ * For an iterator that hands the live map value to the program as a writable\n+ * buffer: the verifier knows nothing of the map, so the special fields of the\n+ * value have to lie outside of what the program may write.\n+ */\n+int bpf_iter_map_check_value_write(const struct bpf_prog *prog,\n+\t\t\t\t   const struct bpf_map *map)\n+{\n+\tconst struct btf_record *rec = map-\u003erecord;\n+\tconst struct btf_field *field;\n+\tu32 i;\n+\n+\tif (IS_ERR_OR_NULL(rec) || !prog-\u003eaux-\u003emax_rdwr_write)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i \u003c rec-\u003ecnt; i++) {\n+\t\tfield = \u0026rec-\u003efields[i];\n+\t\tif (field-\u003eoffset \u003c prog-\u003eaux-\u003emax_rdwr_write \u0026\u0026\n+\t\t    field-\u003eoffset + field-\u003esize \u003e prog-\u003eaux-\u003emin_rdwr_write)\n+\t\t\treturn -EACCES;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int bpf_iter_map_check_prog(const struct bpf_prog *prog,\n+\t\t\t\t   const struct bpf_iter_aux_info *aux)\n+{\n+\tconst struct bpf_map *map = aux-\u003emap;\n+\tu32 value_size = map-\u003evalue_size;\n+\tbool is_percpu;\n+\n+\tis_percpu = map-\u003emap_type == BPF_MAP_TYPE_PERCPU_HASH ||\n+\t\t    map-\u003emap_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||\n+\t\t    map-\u003emap_type == BPF_MAP_TYPE_PERCPU_ARRAY;\n+\tif (is_percpu)\n+\t\tvalue_size = round_up(value_size, 8) * num_possible_cpus();\n+\n+\tif (prog-\u003eaux-\u003emax_rdonly_access \u003e map-\u003ekey_size ||\n+\t    prog-\u003eaux-\u003emax_rdwr_access \u003e value_size)\n+\t\treturn -EACCES;\n+\n+\t/* the program gets a copy of a per-cpu value */\n+\treturn is_percpu ? 0 : bpf_iter_map_check_value_write(prog, map);\n+}\n+\n static int bpf_iter_attach_map(struct bpf_prog *prog,\n \t\t\t       union bpf_iter_link_info *linfo,\n \t\t\t       struct bpf_iter_aux_info *aux)\n {\n-\tu32 key_acc_size, value_acc_size, key_size, value_size;\n \tstruct bpf_map *map;\n-\tbool is_percpu = false;\n \tint err = -EINVAL;\n \n \tif (!linfo-\u003emap.map_fd)\n@@ -123,30 +167,20 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,\n \t\tgoto put_map;\n \t}\n \n-\tif (map-\u003emap_type == BPF_MAP_TYPE_PERCPU_HASH ||\n-\t    map-\u003emap_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||\n-\t    map-\u003emap_type == BPF_MAP_TYPE_PERCPU_ARRAY)\n-\t\tis_percpu = true;\n-\telse if (map-\u003emap_type != BPF_MAP_TYPE_HASH \u0026\u0026\n-\t\t map-\u003emap_type != BPF_MAP_TYPE_LRU_HASH \u0026\u0026\n-\t\t map-\u003emap_type != BPF_MAP_TYPE_ARRAY \u0026\u0026\n-\t\t map-\u003emap_type != BPF_MAP_TYPE_RHASH)\n+\tif (map-\u003emap_type != BPF_MAP_TYPE_PERCPU_HASH \u0026\u0026\n+\t    map-\u003emap_type != BPF_MAP_TYPE_LRU_PERCPU_HASH \u0026\u0026\n+\t    map-\u003emap_type != BPF_MAP_TYPE_PERCPU_ARRAY \u0026\u0026\n+\t    map-\u003emap_type != BPF_MAP_TYPE_HASH \u0026\u0026\n+\t    map-\u003emap_type != BPF_MAP_TYPE_LRU_HASH \u0026\u0026\n+\t    map-\u003emap_type != BPF_MAP_TYPE_ARRAY \u0026\u0026\n+\t    map-\u003emap_type != BPF_MAP_TYPE_RHASH)\n \t\tgoto put_map;\n \n-\tkey_acc_size = prog-\u003eaux-\u003emax_rdonly_access;\n-\tvalue_acc_size = prog-\u003eaux-\u003emax_rdwr_access;\n-\tkey_size = map-\u003ekey_size;\n-\tif (!is_percpu)\n-\t\tvalue_size = map-\u003evalue_size;\n-\telse\n-\t\tvalue_size = round_up(map-\u003evalue_size, 8) * num_possible_cpus();\n-\n-\tif (key_acc_size \u003e key_size || value_acc_size \u003e value_size) {\n-\t\terr = -EACCES;\n+\taux-\u003emap = map;\n+\terr = bpf_iter_map_check_prog(prog, aux);\n+\tif (err)\n \t\tgoto put_map;\n-\t}\n \n-\taux-\u003emap = map;\n \treturn 0;\n \n put_map:\n@@ -179,6 +213,7 @@ static const struct bpf_iter_reg bpf_map_elem_reg_info = {\n \t.target\t\t\t= \"bpf_map_elem\",\n \t.attach_target\t\t= bpf_iter_attach_map,\n \t.detach_target\t\t= bpf_iter_detach_map,\n+\t.check_prog\t\t= bpf_iter_map_check_prog,\n \t.show_fdinfo\t\t= bpf_iter_map_show_fdinfo,\n \t.fill_link_info\t\t= bpf_iter_map_fill_link_info,\n \t.ctx_arg_info_size\t= 2,\ndiff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c\nindex d855399812eec..c615ed46f6293 100644\n--- a/kernel/bpf/offload.c\n+++ b/kernel/bpf/offload.c\n@@ -250,7 +250,14 @@ int bpf_prog_dev_bound_init(struct bpf_prog *prog, union bpf_attr *attr)\n \tprog-\u003eaux-\u003eoffload_requested = !(attr-\u003eprog_flags \u0026 BPF_F_XDP_DEV_BOUND_ONLY);\n \n \tdown_write(\u0026bpf_devs_lock);\n-\terr = __bpf_prog_dev_bound_init(prog, netdev);\n+\t/*\n+\t * Behind bpf_dev_bound_netdev_unregister() nobody would take the\n+\t * program off the device, which goes once the reference is dropped.\n+\t */\n+\tif (READ_ONCE(netdev-\u003ereg_state) == NETREG_REGISTERED)\n+\t\terr = __bpf_prog_dev_bound_init(prog, netdev);\n+\telse\n+\t\terr = -EINVAL;\n \tup_write(\u0026bpf_devs_lock);\n \n out:\ndiff --git a/kernel/bpf/states.c b/kernel/bpf/states.c\nindex 953700822fa73..b3d250caaaa65 100644\n--- a/kernel/bpf/states.c\n+++ b/kernel/bpf/states.c\n@@ -995,6 +995,9 @@ static bool func_states_equal(struct bpf_verifier_env *env, struct bpf_func_stat\n \tif (!old-\u003eno_stack_arg_load \u0026\u0026 cur-\u003eno_stack_arg_load)\n \t\treturn false;\n \n+\tif (old-\u003ein_rcu_callback_fn != cur-\u003ein_rcu_callback_fn)\n+\t\treturn false;\n+\n \tfor (i = 0; i \u003c MAX_BPF_REG; i++)\n \t\tif (((1 \u003c\u003c i) \u0026 live_regs) \u0026\u0026\n \t\t    !regsafe(env, \u0026old-\u003eregs[i], \u0026cur-\u003eregs[i],\ndiff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c\nindex 654f896af265b..c8bd92c95ac02 100644\n--- a/kernel/bpf/syscall.c\n+++ b/kernel/bpf/syscall.c\n@@ -2461,6 +2461,8 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu)\n \tstruct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);\n \n \tbtf_put(aux-\u003ebtf);\n+\tkvfree(aux-\u003ejited_linfo);\n+\tkvfree(aux-\u003elinfo);\n \tkvfree(aux-\u003efunc_info);\n \tkfree(aux-\u003efunc_info_aux);\n \tfree_uid(aux-\u003euser);\n@@ -2477,7 +2479,7 @@ static void __bpf_prog_put_rcu_tasks(struct rcu_head *rcu)\n {\n \tstruct bpf_prog *prog = container_of(rcu, struct bpf_prog_aux, rcu)-\u003eprog;\n \n-\tif (prog-\u003esleepable)\n+\tif (bpf_prog_runs_sleepable(prog))\n \t\tcall_rcu_tasks_trace(rcu, __bpf_prog_put_rcu);\n \telse\n \t\tcall_rcu(rcu, __bpf_prog_put_rcu);\n@@ -2485,10 +2487,7 @@ static void __bpf_prog_put_rcu_tasks(struct rcu_head *rcu)\n \n static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)\n {\n-\tbpf_prog_kallsyms_del_all(prog);\n \tmodule_put(prog-\u003eaux-\u003emod);\n-\tkvfree(prog-\u003eaux-\u003ejited_linfo);\n-\tkvfree(prog-\u003eaux-\u003elinfo);\n \tkfree(prog-\u003eaux-\u003ekfunc_tab);\n \tkfree(prog-\u003eaux-\u003ectx_arg_info);\n \tif (prog-\u003eaux-\u003eattach_btf)\n@@ -2497,7 +2496,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)\n \tif (deferred) {\n \t\tif (IS_ENABLED(CONFIG_TASKS_RCU) \u0026\u0026 prog-\u003eaux-\u003etramp_linked)\n \t\t\tcall_rcu_tasks(\u0026prog-\u003eaux-\u003ercu, __bpf_prog_put_rcu_tasks);\n-\t\telse if (prog-\u003esleepable)\n+\t\telse if (bpf_prog_runs_sleepable(prog))\n \t\t\tcall_rcu_tasks_trace(\u0026prog-\u003eaux-\u003ercu, __bpf_prog_put_rcu);\n \t\telse\n \t\t\tcall_rcu(\u0026prog-\u003eaux-\u003ercu, __bpf_prog_put_rcu);\n@@ -4020,19 +4019,19 @@ static int bpf_perf_link_fill_common(const struct perf_event *event,\n \t\t*ulenp = 1;\n \t}\n \tif (!uname)\n-\t\treturn 0;\n+\t\tgoto out;\n \n \tif (buf) {\n \t\terr = bpf_copy_to_user(uname, buf, ulen, len);\n-\t\tif (err)\n-\t\t\treturn err;\n \t} else {\n \t\tchar zero = '\\0';\n \n \t\tif (put_user(zero, uname))\n-\t\t\treturn -EFAULT;\n+\t\t\terr = -EFAULT;\n \t}\n-\treturn 0;\n+out:\n+\tkfree_const(buf);\n+\treturn err;\n }\n \n #ifdef CONFIG_KPROBE_EVENTS\n@@ -4089,6 +4088,7 @@ static void bpf_perf_link_fdinfo_kprobe(const struct perf_event *event,\n \t\t   name, offset, missed, addr,\n \t\t   type == BPF_FD_TYPE_KRETPROBE ?  \"kretprobe\" : \"kprobe\",\n \t\t   event-\u003ebpf_cookie);\n+\tkfree_const(name);\n }\n #endif\n \n@@ -4142,6 +4142,7 @@ static void bpf_perf_link_fdinfo_uprobe(const struct perf_event *event,\n \t\t   name, offset, ref_ctr_offset,\n \t\t   type == BPF_FD_TYPE_URETPROBE ?  \"uretprobe\" : \"uprobe\",\n \t\t   event-\u003ebpf_cookie);\n+\tkfree_const(name);\n }\n #endif\n \n@@ -4240,6 +4241,7 @@ static void bpf_tracepoint_link_show_fdinfo(const struct perf_event *event,\n \t\t   \"event_type:\\t%s\\n\"\n \t\t   \"cookie:\\t%llu\\n\",\n \t\t   name, \"tracepoint\", event-\u003ebpf_cookie);\n+\tkfree_const(name);\n }\n \n static void bpf_probe_link_show_fdinfo(const struct perf_event *event,\n@@ -5763,11 +5765,13 @@ static int bpf_task_fd_query(const union bpf_attr *attr,\n \t\terr = bpf_get_perf_event_info(event, \u0026prog_id, \u0026fd_type,\n \t\t\t\t\t      \u0026buf, \u0026probe_offset,\n \t\t\t\t\t      \u0026probe_addr, NULL);\n-\t\tif (!err)\n+\t\tif (!err) {\n \t\t\terr = bpf_task_fd_query_copy(attr, uattr, prog_id,\n \t\t\t\t\t\t     fd_type, buf,\n \t\t\t\t\t\t     probe_offset,\n \t\t\t\t\t\t     probe_addr);\n+\t\t\tkfree_const(buf);\n+\t\t}\n \t\tgoto put_file;\n \t}\n \n@@ -6248,7 +6252,7 @@ static int bpf_prog_bind_map(union bpf_attr *attr)\n \t/* The bpf program will not access the bpf map, but for the sake of\n \t * simplicity, increase sleepable_refcnt for sleepable program as well.\n \t */\n-\tif (prog-\u003esleepable)\n+\tif (bpf_prog_runs_sleepable(prog))\n \t\tatomic64_inc(\u0026map-\u003esleepable_refcnt);\n \tmemcpy(used_maps_new, used_maps_old,\n \t       sizeof(used_maps_old[0]) * prog-\u003eaux-\u003eused_map_cnt);\ndiff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c\nindex 13e1aabe6f886..2fa6b8dae8c4f 100644\n--- a/kernel/bpf/task_iter.c\n+++ b/kernel/bpf/task_iter.c\n@@ -737,7 +737,11 @@ static const struct bpf_iter_seq_info task_vma_seq_info = {\n static struct bpf_iter_reg task_vma_reg_info = {\n \t.target\t\t\t= \"task_vma\",\n \t.attach_target\t\t= bpf_iter_attach_task,\n-\t.feature\t\t= BPF_ITER_RESCHED,\n+\t/*\n+\t * -\u003eshow() runs with the mmap_lock of the iterated mm held, which a\n+\t * sleepable program takes again when it faults on user memory.\n+\t */\n+\t.feature\t\t= BPF_ITER_RESCHED | BPF_ITER_NOSLEEP,\n \t.ctx_arg_info_size\t= 2,\n \t.ctx_arg_info\t\t= {\n \t\t{ offsetof(struct bpf_iter__task_vma, task),\n@@ -806,8 +810,14 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,\n \tvma = find_vma(mm, start);\n \n \tif (vma \u0026\u0026 vma-\u003evm_start \u003c= start \u0026\u0026 vma-\u003evm_end \u003e start) {\n+\t\t/*\n+\t\t * The callback must not sleep while mmap_lock is held, and the\n+\t\t * verifier checks it as an RCU read-side critical section.\n+\t\t */\n+\t\trcu_read_lock();\n \t\tcallback_fn((u64)(long)task, (u64)(long)vma,\n \t\t\t    (u64)(long)callback_ctx, 0, 0);\n+\t\trcu_read_unlock();\n \t\tret = 0;\n \t}\n \tbpf_mmap_unlock_mm(work, mm);\ndiff --git a/kernel/bpf/token.c b/kernel/bpf/token.c\nindex e85a179523f02..19660ef95ddbd 100644\n--- a/kernel/bpf/token.c\n+++ b/kernel/bpf/token.c\n@@ -169,8 +169,11 @@ int bpf_token_create(union bpf_attr *attr)\n \tFD_PREPARE(fdf, O_CLOEXEC,\n \t\t   alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME,\n \t\t\t\t     O_RDWR, \u0026bpf_token_fops));\n-\tif (fdf.err)\n+\tif (fdf.err) {\n+\t\t/* no file took over the inode reference */\n+\t\tiput(inode);\n \t\treturn fdf.err;\n+\t}\n \n \ttoken = kzalloc_obj(*token, GFP_USER);\n \tif (!token)\ndiff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c\nindex ddfa0c6d2755f..1cf7f2e57a161 100644\n--- a/kernel/bpf/verifier.c\n+++ b/kernel/bpf/verifier.c\n@@ -219,6 +219,7 @@ static int ref_set_non_owning(struct bpf_verifier_env *env,\n \t\t\t      struct bpf_reg_state *reg);\n static bool is_trusted_reg(struct bpf_verifier_env *env, const struct bpf_reg_state *reg);\n static inline bool in_sleepable_context(struct bpf_verifier_env *env);\n+static bool in_rcu_callback(struct bpf_verifier_env *env);\n static const char *non_sleepable_context_description(struct bpf_verifier_env *env);\n static void scalar32_min_max_add(struct bpf_reg_state *dst_reg, struct bpf_reg_state *src_reg);\n static void scalar_min_max_add(struct bpf_reg_state *dst_reg, struct bpf_reg_state *src_reg);\n@@ -593,6 +594,19 @@ static bool is_async_cb_sleepable(struct bpf_verifier_env *env, struct bpf_insn\n \treturn false;\n }\n \n+/* From here on the maps of the program count it as a sleepable user. */\n+static void mark_sleepable_async_cb(struct bpf_verifier_env *env)\n+{\n+\tint i;\n+\n+\tif (bpf_prog_runs_sleepable(env-\u003eprog))\n+\t\treturn;\n+\n+\tenv-\u003eprog-\u003eaux-\u003esleepable_async_cb = true;\n+\tfor (i = 0; i \u003c env-\u003eused_map_cnt; i++)\n+\t\tatomic64_inc(\u0026env-\u003eused_maps[i]-\u003esleepable_refcnt);\n+}\n+\n bool bpf_is_may_goto_insn(struct bpf_insn *insn)\n {\n \treturn insn-\u003ecode == (BPF_JMP | BPF_JCOND) \u0026\u0026 insn-\u003esrc_reg == BPF_MAY_GOTO;\n@@ -988,6 +1002,11 @@ static enum bpf_dynptr_type dynptr_reg_type(struct bpf_verifier_env *env, struct\n \treturn bpf_stack_slot(state, spi)-\u003espilled_ptr.dynptr.type;\n }\n \n+static bool dynptr_write_changes_pkt_data(enum bpf_dynptr_type type)\n+{\n+\treturn type == BPF_DYNPTR_TYPE_SKB || type == BPF_DYNPTR_TYPE_SKB_META;\n+}\n+\n static bool is_dynptr_type_expected(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n \t\t\t\t    enum bpf_arg_type arg_type)\n {\n@@ -6039,9 +6058,10 @@ static int check_buffer_access(struct bpf_verifier_env *env,\n \t\t\t       const struct bpf_reg_state *reg,\n \t\t\t       argno_t argno, int off, int size,\n \t\t\t       bool zero_size_allowed,\n-\t\t\t       u32 *max_access)\n+\t\t\t       u32 *max_access, bool write)\n {\n \tconst char *buf_info = type_is_rdonly_mem(reg-\u003etype) ? \"rdonly\" : \"rdwr\";\n+\tstruct bpf_prog_aux *aux = env-\u003eprog-\u003eaux;\n \tu32 access_end;\n \tint err;\n \n@@ -6050,6 +6070,11 @@ static int check_buffer_access(struct bpf_verifier_env *env,\n \t\treturn err;\n \n \t*max_access = max(access_end, *max_access);\n+\tif (write \u0026\u0026 size) {\n+\t\tif (!aux-\u003emax_rdwr_write || access_end - size \u003c aux-\u003emin_rdwr_write)\n+\t\t\taux-\u003emin_rdwr_write = access_end - size;\n+\t\taux-\u003emax_rdwr_write = max(access_end, aux-\u003emax_rdwr_write);\n+\t}\n \n \treturn 0;\n }\n@@ -7325,7 +7350,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b\n \t\t}\n \n \t\terr = check_buffer_access(env, reg, argno, off, size, false,\n-\t\t\t\t\t  max_access);\n+\t\t\t\t\t  max_access, t == BPF_WRITE);\n \n \t\tif (!err \u0026\u0026 value_regno \u003e= 0 \u0026\u0026 (rdonly_mem || t == BPF_READ))\n \t\t\tmark_reg_unknown(env, regs, value_regno);\n@@ -7838,7 +7863,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, struct bpf_reg_\n \t\t}\n \t\treturn check_buffer_access(env, reg, argno, 0,\n \t\t\t\t\t   access_size, zero_size_allowed,\n-\t\t\t\t\t   max_access);\n+\t\t\t\t\t   max_access, access_type == BPF_WRITE);\n \tcase PTR_TO_STACK:\n \t\treturn check_stack_range_initialized(\n \t\t\t\tenv, reg,\n@@ -8391,6 +8416,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat\n \t\t\t       argno_t argno, int insn_idx, enum bpf_arg_type arg_type,\n \t\t\t       struct bpf_call_arg_meta *meta)\n {\n+\tbool is_arg = reg-\u003etype == CONST_PTR_TO_DYNPTR;\n \tint spi, err = 0;\n \n \t/*  MEM_UNINIT - Points to memory that is an appropriate candidate for\n@@ -8477,7 +8503,12 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat\n \t\t\treg = \u0026bpf_stack_slot(state, spi)-\u003espilled_ptr;\n \t\t}\n \n-\t\tmeta-\u003edynptr.type = reg-\u003edynptr.type;\n+\t\t/*\n+\t\t * The callers of a global function may hand in a dynptr of any\n+\t\t * type. Take it for that of an skb, so that a write through it\n+\t\t * and its slices are treated with care.\n+\t\t */\n+\t\tmeta-\u003edynptr.type = is_arg ? BPF_DYNPTR_TYPE_SKB : reg-\u003edynptr.type;\n \t\tmeta-\u003edynptr.id = reg-\u003eid;\n \t\tmeta-\u003edynptr.parent_id = reg-\u003eparent_id;\n \t}\n@@ -8956,6 +8987,7 @@ static bool is_kfunc_arg_scalar_with_name(const struct btf *btf,\n static bool is_bpf_cast_to_kern_ctx_kfunc(const struct bpf_call_arg_meta *meta);\n static bool is_bpf_dynptr_clone_kfunc(const struct bpf_call_arg_meta *meta);\n static bool is_bpf_iter_css_task_new_kfunc(const struct bpf_call_arg_meta *meta);\n+static bool is_kfunc_dynptr_write(struct bpf_call_arg_meta *meta);\n static bool is_bpf_obj_drop_kfunc(u32 func_id);\n static bool is_bpf_percpu_obj_drop_kfunc(u32 func_id);\n static bool is_bpf_rbtree_add_kfunc(u32 func_id);\n@@ -9661,6 +9693,16 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p\n \tif (err)\n \t\treturn err;\n \n+\t/*\n+\t * A slice of a packet is packet data under another name. A helper which\n+\t * may reallocate the packet must not go on reading from the old one.\n+\t */\n+\tif (is_helper(meta) \u0026\u0026 reg_is_dynptr_slice_pkt(reg) \u0026\u0026\n+\t    bpf_helper_changes_pkt_data(meta-\u003efunc_id)) {\n+\t\tverbose(env, \"function access to the packet is not allowed\\n\");\n+\t\treturn -EACCES;\n+\t}\n+\n \tif (arg_type_is_raw_mem(arg_type))\n \t\tmeta-\u003earg_raw_mem.mask |= BIT(slot);\n \n@@ -10020,6 +10062,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p\n \t\terr = process_dynptr_func(env, reg, argno, insn_idx, arg_type, meta);\n \t\tif (err)\n \t\t\treturn err;\n+\t\tif (!arg \u0026\u0026 is_kfunc_dynptr_write(meta))\n+\t\t\tmeta-\u003edynptr_write_type = meta-\u003edynptr.type;\n \t\tbreak;\n \t}\n \tcase ARG_PTR_TO_ITER:\n@@ -10366,12 +10410,57 @@ bool bpf_allow_tail_call_in_subprogs(struct bpf_verifier_env *env)\n \t       bpf_jit_supports_subprog_tailcalls();\n }\n \n+/* May the map be used outside of an RCU read side critical section? */\n+static bool map_needs_no_rcu(const struct bpf_map *map)\n+{\n+\tswitch (map-\u003emap_type) {\n+\tcase BPF_MAP_TYPE_HASH:\n+\tcase BPF_MAP_TYPE_RHASH:\n+\tcase BPF_MAP_TYPE_LRU_HASH:\n+\tcase BPF_MAP_TYPE_ARRAY:\n+\tcase BPF_MAP_TYPE_PERCPU_HASH:\n+\tcase BPF_MAP_TYPE_PERCPU_ARRAY:\n+\tcase BPF_MAP_TYPE_LRU_PERCPU_HASH:\n+\tcase BPF_MAP_TYPE_LPM_TRIE:\n+\tcase BPF_MAP_TYPE_ARRAY_OF_MAPS:\n+\tcase BPF_MAP_TYPE_HASH_OF_MAPS:\n+\tcase BPF_MAP_TYPE_RINGBUF:\n+\tcase BPF_MAP_TYPE_USER_RINGBUF:\n+\tcase BPF_MAP_TYPE_INODE_STORAGE:\n+\tcase BPF_MAP_TYPE_SK_STORAGE:\n+\tcase BPF_MAP_TYPE_TASK_STORAGE:\n+\tcase BPF_MAP_TYPE_CGRP_STORAGE:\n+\tcase BPF_MAP_TYPE_QUEUE:\n+\tcase BPF_MAP_TYPE_STACK:\n+\tcase BPF_MAP_TYPE_ARENA:\n+\tcase BPF_MAP_TYPE_INSN_ARRAY:\n+\tcase BPF_MAP_TYPE_PROG_ARRAY:\n+\tcase BPF_MAP_TYPE_BLOOM_FILTER:\n+\t\treturn true;\n+\tdefault:\n+\t\treturn false;\n+\t}\n+}\n+\n static int check_map_func_compatibility(struct bpf_verifier_env *env,\n \t\t\t\t\tstruct bpf_map *map, int func_id)\n {\n \tif (!map)\n \t\treturn 0;\n \n+\t/*\n+\t * check_map_prog_compatibility() asks the program.  That misses the\n+\t * sleepable callback of another program, and an inner map.  They may\n+\t * use any map under the RCU read lock.  Disabled preemption or\n+\t * interrupts will not do: the maps ask for rcu_read_lock_held().\n+\t */\n+\tif (in_sleepable(env) \u0026\u0026 !env-\u003ecur_state-\u003eactive_rcu_locks \u0026\u0026\n+\t    !in_rcu_callback(env) \u0026\u0026 !map_needs_no_rcu(map)) {\n+\t\tverbose(env, \"map '%s' needs bpf_rcu_read_lock() in sleepable context\\n\",\n+\t\t\tmap-\u003ename);\n+\t\treturn -EINVAL;\n+\t}\n+\n \t/* We need a two way check, first is from map perspective ... */\n \tswitch (map-\u003emap_type) {\n \tcase BPF_MAP_TYPE_PROG_ARRAY:\n@@ -11211,6 +11300,8 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins\n \t\t\t\t\t is_async_cb_sleepable(env, insn));\n \t\tif (IS_ERR(async_cb))\n \t\t\treturn PTR_ERR(async_cb);\n+\t\tif (is_async_cb_sleepable(env, insn))\n+\t\t\tmark_sleepable_async_cb(env);\n \t\tcallee = async_cb-\u003eframe[0];\n \t\tcallee-\u003easync_entry_cnt = state-\u003eframe[0]-\u003easync_entry_cnt + 1;\n \n@@ -11530,6 +11621,19 @@ static int set_map_elem_callback_state(struct bpf_verifier_env *env,\n \tif (err)\n \t\treturn err;\n \n+\tswitch (map-\u003emap_type) {\n+\tcase BPF_MAP_TYPE_HASH:\n+\tcase BPF_MAP_TYPE_PERCPU_HASH:\n+\tcase BPF_MAP_TYPE_LRU_HASH:\n+\tcase BPF_MAP_TYPE_LRU_PERCPU_HASH:\n+\tcase BPF_MAP_TYPE_RHASH:\n+\t\t/* Hash tables run the callback under rcu_read_lock(). */\n+\t\tcallee-\u003ein_rcu_callback_fn = true;\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n \tcallee-\u003ein_callback_fn = true;\n \tcallee-\u003ecallback_ret_range = retval_range(0, 1);\n \treturn 0;\n@@ -11616,6 +11720,8 @@ static int set_find_vma_callback_state(struct bpf_verifier_env *env,\n \tbpf_mark_reg_not_init(env, \u0026callee-\u003eregs[BPF_REG_4]);\n \tbpf_mark_reg_not_init(env, \u0026callee-\u003eregs[BPF_REG_5]);\n \tcallee-\u003ein_callback_fn = true;\n+\t/* bpf_find_vma() runs the callback under mmap_lock and RCU. */\n+\tcallee-\u003ein_rcu_callback_fn = true;\n \tcallee-\u003ecallback_ret_range = retval_range(0, 1);\n \treturn 0;\n }\n@@ -12273,10 +12379,22 @@ int bpf_get_helper_proto(struct bpf_verifier_env *env, int func_id,\n \treturn *ptr \u0026\u0026 (*ptr)-\u003efunc ? 0 : -EINVAL;\n }\n \n+/* Is any frame on the current path a callback that runs under RCU? */\n+static bool in_rcu_callback(struct bpf_verifier_env *env)\n+{\n+\tstruct bpf_verifier_state *state = env-\u003ecur_state;\n+\tint i;\n+\n+\tfor (i = 0; i \u003c= state-\u003ecurframe; i++)\n+\t\tif (state-\u003eframe[i]-\u003ein_rcu_callback_fn)\n+\t\t\treturn true;\n+\treturn false;\n+}\n+\n /* Check if we're in a sleepable context. */\n static inline bool in_sleepable_context(struct bpf_verifier_env *env)\n {\n-\treturn !in_rcu_cs(env);\n+\treturn !in_rcu_cs(env) \u0026\u0026 !in_rcu_callback(env);\n }\n \n static const char *non_sleepable_context_description(struct bpf_verifier_env *env)\n@@ -12290,6 +12408,7 @@ static const char *non_sleepable_context_description(struct bpf_verifier_env *en\n \t\t\treturn \"IRQ-disabled region\";\n \t\tif (env-\u003ecur_state-\u003eactive_locks)\n \t\t\treturn \"lock region\";\n+\t\treturn \"callback running under rcu_read_lock\";\n \t}\n \treturn \"non-sleepable prog\";\n }\n@@ -12540,8 +12659,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn\n \t\tif (dynptr_type == BPF_DYNPTR_TYPE_INVALID)\n \t\t\treturn -EFAULT;\n \n-\t\tif (dynptr_type == BPF_DYNPTR_TYPE_SKB ||\n-\t\t    dynptr_type == BPF_DYNPTR_TYPE_SKB_META)\n+\t\tif (dynptr_write_changes_pkt_data(dynptr_type))\n \t\t\t/* this will trigger clear_all_pkt_pointers(), which will\n \t\t\t * invalidate all dynptr slices associated with the skb\n \t\t\t */\n@@ -13590,9 +13708,36 @@ static bool is_kfunc_bpf_preempt_enable(struct bpf_call_arg_meta *meta)\n \treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_preempt_enable]);\n }\n \n+/* These write to what their first argument, a dynptr, points to */\n+BTF_SET_START(dynptr_write_kfuncs)\n+BTF_ID(func, bpf_dynptr_copy)\n+BTF_ID(func, bpf_dynptr_memset)\n+#ifdef CONFIG_BPF_EVENTS\n+BTF_ID(func, bpf_probe_read_user_dynptr)\n+BTF_ID(func, bpf_probe_read_kernel_dynptr)\n+BTF_ID(func, bpf_probe_read_user_str_dynptr)\n+BTF_ID(func, bpf_probe_read_kernel_str_dynptr)\n+BTF_ID(func, bpf_copy_from_user_dynptr)\n+BTF_ID(func, bpf_copy_from_user_str_dynptr)\n+BTF_ID(func, bpf_copy_from_user_task_dynptr)\n+BTF_ID(func, bpf_copy_from_user_task_str_dynptr)\n+#endif\n+BTF_SET_END(dynptr_write_kfuncs)\n+\n+static bool is_kfunc_dynptr_write(struct bpf_call_arg_meta *meta)\n+{\n+\treturn meta-\u003ebtf == btf_vmlinux \u0026\u0026\n+\t       btf_id_set_contains(\u0026dynptr_write_kfuncs, meta-\u003efunc_id);\n+}\n+\n+/*\n+ * A write through the dynptr of an skb may reallocate its head. Before the\n+ * arguments are checked nobody knows what kind of dynptr it is.\n+ */\n bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta)\n {\n-\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_xdp_pull_data]);\n+\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_xdp_pull_data]) ||\n+\t       is_kfunc_dynptr_write(meta);\n }\n \n static u32 kfunc_abi_slots(const struct btf_func_model *fm)\n@@ -15530,7 +15675,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\n \t\t}\n \t}\n \n-\tif (bpf_is_kfunc_pkt_changing(\u0026meta))\n+\tif (is_kfunc_dynptr_write(\u0026meta) ?\n+\t    dynptr_write_changes_pkt_data(meta.dynptr_write_type) :\n+\t    bpf_is_kfunc_pkt_changing(\u0026meta))\n \t\tclear_all_pkt_pointers(env);\n \n \tproto_slots = kfunc_abi_slots(\u0026desc-\u003efunc_model);\n@@ -18117,7 +18264,7 @@ static void regs_refine_cond_op(struct bpf_reg_state *reg1, struct bpf_reg_state\n \t\t * this restriction. I.e., !(r1 \u0026 0x3) means neither bit 0 nor\n \t\t * bit 1 is set, which we can readily use in adjustments.\n \t\t */\n-\t\tif (!is_power_of_2(val))\n+\t\tif (hweight64(val) != 1)\n \t\t\tbreak;\n \t\tif (is_jmp32) {\n \t\t\tt = tnum_or(tnum_subreg(reg1-\u003evar_off), tnum_const(val));\n@@ -20633,35 +20780,11 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,\n \t\treturn -EINVAL;\n \t}\n \n-\tif (prog-\u003esleepable)\n-\t\tswitch (map-\u003emap_type) {\n-\t\tcase BPF_MAP_TYPE_HASH:\n-\t\tcase BPF_MAP_TYPE_RHASH:\n-\t\tcase BPF_MAP_TYPE_LRU_HASH:\n-\t\tcase BPF_MAP_TYPE_ARRAY:\n-\t\tcase BPF_MAP_TYPE_PERCPU_HASH:\n-\t\tcase BPF_MAP_TYPE_PERCPU_ARRAY:\n-\t\tcase BPF_MAP_TYPE_LRU_PERCPU_HASH:\n-\t\tcase BPF_MAP_TYPE_LPM_TRIE:\n-\t\tcase BPF_MAP_TYPE_ARRAY_OF_MAPS:\n-\t\tcase BPF_MAP_TYPE_HASH_OF_MAPS:\n-\t\tcase BPF_MAP_TYPE_RINGBUF:\n-\t\tcase BPF_MAP_TYPE_USER_RINGBUF:\n-\t\tcase BPF_MAP_TYPE_INODE_STORAGE:\n-\t\tcase BPF_MAP_TYPE_SK_STORAGE:\n-\t\tcase BPF_MAP_TYPE_TASK_STORAGE:\n-\t\tcase BPF_MAP_TYPE_CGRP_STORAGE:\n-\t\tcase BPF_MAP_TYPE_QUEUE:\n-\t\tcase BPF_MAP_TYPE_STACK:\n-\t\tcase BPF_MAP_TYPE_ARENA:\n-\t\tcase BPF_MAP_TYPE_INSN_ARRAY:\n-\t\tcase BPF_MAP_TYPE_PROG_ARRAY:\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tverbose(env,\n-\t\t\t\t\"Sleepable programs can only use array, hash, ringbuf and local storage maps\\n\");\n-\t\t\treturn -EINVAL;\n-\t\t}\n+\tif (prog-\u003esleepable \u0026\u0026 !map_needs_no_rcu(map)) {\n+\t\tverbose(env,\n+\t\t\t\"Sleepable programs can only use array, hash, ringbuf and local storage maps\\n\");\n+\t\treturn -EINVAL;\n+\t}\n \n \tif (bpf_map_is_cgroup_storage(map) \u0026\u0026\n \t    bpf_cgroup_storage_assign(env-\u003eprog-\u003eaux, map)) {\n@@ -20746,7 +20869,7 @@ static int __add_used_map(struct bpf_verifier_env *env, struct bpf_map *map)\n \tif (err)\n \t\treturn err;\n \n-\tif (env-\u003eprog-\u003esleepable)\n+\tif (bpf_prog_runs_sleepable(env-\u003eprog))\n \t\tatomic64_inc(\u0026map-\u003esleepable_refcnt);\n \n \t/* hold the map. If the program is rejected by verifier,\ndiff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c\nindex 5465e7eba2384..304b426bd44d4 100644\n--- a/kernel/trace/bpf_trace.c\n+++ b/kernel/trace/bpf_trace.c\n@@ -2209,6 +2209,7 @@ int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_raw_tp_link *\n \treturn tracepoint_probe_unregister(btp-\u003etp, (void *)btp-\u003ebpf_func, link);\n }\n \n+/* On success the caller releases *buf with kfree_const() */\n int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,\n \t\t\t    u32 *fd_type, const char **buf,\n \t\t\t    u64 *probe_offset, u64 *probe_addr,\n@@ -2218,6 +2219,12 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,\n \tstruct bpf_prog *prog;\n \tint flags, err = 0;\n \n+\t/*\n+\t * The list of dynamic events is walked, and a probe which has siblings\n+\t * can be deleted, with its strings, while its event is in use.\n+\t */\n+\tguard(mutex)(\u0026event_mutex);\n+\n \tprog = event-\u003eprog;\n \tif (!prog)\n \t\treturn -ENOENT;\n@@ -2258,6 +2265,12 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,\n #endif\n \t}\n \n+\tif (!err \u0026\u0026 *buf) {\n+\t\t*buf = kstrdup_const(*buf, GFP_KERNEL);\n+\t\tif (!*buf)\n+\t\t\terr = -ENOMEM;\n+\t}\n+\n \treturn err;\n }\n \ndiff --git a/net/bpf/test_run.c b/net/bpf/test_run.c\nindex d73cd247f8cd0..3043a7393c29c 100644\n--- a/net/bpf/test_run.c\n+++ b/net/bpf/test_run.c\n@@ -1656,20 +1656,19 @@ int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kat\n \t\tctx.selected_sk = NULL;\n \t\tretval = BPF_PROG_SK_LOOKUP_RUN_ARRAY(progs, ctx, bpf_prog_run);\n \t} while (bpf_test_timer_continue(\u0026t, 1, repeat, \u0026ret, \u0026duration));\n-\tbpf_test_timer_leave(\u0026t);\n-\n-\tif (ret \u003c 0)\n-\t\tgoto out;\n \n+\t/* Nothing but RCU keeps the selected socket */\n \tuser_ctx-\u003ecookie = 0;\n-\tif (ctx.selected_sk) {\n-\t\tif (ctx.selected_sk-\u003esk_reuseport \u0026\u0026 !ctx.no_reuseport) {\n+\tif (!ret \u0026\u0026 ctx.selected_sk) {\n+\t\tif (ctx.selected_sk-\u003esk_reuseport \u0026\u0026 !ctx.no_reuseport)\n \t\t\tret = -EOPNOTSUPP;\n-\t\t\tgoto out;\n-\t\t}\n-\n-\t\tuser_ctx-\u003ecookie = sock_gen_cookie(ctx.selected_sk);\n+\t\telse\n+\t\t\tuser_ctx-\u003ecookie = sock_gen_cookie(ctx.selected_sk);\n \t}\n+\tbpf_test_timer_leave(\u0026t);\n+\n+\tif (ret \u003c 0)\n+\t\tgoto out;\n \n \tret = bpf_test_finish(kattr, uattr, NULL, NULL, 0, 0, retval, duration);\n \tif (!ret)\ndiff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c\nindex 1d295a8769fad..1c59300af05c7 100644\n--- a/net/core/bpf_sk_storage.c\n+++ b/net/core/bpf_sk_storage.c\n@@ -164,6 +164,13 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)\n \tif (!sk_storage || hlist_empty(\u0026sk_storage-\u003elist))\n \t\tgoto out;\n \n+\t/*\n+\t * The maps lead to newsk as soon as an element is linked, but\n+\t * sk_clone() sets sk_refcnt only later.  Until then it holds whatever\n+\t * the slab object held before: no reference can be had yet.\n+\t */\n+\trefcount_set(\u0026newsk-\u003esk_refcnt, 0);\n+\n \thlist_for_each_entry_rcu(selem, \u0026sk_storage-\u003elist, snode) {\n \t\tstruct bpf_local_storage_elem *copy_selem;\n \t\tstruct bpf_local_storage_map *smap;\n@@ -692,8 +699,37 @@ struct bpf_iter_seq_sk_storage_map_info {\n \tstruct bpf_map *map;\n \tunsigned int bucket_id;\n \tunsigned skip_elems;\n+\tstruct rcu_head *dead_sks;\n };\n \n+/*\n+ * sock_put() in two halves. The end of a socket may want process context:\n+ * rfcomm_sock_destruct() takes a mutex. If the iterator drops the last\n+ * reference, it keeps the socket until it has left the RCU read side critical\n+ * section. Nobody uses sk_rcu before sk_destruct().\n+ */\n+static void\n+bpf_sk_storage_map_seq_put_sk(struct bpf_iter_seq_sk_storage_map_info *info,\n+\t\t\t      struct sock *sk)\n+{\n+\tif (refcount_dec_and_test(\u0026sk-\u003esk_refcnt)) {\n+\t\tsk-\u003esk_rcu.next = info-\u003edead_sks;\n+\t\tinfo-\u003edead_sks = \u0026sk-\u003esk_rcu;\n+\t}\n+}\n+\n+static void\n+bpf_sk_storage_map_seq_free_sks(struct bpf_iter_seq_sk_storage_map_info *info)\n+{\n+\tstruct sock *sk;\n+\n+\twhile (info-\u003edead_sks) {\n+\t\tsk = container_of(info-\u003edead_sks, struct sock, sk_rcu);\n+\t\tinfo-\u003edead_sks = sk-\u003esk_rcu.next;\n+\t\tsk_free(sk);\n+\t}\n+}\n+\n static struct bpf_local_storage_elem *\n bpf_sk_storage_map_seq_find_next(struct bpf_iter_seq_sk_storage_map_info *info,\n \t\t\t\t struct bpf_local_storage_elem *prev_selem)\n@@ -722,6 +758,7 @@ bpf_sk_storage_map_seq_find_next(struct bpf_iter_seq_sk_storage_map_info *info,\n \t\t\t/* not found, unlock and go to the next bucket */\n \t\t\tb = \u0026smap-\u003ebuckets[bucket_id++];\n \t\t\trcu_read_unlock();\n+\t\t\tbpf_sk_storage_map_seq_free_sks(info);\n \t\t\tskip_elems = 0;\n \t\t\tbreak;\n \t\t}\n@@ -789,12 +826,44 @@ DEFINE_BPF_ITER_FUNC(bpf_sk_storage_map, struct bpf_iter_meta *meta,\n \t\t     struct bpf_map *map, struct sock *sk,\n \t\t     void *value)\n \n+/*\n+ * Take a reference on the socket which owns @selem. RCU keeps the element, not\n+ * its owner. As long as the element is linked under the lock of the storage,\n+ * the owner has not got past bpf_sk_storage_free(), unless that has given up\n+ * on the lock. Then it still waits for owner_refcnt.\n+ */\n+static struct sock *\n+bpf_sk_storage_selem_get_sk(struct bpf_local_storage_elem *selem)\n+{\n+\tstruct bpf_local_storage *sk_storage;\n+\tstruct sock *sk = NULL;\n+\tunsigned long flags;\n+\n+\tsk_storage = rcu_dereference(selem-\u003elocal_storage);\n+\t/* reset since -\u003enext() looked: the socket goes away */\n+\tif (!sk_storage)\n+\t\treturn NULL;\n+\n+\tif (raw_res_spin_lock_irqsave(\u0026sk_storage-\u003elock, flags))\n+\t\treturn NULL;\n+\n+\tif (!hlist_unhashed(\u0026selem-\u003esnode) \u0026\u0026\n+\t    refcount_inc_not_zero(\u0026sk_storage-\u003eowner_refcnt)) {\n+\t\tsk = sk_storage-\u003eowner;\n+\t\tif (!refcount_inc_not_zero(\u0026sk-\u003esk_refcnt))\n+\t\t\tsk = NULL;\n+\t\tbpf_local_storage_unpin_owner(sk_storage);\n+\t}\n+\traw_res_spin_unlock_irqrestore(\u0026sk_storage-\u003elock, flags);\n+\n+\treturn sk;\n+}\n+\n static int __bpf_sk_storage_map_seq_show(struct seq_file *seq,\n \t\t\t\t\t struct bpf_local_storage_elem *selem)\n {\n \tstruct bpf_iter_seq_sk_storage_map_info *info = seq-\u003eprivate;\n \tstruct bpf_iter__bpf_sk_storage_map ctx = {};\n-\tstruct bpf_local_storage *sk_storage;\n \tstruct bpf_iter_meta meta;\n \tstruct bpf_prog *prog;\n \tint ret = 0;\n@@ -805,11 +874,14 @@ static int __bpf_sk_storage_map_seq_show(struct seq_file *seq,\n \t\tctx.meta = \u0026meta;\n \t\tctx.map = info-\u003emap;\n \t\tif (selem) {\n-\t\t\tsk_storage = rcu_dereference(selem-\u003elocal_storage);\n-\t\t\tctx.sk = sk_storage-\u003eowner;\n+\t\t\tctx.sk = bpf_sk_storage_selem_get_sk(selem);\n+\t\t\tif (!ctx.sk)\n+\t\t\t\treturn SEQ_SKIP;\n \t\t\tctx.value = SDATA(selem)-\u003edata;\n \t\t}\n \t\tret = bpf_iter_run_prog(prog, \u0026ctx);\n+\t\tif (ctx.sk)\n+\t\t\tbpf_sk_storage_map_seq_put_sk(info, ctx.sk);\n \t}\n \n \treturn ret;\n@@ -827,6 +899,7 @@ static void bpf_sk_storage_map_seq_stop(struct seq_file *seq, void *v)\n \t\t(void)__bpf_sk_storage_map_seq_show(seq, v);\n \telse\n \t\trcu_read_unlock();\n+\tbpf_sk_storage_map_seq_free_sks(seq-\u003eprivate);\n }\n \n static int bpf_iter_init_sk_storage_map(void *priv_data,\n@@ -846,6 +919,15 @@ static void bpf_iter_fini_sk_storage_map(void *priv_data)\n \tbpf_map_put_with_uref(seq_info-\u003emap);\n }\n \n+static int bpf_iter_map_check_prog(const struct bpf_prog *prog,\n+\t\t\t\t   const struct bpf_iter_aux_info *aux)\n+{\n+\tif (prog-\u003eaux-\u003emax_rdwr_access \u003e aux-\u003emap-\u003evalue_size)\n+\t\treturn -EACCES;\n+\n+\treturn bpf_iter_map_check_value_write(prog, aux-\u003emap);\n+}\n+\n static int bpf_iter_attach_map(struct bpf_prog *prog,\n \t\t\t       union bpf_iter_link_info *linfo,\n \t\t\t       struct bpf_iter_aux_info *aux)\n@@ -863,12 +945,11 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,\n \tif (map-\u003emap_type != BPF_MAP_TYPE_SK_STORAGE)\n \t\tgoto put_map;\n \n-\tif (prog-\u003eaux-\u003emax_rdwr_access \u003e map-\u003evalue_size) {\n-\t\terr = -EACCES;\n+\taux-\u003emap = map;\n+\terr = bpf_iter_map_check_prog(prog, aux);\n+\tif (err)\n \t\tgoto put_map;\n-\t}\n \n-\taux-\u003emap = map;\n \treturn 0;\n \n put_map:\n@@ -899,6 +980,7 @@ static struct bpf_iter_reg bpf_sk_storage_map_reg_info = {\n \t.target\t\t\t= \"bpf_sk_storage_map\",\n \t.attach_target\t\t= bpf_iter_attach_map,\n \t.detach_target\t\t= bpf_iter_detach_map,\n+\t.check_prog\t\t= bpf_iter_map_check_prog,\n \t.show_fdinfo\t\t= bpf_iter_map_show_fdinfo,\n \t.fill_link_info\t\t= bpf_iter_map_fill_link_info,\n \t.ctx_arg_info_size\t= 2,\ndiff --git a/net/core/filter.c b/net/core/filter.c\nindex ba536be2915fb..0e3261f8d322c 100644\n--- a/net/core/filter.c\n+++ b/net/core/filter.c\n@@ -1731,7 +1731,8 @@ BPF_CALL_5(bpf_skb_store_bytes, struct sk_buff *, skb, u32, offset,\n \tif (flags \u0026 BPF_F_RECOMPUTE_CSUM)\n \t\t__skb_postpull_rcsum(skb, ptr, len, offset);\n \n-\tmemcpy(ptr, from, len);\n+\t/* through a dynptr the source may be an overlapping slice of the skb */\n+\tmemmove(ptr, from, len);\n \n \tif (flags \u0026 BPF_F_RECOMPUTE_CSUM)\n \t\t__skb_postpush_rcsum(skb, ptr, len, offset);\n@@ -1752,9 +1753,32 @@ static const struct bpf_func_proto bpf_skb_store_bytes_proto = {\n \t.arg5_type\t= ARG_ANYTHING,\n };\n \n+/*\n+ * The source of a write through a dynptr may be a slice of the same skb.\n+ * Making the skb writable can move its head: follow the move.\n+ */\n+static int bpf_try_make_writable_from(struct sk_buff *skb, u32 write_len,\n+\t\t\t\t      const void **from)\n+{\n+\tconst void *head = skb-\u003ehead;\n+\tbool in_head = *from \u003e= head \u0026\u0026\n+\t\t       *from \u003c (const void *)skb_end_pointer(skb);\n+\tint err;\n+\n+\terr = bpf_try_make_writable(skb, write_len);\n+\tif (!err \u0026\u0026 in_head)\n+\t\t*from = skb-\u003ehead + (*from - head);\n+\treturn err;\n+}\n+\n int __bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from,\n \t\t\t  u32 len, u64 flags)\n {\n+\tif (unlikely(offset \u003e INT_MAX))\n+\t\treturn -EFAULT;\n+\tif (unlikely(bpf_try_make_writable_from(skb, offset + len, \u0026from)))\n+\t\treturn -EFAULT;\n+\n \treturn ____bpf_skb_store_bytes(skb, offset, from, len, flags);\n }\n \n@@ -3612,6 +3636,11 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,\n \t\t\treturn -ENOTSUPP;\n \t}\n \n+\t/* The MSS is lowered by len_diff: something has to be left of it. */\n+\tif (skb_is_gso(skb) \u0026\u0026 !(flags \u0026 BPF_F_ADJ_ROOM_FIXED_GSO) \u0026\u0026\n+\t    skb_shinfo(skb)-\u003egso_size \u003c= len_diff)\n+\t\treturn -ENOTSUPP;\n+\n \tret = skb_cow_head(skb, meta_len + len_diff);\n \tif (unlikely(ret \u003c 0))\n \t\treturn ret;\n@@ -7017,15 +7046,15 @@ static void bpf_update_srh_state(struct sk_buff *skb)\n {\n \tstruct seg6_bpf_srh_state *srh_state =\n \t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n-\tint srhoff = 0;\n \n-\tif (ipv6_find_hdr(skb, \u0026srhoff, IPPROTO_ROUTING, NULL, NULL) \u003c 0) {\n-\t\tsrh_state-\u003esrh = NULL;\n-\t} else {\n-\t\tsrh_state-\u003esrh = (struct ipv6_sr_hdr *)(skb-\u003edata + srhoff);\n+\t/* Behind a decapsulation this is a header that nobody has looked at */\n+\tsrh_state-\u003esrh = seg6_get_srh(skb, 0);\n+\tif (srh_state-\u003esrh) {\n \t\tsrh_state-\u003ehdrlen = srh_state-\u003esrh-\u003ehdrlen \u003c\u003c 3;\n \t\tsrh_state-\u003evalid = true;\n \t}\n+\t/* it may have been pulled into the head */\n+\tbpf_compute_data_pointers(skb);\n }\n \n BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\n@@ -7058,9 +7087,14 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\n \n \t\tif (ipv6_find_hdr(skb, \u0026hdroff, IPPROTO_IPV6, NULL, NULL) \u003c 0)\n \t\t\treturn -EBADMSG;\n-\t\tif (!pskb_pull(skb, hdroff))\n+\t\t/* As long as nothing has been changed, the program goes on */\n+\t\tif (!pskb_may_pull(skb, hdroff + sizeof(struct ipv6hdr))) {\n+\t\t\t/* but the head may have moved */\n+\t\t\tbpf_update_srh_state(skb);\n \t\t\treturn -EBADMSG;\n+\t\t}\n \n+\t\t__skb_pull(skb, hdroff);\n \t\tskb_postpull_rcsum(skb, skb_network_header(skb), hdroff);\n \t\tskb_reset_network_header(skb);\n \t\tskb_reset_transport_header(skb);\n@@ -7074,8 +7108,8 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\n \t\t\treturn -EBADMSG;\n \t\terr = bpf_push_seg6_encap(skb, BPF_LWT_ENCAP_SEG6_INLINE,\n \t\t\t\t\t  param, param_len);\n-\t\tif (!err)\n-\t\t\tbpf_update_srh_state(skb);\n+\t\t/* The header can be in place although err says otherwise */\n+\t\tbpf_update_srh_state(skb);\n \n \t\treturn err;\n \tcase SEG6_LOCAL_ACTION_END_B6_ENCAP:\n@@ -7083,8 +7117,8 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\n \t\t\treturn -EBADMSG;\n \t\terr = bpf_push_seg6_encap(skb, BPF_LWT_ENCAP_SEG6,\n \t\t\t\t\t  param, param_len);\n-\t\tif (!err)\n-\t\t\tbpf_update_srh_state(skb);\n+\t\t/* The header can be in place although err says otherwise */\n+\t\tbpf_update_srh_state(skb);\n \n \t\treturn err;\n \tdefault:\n@@ -12414,7 +12448,7 @@ int __bpf_skb_meta_store_bytes(struct sk_buff *skb, u32 offset,\n {\n \tif (unlikely(flags))\n \t\treturn -EINVAL;\n-\tif (unlikely(bpf_try_make_writable(skb, 0)))\n+\tif (unlikely(bpf_try_make_writable_from(skb, 0, \u0026from)))\n \t\treturn -EFAULT;\n \n \tmemmove(bpf_skb_meta_pointer(skb, offset), from, len);\ndiff --git a/net/core/sock_map.c b/net/core/sock_map.c\nindex 38df842843289..057e2f3c0265e 100644\n--- a/net/core/sock_map.c\n+++ b/net/core/sock_map.c\n@@ -1933,6 +1933,15 @@ int sock_map_link_create(const union bpf_attr *attr, struct bpf_prog *prog)\n \treturn ret;\n }\n \n+static int sock_map_iter_check_prog(const struct bpf_prog *prog,\n+\t\t\t\t    const struct bpf_iter_aux_info *aux)\n+{\n+\tif (prog-\u003eaux-\u003emax_rdonly_access \u003e aux-\u003emap-\u003ekey_size)\n+\t\treturn -EACCES;\n+\n+\treturn 0;\n+}\n+\n static int sock_map_iter_attach_target(struct bpf_prog *prog,\n \t\t\t\t       union bpf_iter_link_info *linfo,\n \t\t\t\t       struct bpf_iter_aux_info *aux)\n@@ -1951,12 +1960,11 @@ static int sock_map_iter_attach_target(struct bpf_prog *prog,\n \t    map-\u003emap_type != BPF_MAP_TYPE_SOCKHASH)\n \t\tgoto put_map;\n \n-\tif (prog-\u003eaux-\u003emax_rdonly_access \u003e map-\u003ekey_size) {\n-\t\terr = -EACCES;\n+\taux-\u003emap = map;\n+\terr = sock_map_iter_check_prog(prog, aux);\n+\tif (err)\n \t\tgoto put_map;\n-\t}\n \n-\taux-\u003emap = map;\n \treturn 0;\n \n put_map:\n@@ -1973,6 +1981,7 @@ static struct bpf_iter_reg sock_map_iter_reg = {\n \t.target\t\t\t= \"sockmap\",\n \t.attach_target\t\t= sock_map_iter_attach_target,\n \t.detach_target\t\t= sock_map_iter_detach_target,\n+\t.check_prog\t\t= sock_map_iter_check_prog,\n \t.show_fdinfo\t\t= bpf_iter_map_show_fdinfo,\n \t.fill_link_info\t\t= bpf_iter_map_fill_link_info,\n \t.ctx_arg_info_size\t= 2,\n"
}

2/1 2026/10/17 07:02 agent patch-evaluator
2m Model:
core

Args:
null

Results:
{
  "EnableConfigs": [
    "BPF_SYSCALL",
    "NET",
    "BPF_EVENTS",
    "KPROBE_EVENTS",
    "UPROBE_EVENTS",
    "IPV6_SEG6_LWTUNNEL"
  ],
  "FocusSymbols": [
    "bpf_iter_map_check_value_write",
    "bpf_iter_link_replace",
    "bpf_selem_unlink_nofail",
    "bpf_sk_storage_clone",
    "bpf_sk_storage_selem_get_sk",
    "htab_map_update_elem",
    "cpu_map_generic_redirect",
    "cpu_map_kthread_run",
    "bpf_token_create",
    "bpf_task_fd_query",
    "bpf_prog_test_run_sk_lookup",
    "__bpf_skb_store_bytes",
    "bpf_skb_net_grow",
    "bpf_lwt_seg6_action",
    "check_buffer_access",
    "check_kfunc_call",
    "check_map_func_compatibility",
    "push_callback_call"
  ],
  "Reasoning": "The patch series modifies core BPF subsystem logic, including the BPF verifier (dynptr writes, sleepable async callbacks, RCU callback tracking, buffer access ranges), BPF iterators (map/vma/sk_storage iteration, link replacement, program capability checks), map lifetime and concurrency (local storage refcounting/unlinking, hashtab extra elements, map-in-map), networking helpers (skb store bytes, seg6 actions, cpumap device reference holding), and syscall interfaces. These paths are directly reachable and exercisable from unprivileged or privileged userspace via the bpf() system call, socket operations, and perf/tracepoints. Fuzzing is warranted to uncover regressions, verification bypasses, or concurrency issues.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.

================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.

- REACHABILITY IS THE PRIMARY GATE:
  Fuzzing can only discover bugs in code that can actually execute in standard virtualized
  environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
  If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
  regardless of whether it adds assertions or complex logic.

- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
  Patch authors routinely label changes as "cleanups", "refactorings", or state
  "No functional change intended". Do NOT take these claims at face value.
  Code refactorings that rearrange logic, introduce helper functions, or alter state management
  in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
  If reachable executable code is modified or refactored, it MUST be fuzzed.

- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
  When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
  BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
  Even if the author believes the invariant always holds, fuzzing is essential to verify whether
  an unusual sequence of operations can violate it.

================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:

- Non-kernel and non-executable changes:
  * Modifications to Documentation/, comments, or spelling fixes.
  * User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
    that do not affect the compiled kernel image (vmlinux) or kernel modules.
  * Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
    that do not alter control flow or data structures.
  * Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
  * Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
    ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
  * Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
    physical PCI hot-unplug or manual sysfs driver unbinding.
  * Code paths exclusive to architectures other than the target architecture.

================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
  * Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
    BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
  * Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
  * Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
  * Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).

================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:

- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
  Do NOT list generic, ubiquitous functions called by almost every program in the corpus
  (including, but not limited to: general memory allocators and deallocators, page fault
  and trap handlers, or core synchronization primitives; this is not an exhaustive list).
  Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
  which severely dilutes fuzzing effort away from the actual changes.

- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
  List functions that specifically implement the logic being added or altered, or direct API entrypoints
  for the subsystem feature under review.

- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
  Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
  distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
  If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
  functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).

================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 1117fabc0498a30e4d022f35e627ac586b1db367
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Oct 17 07:02:07 2026 +0000

    syz-cluster: applied patch under review

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 54144372281cb..c1d92fd10ef12 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -341,6 +341,7 @@ struct bpf_map {
 	bool frozen; /* write-once; write-protected by freeze_mutex */
 	bool free_after_mult_rcu_gp;
 	bool free_after_rcu_gp;
+	bool was_inner_map;
 	atomic64_t sleepable_refcnt;
 	s64 __percpu *elem_count;
 	u64 cookie; /* write-once */
@@ -1858,6 +1859,9 @@ struct bpf_prog_aux {
 	u32 ctx_arg_info_size;
 	u32 max_rdonly_access;
 	u32 max_rdwr_access;
+	/* [min, max): the bytes of a rdwr buffer that may be written */
+	u32 min_rdwr_write;
+	u32 max_rdwr_write;
 	u32 subprog_start;
 	struct btf *attach_btf;
 	struct bpf_ctx_arg_aux *ctx_arg_info;
@@ -1873,6 +1877,7 @@ struct bpf_prog_aux {
 	bool attach_btf_trace; /* true if attaching to BTF-enabled raw tp */
 	bool attach_tracing_prog; /* true if tracing another tracing program */
 	bool tramp_linked; /* true if it was ever linked to a trampoline */
+	bool sleepable_async_cb; /* has a bpf_wq or bpf_task_work callback */
 	bool func_proto_unreliable;
 	bool tail_call_reachable;
 	bool xdp_has_frags;
@@ -1958,6 +1963,7 @@ struct bpf_prog_aux {
 	union {
 		struct work_struct work;
 		struct rcu_head	rcu;
+		struct rcu_work rwork;
 	};
 	struct bpf_stream *stream[2];
 	struct mutex st_ops_assoc_mutex;
@@ -2006,6 +2012,15 @@ struct bpf_prog {
 	};
 };
 
+/*
+ * Does the program, or a callback of it, run under RCU Tasks Trace protection
+ * only, outside of any RCU read side critical section?
+ */
+static inline bool bpf_prog_runs_sleepable(const struct bpf_prog *prog)
+{
+	return prog->sleepable || prog->aux->sleepable_async_cb;
+}
+
 struct bpf_array_aux {
 	/* Programs with direct jumps into programs part of this array. */
 	struct list_head poke_progs;
@@ -3128,6 +3143,8 @@ typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *prog,
 					union bpf_iter_link_info *linfo,
 					struct bpf_iter_aux_info *aux);
 typedef void (*bpf_iter_detach_target_t)(struct bpf_iter_aux_info *aux);
+typedef int (*bpf_iter_check_prog_t)(const struct bpf_prog *prog,
+				     const struct bpf_iter_aux_info *aux);
 typedef void (*bpf_iter_show_fdinfo_t) (const struct bpf_iter_aux_info *aux,
 					struct seq_file *seq);
 typedef int (*bpf_iter_fill_link_info_t)(const struct bpf_iter_aux_info *aux,
@@ -3137,7 +3154,8 @@ typedef const struct bpf_func_proto *
 			     const struct bpf_prog *prog);
 
 enum bpf_iter_feature {
-	BPF_ITER_RESCHED	= BIT(0),
+	BPF_ITER_RESCHED	= BIT(0),	/* may cond_resched() between objects */
+	BPF_ITER_NOSLEEP	= BIT(1),	/* ->show() can't run sleepable progs */
 };
 
 #define BPF_ITER_CTX_ARG_MAX 2
@@ -3145,6 +3163,8 @@ struct bpf_iter_reg {
 	const char *target;
 	bpf_iter_attach_target_t attach_target;
 	bpf_iter_detach_target_t detach_target;
+	/* may the program run on what the link is attached to? */
+	bpf_iter_check_prog_t check_prog;
 	bpf_iter_show_fdinfo_t show_fdinfo;
 	bpf_iter_fill_link_info_t fill_link_info;
 	bpf_iter_get_func_proto_t get_func_proto;
@@ -3181,6 +3201,8 @@ void bpf_iter_map_show_fdinfo(const struct bpf_iter_aux_info *aux,
 			      struct seq_file *seq);
 int bpf_iter_map_fill_link_info(const struct bpf_iter_aux_info *aux,
 				struct bpf_link_info *info);
+int bpf_iter_map_check_value_write(const struct bpf_prog *prog,
+				   const struct bpf_map *map);
 
 int map_set_for_each_callback_args(struct bpf_verifier_env *env,
 				   struct bpf_func_state *caller,
diff --git a/include/linux/bpf_local_storage.h b/include/linux/bpf_local_storage.h
index 9e4f5c45c974d..6c643ac510799 100644
--- a/include/linux/bpf_local_storage.h
+++ b/include/linux/bpf_local_storage.h
@@ -104,6 +104,19 @@ struct bpf_local_storage {
 	refcount_t owner_refcnt;/* Used to pin owner when map_free is uncharging */
 };
 
+/*
+ * Drop a reference got by refcount_inc_not_zero(&local_storage->owner_refcnt).
+ * bpf_local_storage_destroy() may have dropped the owner's reference meanwhile
+ * and wait for the count to reach zero, so this one can be the last.
+ */
+static inline void
+bpf_local_storage_unpin_owner(struct bpf_local_storage *local_storage)
+{
+	bool last __maybe_unused;
+
+	last = refcount_dec_and_test(&local_storage->owner_refcnt);
+}
+
 /* U16_MAX is much more than enough for sk local storage
  * considering a tcp_sock is ~2k.
  */
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 112ca1511da4d..1ca03f8cfd838 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -379,6 +379,11 @@ struct bpf_func_state {
 	bool in_async_callback_fn;
 	bool in_exception_callback_fn;
 	bool no_stack_arg_load;
+	/*
+	 * The helper invokes this callback under rcu_read_lock(), so the
+	 * callback and its callees run in an RCU read-side critical section.
+	 */
+	bool in_rcu_callback_fn;
 	/* For callback calling functions that limit number of possible
 	 * callback executions (e.g. bpf_loop) keeps track of current
 	 * simulated iteration number.
@@ -1796,6 +1801,8 @@ struct bpf_call_arg_meta {
 	u32 kfunc_flags;
 	const char *func_name;
 	struct arg_constant_desc arg_constant;
+	/* The type of the dynptr that the kfunc writes through */
+	enum bpf_dynptr_type dynptr_write_type;
 
 	/* arg_{btf,btf_id,owning_ref} are used by kfunc-specific handling,
 	 * generally to pass info about user-defined local kptr types to later
diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
index b40eb404adab9..5fd376bd210b0 100644
--- a/kernel/bpf/bpf_iter.c
+++ b/kernel/bpf/bpf_iter.c
@@ -72,6 +72,15 @@ static inline bool bpf_iter_target_support_resched(const struct bpf_iter_target_
 	return tinfo->reg_info->feature & BPF_ITER_RESCHED;
 }
 
+/* Only allow sleepable program for resched-able iterator that can run one */
+static bool bpf_iter_target_support_prog(const struct bpf_iter_target_info *tinfo,
+					 const struct bpf_prog *prog)
+{
+	return !prog->sleepable ||
+	       (bpf_iter_target_support_resched(tinfo) &&
+		!(tinfo->reg_info->feature & BPF_ITER_NOSLEEP));
+}
+
 static bool bpf_iter_support_resched(struct seq_file *seq)
 {
 	struct bpf_iter_priv_data *iter_priv;
@@ -342,6 +351,13 @@ int bpf_iter_prog_supported(struct bpf_prog *prog)
 	const char *prefix = BPF_ITER_FUNC_PREFIX;
 	int prefix_len = strlen(prefix);
 
+	/*
+	 * The attach function of an extension is a subprogram of the iterator
+	 * program that it extends, whatever its name is.
+	 */
+	if (prog->type == BPF_PROG_TYPE_EXT)
+		return -EINVAL;
+
 	if (strncmp(attach_fname, prefix, prefix_len))
 		return -EINVAL;
 
@@ -409,6 +425,8 @@ static int bpf_iter_link_replace(struct bpf_link *link,
 				 struct bpf_prog *new_prog,
 				 struct bpf_prog *old_prog)
 {
+	struct bpf_iter_link *iter_link =
+		container_of(link, struct bpf_iter_link, link);
 	int ret = 0;
 
 	mutex_lock(&link_mutex);
@@ -419,11 +437,19 @@ static int bpf_iter_link_replace(struct bpf_link *link,
 
 	if (link->prog->type != new_prog->type ||
 	    link->prog->expected_attach_type != new_prog->expected_attach_type ||
-	    link->prog->aux->attach_btf_id != new_prog->aux->attach_btf_id) {
+	    link->prog->aux->attach_btf_id != new_prog->aux->attach_btf_id ||
+	    !bpf_iter_target_support_prog(iter_link->tinfo, new_prog)) {
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 
+	if (iter_link->tinfo->reg_info->check_prog) {
+		ret = iter_link->tinfo->reg_info->check_prog(new_prog,
+							     &iter_link->aux);
+		if (ret)
+			goto out_unlock;
+	}
+
 	old_prog = xchg(&link->prog, new_prog);
 	bpf_prog_put(old_prog);
 
@@ -544,8 +570,7 @@ int bpf_iter_link_attach(const union bpf_attr *attr, bpfptr_t uattr,
 	if (!tinfo)
 		return -ENOENT;
 
-	/* Only allow sleepable program for resched-able iterator */
-	if (prog->sleepable && !bpf_iter_target_support_resched(tinfo))
+	if (!bpf_iter_target_support_prog(tinfo, prog))
 		return -EINVAL;
 
 	link = kzalloc_obj(*link, GFP_USER | __GFP_NOWARN);
diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c
index 4642da062f0f8..3d0c455d258c2 100644
--- a/kernel/bpf/bpf_local_storage.c
+++ b/kernel/bpf/bpf_local_storage.c
@@ -199,7 +199,7 @@ static void bpf_selem_unlink_storage_nolock_misc(struct bpf_local_storage_elem *
 	}
 
 	if (pin_owner)
-		refcount_dec(&local_storage->owner_refcnt);
+		bpf_local_storage_unpin_owner(local_storage);
 }
 
 /* local_storage->lock must be held and selem->local_storage == local_storage.
@@ -352,7 +352,7 @@ int bpf_selem_unlink(struct bpf_local_storage_elem *selem)
 static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,
 				    struct bpf_local_storage_map_bucket *b)
 {
-	bool in_map_free = !!b, free_storage = false;
+	bool in_map_free = !!b, free_storage = false, sleepable_users = false;
 	struct bpf_local_storage *local_storage;
 	struct bpf_local_storage_map *smap;
 	unsigned long flags;
@@ -362,6 +362,10 @@ static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,
 	smap = rcu_dereference_check(SDATA(selem)->smap, bpf_rcu_lock_held());
 
 	if (smap) {
+		/* A map that is freed, or NULL here, has no program left. */
+		sleepable_users = !in_map_free &&
+				  (atomic64_read(&smap->map.sleepable_refcnt) ||
+				   READ_ONCE(smap->map.was_inner_map));
 		b = b ? : select_bucket(smap, local_storage);
 		err = raw_res_spin_lock_irqsave(&b->lock, flags);
 		if (!err) {
@@ -431,13 +435,18 @@ static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,
 	 * then freed after an RCU grace period. However, if destroy() and map_free() are
 	 * racing or rqspinlock returns errors in unlikely situations (unlink != 2), free
 	 * the selem only after both map_free() and destroy() see the selem.
+	 *
+	 * The owner that map_free() takes an selem from is alive: sleepable code, which
+	 * is in no RCU read side critical section, may be walking its list for another
+	 * map.  And it can still use a value that it got before it let go of an owner
+	 * that destroy() is called for.
 	 */
 	if (unlink == 2 ||
 	    atomic_cmpxchg(&selem->state, SELEM_UNLINKED, SELEM_TOFREE) == SELEM_UNLINKED)
-		bpf_selem_free(selem, true);
+		bpf_selem_free(selem, !in_map_free && !sleepable_users);
 
 	if (free_storage)
-		bpf_local_storage_free(local_storage, true);
+		bpf_local_storage_free(local_storage, !in_map_free);
 }
 
 void __bpf_local_storage_insert_cache(struct bpf_local_storage *local_storage,
@@ -753,8 +762,8 @@ u32 bpf_local_storage_destroy(struct bpf_local_storage *local_storage)
 		while (refcount_read(&local_storage->owner_refcnt))
 			cpu_relax();
 		/*
-		 * Paired with refcount_dec() in bpf_selem_unlink_nofail()
-		 * to make sure destroy() sees the correct local_storage->mem_charge.
+		 * Paired with bpf_local_storage_unpin_owner() to make sure
+		 * destroy() sees the correct local_storage->mem_charge.
 		 */
 		smp_mb();
 	}
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 64c78434fa050..a9bf4c3c0a273 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -1081,6 +1081,8 @@ static const struct btf_type *btf_type_skip_qualifiers(const struct btf *btf,
 }
 
 #define BTF_SHOW_MAX_ITER	10
+/* nested structs and arrays shown; __btf_show_indent() has as many columns */
+#define BTF_SHOW_MAX_DEPTH	32
 
 #define BTF_KIND_BIT(kind)	(1ULL << kind)
 
@@ -1474,8 +1476,18 @@ static void *btf_show_start_aggr_type(struct btf_show *show,
 				      const struct btf_type *t,
 				      u32 type_id, void *data)
 {
-	void *safe_data = btf_show_start_type(show, t, type_id, data);
+	void *safe_data;
 
+	/*
+	 * Structs and arrays are shown by recursion.  BTF loading bounds the
+	 * depth of one resolve walk, not how deep resolved types may nest.
+	 */
+	if (show->state.depth >= BTF_SHOW_MAX_DEPTH) {
+		show->state.status = -E2BIG;
+		return NULL;
+	}
+
+	safe_data = btf_show_start_type(show, t, type_id, data);
 	if (!safe_data)
 		return safe_data;
 
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index bce7b5abcfda3..2ee950e9ac829 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -598,7 +598,9 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
 			 */
 			if (ret == 0 && fp->might_sleep)
 				mark_subprog_might_sleep(env, t);
-			if (bpf_helper_changes_pkt_data(insn->imm))
+			/* nobody knows yet whether the dynptr is that of an skb */
+			if (bpf_helper_changes_pkt_data(insn->imm) ||
+			    insn->imm == BPF_FUNC_dynptr_write)
 				mark_subprog_changes_pkt_data(env, t);
 		} else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
 			struct bpf_call_arg_meta meta;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 642f0ab8eb2d8..956555fc5e9f5 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -269,6 +269,8 @@ struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
 		memcpy(fp, fp_old, fp_old->pages * PAGE_SIZE);
 		fp->pages = pages;
 		fp->aux->prog = fp;
+		if (fp->aux->offload)
+			fp->aux->offload->prog = fp;
 
 		/* We keep fp->aux from fp_old around in the new
 		 * reallocated structure.
@@ -3042,7 +3044,7 @@ void __bpf_free_used_maps(struct bpf_prog_aux *aux,
 	bool sleepable;
 	u32 i;
 
-	sleepable = aux->prog->sleepable;
+	sleepable = bpf_prog_runs_sleepable(aux->prog);
 	for (i = 0; i < len; i++) {
 		map = used_maps[i];
 		if (map->ops->map_poke_untrack)
@@ -3085,12 +3087,40 @@ static void bpf_free_used_btfs(struct bpf_prog_aux *aux)
 	kfree(aux->used_btfs);
 }
 
-static void bpf_prog_free_deferred(struct work_struct *work)
+static void bpf_prog_free_images(struct work_struct *work)
 {
 	struct bpf_prog_aux *aux;
 	int i;
 
+	aux = container_of(to_rcu_work(work), struct bpf_prog_aux, rwork);
+	for (i = 0; i < aux->real_func_cnt; i++) {
+		/* We can just unlink the subprog poke descriptor table as
+		 * it was originally linked to the main program and is also
+		 * released along with it.
+		 */
+		aux->func[i]->aux->poke_tab = NULL;
+		bpf_jit_free(aux->func[i]);
+	}
+	if (aux->real_func_cnt) {
+		kfree(aux->func);
+		bpf_prog_unlock_free(aux->prog);
+	} else {
+		bpf_jit_free(aux->prog);
+	}
+}
+
+static void bpf_prog_free_deferred(struct work_struct *work)
+{
+	struct bpf_prog_aux *aux;
+	bool ksyms;
+
 	aux = container_of(work, struct bpf_prog_aux, work);
+	/*
+	 * A prog that still runs when its last reference goes needs its symbols,
+	 * by which its exception table is found.  It has ended by now.
+	 */
+	ksyms = aux->real_func_cnt || !list_empty(&aux->ksym.lnode);
+	bpf_prog_kallsyms_del_all(aux->prog);
 #ifdef CONFIG_BPF_SYSCALL
 	bpf_free_kfunc_btf_tab(aux->kfunc_btf_tab);
 #endif
@@ -3109,20 +3139,12 @@ static void bpf_prog_free_deferred(struct work_struct *work)
 #endif
 	if (aux->dst_trampoline)
 		bpf_trampoline_put(aux->dst_trampoline);
-	for (i = 0; i < aux->real_func_cnt; i++) {
-		/* We can just unlink the subprog poke descriptor table as
-		 * it was originally linked to the main program and is also
-		 * released along with it.
-		 */
-		aux->func[i]->aux->poke_tab = NULL;
-		bpf_jit_free(aux->func[i]);
-	}
-	if (aux->real_func_cnt) {
-		kfree(aux->func);
-		bpf_prog_unlock_free(aux->prog);
-	} else {
-		bpf_jit_free(aux->prog);
-	}
+	/* The symbols are looked up under rcu_read_lock() */
+	INIT_RCU_WORK(&aux->rwork, bpf_prog_free_images);
+	if (ksyms)
+		queue_rcu_work(system_percpu_wq, &aux->rwork);
+	else
+		bpf_prog_free_images(&aux->rwork.work);
 }
 
 void bpf_prog_free(struct bpf_prog *fp)
diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
index 5e59ab896f058..eb87131b1bef5 100644
--- a/kernel/bpf/cpumap.c
+++ b/kernel/bpf/cpumap.c
@@ -45,6 +45,7 @@
  */
 
 #define CPU_MAP_BULK_SIZE 8  /* 8 == one cacheline on 64-bit archs */
+#define CPU_MAP_HELD_DEVS 2048
 struct bpf_cpu_map_entry;
 struct bpf_cpu_map;
 
@@ -74,6 +75,13 @@ struct bpf_cpu_map_entry {
 
 	struct completion kthread_running;
 	struct rcu_work free_work;
+
+	/*
+	 * Every frame and skb in the queue holds a reference to its device.
+	 * The kthread keeps it until nothing is left in GRO.
+	 */
+	struct net_device *held[CPU_MAP_HELD_DEVS];
+	u32 nr_held;
 };
 
 struct bpf_cpu_map {
@@ -129,9 +137,11 @@ static void __cpu_map_ring_cleanup(struct ptr_ring *ring)
 		WARN_ON_ONCE(1);
 		if (unlikely(__ptr_test_bit(0, &ptr))) {
 			__ptr_clear_bit(0, &ptr);
+			dev_put(((struct sk_buff *)ptr)->dev);
 			kfree_skb(ptr);
 			continue;
 		}
+		dev_put(((struct xdp_frame *)ptr)->dev_rx);
 		xdp_return_frame(ptr);
 	}
 }
@@ -311,7 +321,7 @@ static int cpu_map_kthread_run(void *data)
 		void *frames[CPUMAP_BATCH];
 		void *skbs[CPUMAP_BATCH];
 		u32 i, n, m;
-		bool empty;
+		bool empty, full;
 
 		/* Release CPU reschedule checks */
 		if (__ptr_ring_empty(rcpu->queue)) {
@@ -344,10 +354,12 @@ static int cpu_map_kthread_run(void *data)
 				struct sk_buff *skb = f;
 
 				__ptr_clear_bit(0, &skb);
+				rcpu->held[rcpu->nr_held++] = skb->dev;
 				skbs[ret.skb_n++] = skb;
 				continue;
 			}
 
+			rcpu->held[rcpu->nr_held++] = ((struct xdp_frame *)f)->dev_rx;
 			frames[ret.xdp_n++] = f;
 			page = virt_to_page(f);
 
@@ -398,10 +410,13 @@ static int cpu_map_kthread_run(void *data)
 		/* Flush either every 64 packets or in case of empty ring */
 		packets += n;
 		empty = __ptr_ring_empty(rcpu->queue);
-		if (packets >= NAPI_POLL_WEIGHT || empty) {
-			cpu_map_gro_flush(rcpu, empty);
+		full = empty || rcpu->nr_held > CPU_MAP_HELD_DEVS - CPUMAP_BATCH;
+		if (packets >= NAPI_POLL_WEIGHT || full) {
+			cpu_map_gro_flush(rcpu, full);
 			packets = 0;
 		}
+		while (full && rcpu->nr_held)
+			dev_put(rcpu->held[--rcpu->nr_held]);
 
 		local_bh_enable(); /* resched point, may call do_softirq() */
 	}
@@ -738,12 +753,14 @@ static void bq_flush_to_queue(struct xdp_bulk_queue *bq)
 
 	for (i = 0; i < bq->count; i++) {
 		struct xdp_frame *xdpf = bq->q[i];
-		int err;
 
-		err = __ptr_ring_produce(q, xdpf);
-		if (err) {
+		if (__ptr_ring_full(q)) {
 			drops++;
 			xdp_return_frame_rx_napi(xdpf);
+		} else {
+			/* The device cannot go before the flush, from now on it can */
+			dev_hold(xdpf->dev_rx);
+			__ptr_ring_produce(q, xdpf);
 		}
 		processed++;
 	}
@@ -807,11 +824,15 @@ int cpu_map_generic_redirect(struct bpf_cpu_map_entry *rcpu,
 
 	__skb_pull(skb, skb->mac_len);
 	skb_set_redirected(skb, false);
+	dev_hold(skb->dev);
 	__ptr_set_bit(0, &skb);
 
 	ret = ptr_ring_produce(rcpu->queue, skb);
-	if (ret < 0)
+	if (ret < 0) {
+		__ptr_clear_bit(0, &skb);
+		dev_put(skb->dev);
 		goto trace;
+	}
 
 	wake_up_process(rcpu->kthread);
 trace:
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index dc7b859e8bbfd..1b8f0d7f84552 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -350,6 +350,7 @@ static int dev_map_bpf_prog_run(struct bpf_prog *xdp_prog,
 
 		xdp_convert_frame_to_buff(xdpf, &xdp);
 		xdp.txq = &txq;
+		rxq.mem.type = xdpf->mem_type;
 		xdp.rxq = &rxq;
 
 		act = bpf_prog_run_xdp(xdp_prog, &xdp);
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 608621d7f225c..fe59e3114d828 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -2151,6 +2151,10 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
 			if (!bpf_allow_tail_call_in_subprogs(env))
 				prog->aux->stack_depth = MAX_BPF_STACK;
 			prog->aux->max_pkt_offset = MAX_PACKET_OFF;
+			prog->aux->max_rdonly_access = U32_MAX;
+			prog->aux->max_rdwr_access = U32_MAX;
+			if (prog->type == BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE)
+				prog->aux->max_tp_access = U32_MAX;
 
 			/* mark bpf_tail_call as different opcode to avoid
 			 * conditional branch in the interpreter for every normal
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index 9d4791ee17411..923fec694747b 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -1279,11 +1279,17 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
 	if (prealloc) {
 		if (old_elem) {
 			/* if we're updating the existing element,
-			 * use per-cpu extra elems to avoid freelist_pop/push
+			 * use per-cpu extra elems to avoid freelist_pop/push.
+			 * The caller puts old_elem into the slot once it is
+			 * unlinked. Until then the slot is empty for an NMI
+			 * or a kprobe that updates this map on this cpu.
 			 */
 			pl_new = this_cpu_ptr(htab->extra_elems);
-			l_new = *pl_new;
-			*pl_new = old_elem;
+			l_new = READ_ONCE(*pl_new);
+			do {
+				if (!l_new)
+					return ERR_PTR(-EBUSY);
+			} while (!try_cmpxchg_local(pl_new, &l_new, NULL));
 		} else {
 			struct pcpu_freelist_node *l;
 
@@ -1459,11 +1465,14 @@ static long htab_map_update_elem(struct bpf_map *map, void *key, void *value,
 	if (l_old) {
 		hlist_nulls_del_rcu(&l_old->hash_node);
 
-		/* l_old has already been stashed in htab->extra_elems, cancel
-		 * its reusable special fields before it is available for reuse.
+		/* l_old replaces the extra element that alloc_htab_elem() took,
+		 * cancel its reusable special fields before the next update on
+		 * this cpu reuses it.
 		 */
-		if (htab_is_prealloc(htab))
+		if (htab_is_prealloc(htab)) {
+			WRITE_ONCE(*this_cpu_ptr(htab->extra_elems), l_old);
 			check_and_cancel_fields(htab, l_old);
+		}
 	}
 	htab_unlock_bucket(b, flags);
 	if (l_old && !htab_is_prealloc(htab))
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 439370d73cc5f..648abe1ba63ae 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -1262,18 +1262,21 @@ static void bpf_wq_work(struct work_struct *work)
 
 	BTF_TYPE_EMIT(struct bpf_wq);
 
+	/* keeps the program that callback_fn belongs to */
+	rcu_read_lock_trace();
+
 	callback_fn = READ_ONCE(cb->callback_fn);
 	if (!callback_fn)
-		return;
+		goto out;
 
 	key = map_key_from_value(map, value, &idx);
 
-        rcu_read_lock_trace();
-        migrate_disable();
+	migrate_disable();
 
 	callback_fn((u64)(long)map, (u64)(long)key, (u64)(long)value, 0, 0);
 
 	migrate_enable();
+out:
 	rcu_read_unlock_trace();
 }
 
diff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c
index 5ee8aae7435ba..0fa3f2ac0f992 100644
--- a/kernel/bpf/map_in_map.c
+++ b/kernel/bpf/map_in_map.c
@@ -110,10 +110,13 @@ void *bpf_map_fd_get_ptr(struct bpf_map *map,
 		return ERR_PTR(-ENOTSUPP);
 
 	inner_map_meta = map->inner_map_meta;
-	if (inner_map_meta->ops->map_meta_equal(inner_map_meta, inner_map))
+	if (inner_map_meta->ops->map_meta_equal(inner_map_meta, inner_map)) {
 		bpf_map_inc(inner_map);
-	else
+		/* Its users are those of the outer maps from now on */
+		WRITE_ONCE(inner_map->was_inner_map, true);
+	} else {
 		inner_map = ERR_PTR(-EINVAL);
+	}
 
 	return inner_map;
 }
diff --git a/kernel/bpf/map_iter.c b/kernel/bpf/map_iter.c
index 2077d46d167c7..a58c148692e6c 100644
--- a/kernel/bpf/map_iter.c
+++ b/kernel/bpf/map_iter.c
@@ -97,13 +97,57 @@ static struct bpf_iter_reg bpf_map_reg_info = {
 	.seq_info		= &bpf_map_seq_info,
 };
 
+/*
+ * For an iterator that hands the live map value to the program as a writable
+ * buffer: the verifier knows nothing of the map, so the special fields of the
+ * value have to lie outside of what the program may write.
+ */
+int bpf_iter_map_check_value_write(const struct bpf_prog *prog,
+				   const struct bpf_map *map)
+{
+	const struct btf_record *rec = map->record;
+	const struct btf_field *field;
+	u32 i;
+
+	if (IS_ERR_OR_NULL(rec) || !prog->aux->max_rdwr_write)
+		return 0;
+
+	for (i = 0; i < rec->cnt; i++) {
+		field = &rec->fields[i];
+		if (field->offset < prog->aux->max_rdwr_write &&
+		    field->offset + field->size > prog->aux->min_rdwr_write)
+			return -EACCES;
+	}
+
+	return 0;
+}
+
+static int bpf_iter_map_check_prog(const struct bpf_prog *prog,
+				   const struct bpf_iter_aux_info *aux)
+{
+	const struct bpf_map *map = aux->map;
+	u32 value_size = map->value_size;
+	bool is_percpu;
+
+	is_percpu = map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
+		    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
+		    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
+	if (is_percpu)
+		value_size = round_up(value_size, 8) * num_possible_cpus();
+
+	if (prog->aux->max_rdonly_access > map->key_size ||
+	    prog->aux->max_rdwr_access > value_size)
+		return -EACCES;
+
+	/* the program gets a copy of a per-cpu value */
+	return is_percpu ? 0 : bpf_iter_map_check_value_write(prog, map);
+}
+
 static int bpf_iter_attach_map(struct bpf_prog *prog,
 			       union bpf_iter_link_info *linfo,
 			       struct bpf_iter_aux_info *aux)
 {
-	u32 key_acc_size, value_acc_size, key_size, value_size;
 	struct bpf_map *map;
-	bool is_percpu = false;
 	int err = -EINVAL;
 
 	if (!linfo->map.map_fd)
@@ -123,30 +167,20 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,
 		goto put_map;
 	}
 
-	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
-	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
-	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
-		is_percpu = true;
-	else if (map->map_type != BPF_MAP_TYPE_HASH &&
-		 map->map_type != BPF_MAP_TYPE_LRU_HASH &&
-		 map->map_type != BPF_MAP_TYPE_ARRAY &&
-		 map->map_type != BPF_MAP_TYPE_RHASH)
+	if (map->map_type != BPF_MAP_TYPE_PERCPU_HASH &&
+	    map->map_type != BPF_MAP_TYPE_LRU_PERCPU_HASH &&
+	    map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY &&
+	    map->map_type != BPF_MAP_TYPE_HASH &&
+	    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
+	    map->map_type != BPF_MAP_TYPE_ARRAY &&
+	    map->map_type != BPF_MAP_TYPE_RHASH)
 		goto put_map;
 
-	key_acc_size = prog->aux->max_rdonly_access;
-	value_acc_size = prog->aux->max_rdwr_access;
-	key_size = map->key_size;
-	if (!is_percpu)
-		value_size = map->value_size;
-	else
-		value_size = round_up(map->value_size, 8) * num_possible_cpus();
-
-	if (key_acc_size > key_size || value_acc_size > value_size) {
-		err = -EACCES;
+	aux->map = map;
+	err = bpf_iter_map_check_prog(prog, aux);
+	if (err)
 		goto put_map;
-	}
 
-	aux->map = map;
 	return 0;
 
 put_map:
@@ -179,6 +213,7 @@ static const struct bpf_iter_reg bpf_map_elem_reg_info = {
 	.target			= "bpf_map_elem",
 	.attach_target		= bpf_iter_attach_map,
 	.detach_target		= bpf_iter_detach_map,
+	.check_prog		= bpf_iter_map_check_prog,
 	.show_fdinfo		= bpf_iter_map_show_fdinfo,
 	.fill_link_info		= bpf_iter_map_fill_link_info,
 	.ctx_arg_info_size	= 2,
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
index d855399812eec..c615ed46f6293 100644
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@ -250,7 +250,14 @@ int bpf_prog_dev_bound_init(struct bpf_prog *prog, union bpf_attr *attr)
 	prog->aux->offload_requested = !(attr->prog_flags & BPF_F_XDP_DEV_BOUND_ONLY);
 
 	down_write(&bpf_devs_lock);
-	err = __bpf_prog_dev_bound_init(prog, netdev);
+	/*
+	 * Behind bpf_dev_bound_netdev_unregister() nobody would take the
+	 * program off the device, which goes once the reference is dropped.
+	 */
+	if (READ_ONCE(netdev->reg_state) == NETREG_REGISTERED)
+		err = __bpf_prog_dev_bound_init(prog, netdev);
+	else
+		err = -EINVAL;
 	up_write(&bpf_devs_lock);
 
 out:
diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 953700822fa73..b3d250caaaa65 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -995,6 +995,9 @@ static bool func_states_equal(struct bpf_verifier_env *env, struct bpf_func_stat
 	if (!old->no_stack_arg_load && cur->no_stack_arg_load)
 		return false;
 
+	if (old->in_rcu_callback_fn != cur->in_rcu_callback_fn)
+		return false;
+
 	for (i = 0; i < MAX_BPF_REG; i++)
 		if (((1 << i) & live_regs) &&
 		    !regsafe(env, &old->regs[i], &cur->regs[i],
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 654f896af265b..c8bd92c95ac02 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2461,6 +2461,8 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu)
 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
 
 	btf_put(aux->btf);
+	kvfree(aux->jited_linfo);
+	kvfree(aux->linfo);
 	kvfree(aux->func_info);
 	kfree(aux->func_info_aux);
 	free_uid(aux->user);
@@ -2477,7 +2479,7 @@ static void __bpf_prog_put_rcu_tasks(struct rcu_head *rcu)
 {
 	struct bpf_prog *prog = container_of(rcu, struct bpf_prog_aux, rcu)->prog;
 
-	if (prog->sleepable)
+	if (bpf_prog_runs_sleepable(prog))
 		call_rcu_tasks_trace(rcu, __bpf_prog_put_rcu);
 	else
 		call_rcu(rcu, __bpf_prog_put_rcu);
@@ -2485,10 +2487,7 @@ static void __bpf_prog_put_rcu_tasks(struct rcu_head *rcu)
 
 static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
 {
-	bpf_prog_kallsyms_del_all(prog);
 	module_put(prog->aux->mod);
-	kvfree(prog->aux->jited_linfo);
-	kvfree(prog->aux->linfo);
 	kfree(prog->aux->kfunc_tab);
 	kfree(prog->aux->ctx_arg_info);
 	if (prog->aux->attach_btf)
@@ -2497,7 +2496,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
 	if (deferred) {
 		if (IS_ENABLED(CONFIG_TASKS_RCU) && prog->aux->tramp_linked)
 			call_rcu_tasks(&prog->aux->rcu, __bpf_prog_put_rcu_tasks);
-		else if (prog->sleepable)
+		else if (bpf_prog_runs_sleepable(prog))
 			call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu);
 		else
 			call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
@@ -4020,19 +4019,19 @@ static int bpf_perf_link_fill_common(const struct perf_event *event,
 		*ulenp = 1;
 	}
 	if (!uname)
-		return 0;
+		goto out;
 
 	if (buf) {
 		err = bpf_copy_to_user(uname, buf, ulen, len);
-		if (err)
-			return err;
 	} else {
 		char zero = '\0';
 
 		if (put_user(zero, uname))
-			return -EFAULT;
+			err = -EFAULT;
 	}
-	return 0;
+out:
+	kfree_const(buf);
+	return err;
 }
 
 #ifdef CONFIG_KPROBE_EVENTS
@@ -4089,6 +4088,7 @@ static void bpf_perf_link_fdinfo_kprobe(const struct perf_event *event,
 		   name, offset, missed, addr,
 		   type == BPF_FD_TYPE_KRETPROBE ?  "kretprobe" : "kprobe",
 		   event->bpf_cookie);
+	kfree_const(name);
 }
 #endif
 
@@ -4142,6 +4142,7 @@ static void bpf_perf_link_fdinfo_uprobe(const struct perf_event *event,
 		   name, offset, ref_ctr_offset,
 		   type == BPF_FD_TYPE_URETPROBE ?  "uretprobe" : "uprobe",
 		   event->bpf_cookie);
+	kfree_const(name);
 }
 #endif
 
@@ -4240,6 +4241,7 @@ static void bpf_tracepoint_link_show_fdinfo(const struct perf_event *event,
 		   "event_type:\t%s\n"
 		   "cookie:\t%llu\n",
 		   name, "tracepoint", event->bpf_cookie);
+	kfree_const(name);
 }
 
 static void bpf_probe_link_show_fdinfo(const struct perf_event *event,
@@ -5763,11 +5765,13 @@ static int bpf_task_fd_query(const union bpf_attr *attr,
 		err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
 					      &buf, &probe_offset,
 					      &probe_addr, NULL);
-		if (!err)
+		if (!err) {
 			err = bpf_task_fd_query_copy(attr, uattr, prog_id,
 						     fd_type, buf,
 						     probe_offset,
 						     probe_addr);
+			kfree_const(buf);
+		}
 		goto put_file;
 	}
 
@@ -6248,7 +6252,7 @@ static int bpf_prog_bind_map(union bpf_attr *attr)
 	/* The bpf program will not access the bpf map, but for the sake of
 	 * simplicity, increase sleepable_refcnt for sleepable program as well.
 	 */
-	if (prog->sleepable)
+	if (bpf_prog_runs_sleepable(prog))
 		atomic64_inc(&map->sleepable_refcnt);
 	memcpy(used_maps_new, used_maps_old,
 	       sizeof(used_maps_old[0]) * prog->aux->used_map_cnt);
diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
index 13e1aabe6f886..2fa6b8dae8c4f 100644
--- a/kernel/bpf/task_iter.c
+++ b/kernel/bpf/task_iter.c
@@ -737,7 +737,11 @@ static const struct bpf_iter_seq_info task_vma_seq_info = {
 static struct bpf_iter_reg task_vma_reg_info = {
 	.target			= "task_vma",
 	.attach_target		= bpf_iter_attach_task,
-	.feature		= BPF_ITER_RESCHED,
+	/*
+	 * ->show() runs with the mmap_lock of the iterated mm held, which a
+	 * sleepable program takes again when it faults on user memory.
+	 */
+	.feature		= BPF_ITER_RESCHED | BPF_ITER_NOSLEEP,
 	.ctx_arg_info_size	= 2,
 	.ctx_arg_info		= {
 		{ offsetof(struct bpf_iter__task_vma, task),
@@ -806,8 +810,14 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
 	vma = find_vma(mm, start);
 
 	if (vma && vma->vm_start <= start && vma->vm_end > start) {
+		/*
+		 * The callback must not sleep while mmap_lock is held, and the
+		 * verifier checks it as an RCU read-side critical section.
+		 */
+		rcu_read_lock();
 		callback_fn((u64)(long)task, (u64)(long)vma,
 			    (u64)(long)callback_ctx, 0, 0);
+		rcu_read_unlock();
 		ret = 0;
 	}
 	bpf_mmap_unlock_mm(work, mm);
diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c
index e85a179523f02..19660ef95ddbd 100644
--- a/kernel/bpf/token.c
+++ b/kernel/bpf/token.c
@@ -169,8 +169,11 @@ int bpf_token_create(union bpf_attr *attr)
 	FD_PREPARE(fdf, O_CLOEXEC,
 		   alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME,
 				     O_RDWR, &bpf_token_fops));
-	if (fdf.err)
+	if (fdf.err) {
+		/* no file took over the inode reference */
+		iput(inode);
 		return fdf.err;
+	}
 
 	token = kzalloc_obj(*token, GFP_USER);
 	if (!token)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index ddfa0c6d2755f..1cf7f2e57a161 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -219,6 +219,7 @@ static int ref_set_non_owning(struct bpf_verifier_env *env,
 			      struct bpf_reg_state *reg);
 static bool is_trusted_reg(struct bpf_verifier_env *env, const struct bpf_reg_state *reg);
 static inline bool in_sleepable_context(struct bpf_verifier_env *env);
+static bool in_rcu_callback(struct bpf_verifier_env *env);
 static const char *non_sleepable_context_description(struct bpf_verifier_env *env);
 static void scalar32_min_max_add(struct bpf_reg_state *dst_reg, struct bpf_reg_state *src_reg);
 static void scalar_min_max_add(struct bpf_reg_state *dst_reg, struct bpf_reg_state *src_reg);
@@ -593,6 +594,19 @@ static bool is_async_cb_sleepable(struct bpf_verifier_env *env, struct bpf_insn
 	return false;
 }
 
+/* From here on the maps of the program count it as a sleepable user. */
+static void mark_sleepable_async_cb(struct bpf_verifier_env *env)
+{
+	int i;
+
+	if (bpf_prog_runs_sleepable(env->prog))
+		return;
+
+	env->prog->aux->sleepable_async_cb = true;
+	for (i = 0; i < env->used_map_cnt; i++)
+		atomic64_inc(&env->used_maps[i]->sleepable_refcnt);
+}
+
 bool bpf_is_may_goto_insn(struct bpf_insn *insn)
 {
 	return insn->code == (BPF_JMP | BPF_JCOND) && insn->src_reg == BPF_MAY_GOTO;
@@ -988,6 +1002,11 @@ static enum bpf_dynptr_type dynptr_reg_type(struct bpf_verifier_env *env, struct
 	return bpf_stack_slot(state, spi)->spilled_ptr.dynptr.type;
 }
 
+static bool dynptr_write_changes_pkt_data(enum bpf_dynptr_type type)
+{
+	return type == BPF_DYNPTR_TYPE_SKB || type == BPF_DYNPTR_TYPE_SKB_META;
+}
+
 static bool is_dynptr_type_expected(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
 				    enum bpf_arg_type arg_type)
 {
@@ -6039,9 +6058,10 @@ static int check_buffer_access(struct bpf_verifier_env *env,
 			       const struct bpf_reg_state *reg,
 			       argno_t argno, int off, int size,
 			       bool zero_size_allowed,
-			       u32 *max_access)
+			       u32 *max_access, bool write)
 {
 	const char *buf_info = type_is_rdonly_mem(reg->type) ? "rdonly" : "rdwr";
+	struct bpf_prog_aux *aux = env->prog->aux;
 	u32 access_end;
 	int err;
 
@@ -6050,6 +6070,11 @@ static int check_buffer_access(struct bpf_verifier_env *env,
 		return err;
 
 	*max_access = max(access_end, *max_access);
+	if (write && size) {
+		if (!aux->max_rdwr_write || access_end - size < aux->min_rdwr_write)
+			aux->min_rdwr_write = access_end - size;
+		aux->max_rdwr_write = max(access_end, aux->max_rdwr_write);
+	}
 
 	return 0;
 }
@@ -7325,7 +7350,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
 		}
 
 		err = check_buffer_access(env, reg, argno, off, size, false,
-					  max_access);
+					  max_access, t == BPF_WRITE);
 
 		if (!err && value_regno >= 0 && (rdonly_mem || t == BPF_READ))
 			mark_reg_unknown(env, regs, value_regno);
@@ -7838,7 +7863,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, struct bpf_reg_
 		}
 		return check_buffer_access(env, reg, argno, 0,
 					   access_size, zero_size_allowed,
-					   max_access);
+					   max_access, access_type == BPF_WRITE);
 	case PTR_TO_STACK:
 		return check_stack_range_initialized(
 				env, reg,
@@ -8391,6 +8416,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
 			       argno_t argno, int insn_idx, enum bpf_arg_type arg_type,
 			       struct bpf_call_arg_meta *meta)
 {
+	bool is_arg = reg->type == CONST_PTR_TO_DYNPTR;
 	int spi, err = 0;
 
 	/*  MEM_UNINIT - Points to memory that is an appropriate candidate for
@@ -8477,7 +8503,12 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
 			reg = &bpf_stack_slot(state, spi)->spilled_ptr;
 		}
 
-		meta->dynptr.type = reg->dynptr.type;
+		/*
+		 * The callers of a global function may hand in a dynptr of any
+		 * type. Take it for that of an skb, so that a write through it
+		 * and its slices are treated with care.
+		 */
+		meta->dynptr.type = is_arg ? BPF_DYNPTR_TYPE_SKB : reg->dynptr.type;
 		meta->dynptr.id = reg->id;
 		meta->dynptr.parent_id = reg->parent_id;
 	}
@@ -8956,6 +8987,7 @@ static bool is_kfunc_arg_scalar_with_name(const struct btf *btf,
 static bool is_bpf_cast_to_kern_ctx_kfunc(const struct bpf_call_arg_meta *meta);
 static bool is_bpf_dynptr_clone_kfunc(const struct bpf_call_arg_meta *meta);
 static bool is_bpf_iter_css_task_new_kfunc(const struct bpf_call_arg_meta *meta);
+static bool is_kfunc_dynptr_write(struct bpf_call_arg_meta *meta);
 static bool is_bpf_obj_drop_kfunc(u32 func_id);
 static bool is_bpf_percpu_obj_drop_kfunc(u32 func_id);
 static bool is_bpf_rbtree_add_kfunc(u32 func_id);
@@ -9661,6 +9693,16 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p
 	if (err)
 		return err;
 
+	/*
+	 * A slice of a packet is packet data under another name. A helper which
+	 * may reallocate the packet must not go on reading from the old one.
+	 */
+	if (is_helper(meta) && reg_is_dynptr_slice_pkt(reg) &&
+	    bpf_helper_changes_pkt_data(meta->func_id)) {
+		verbose(env, "function access to the packet is not allowed\n");
+		return -EACCES;
+	}
+
 	if (arg_type_is_raw_mem(arg_type))
 		meta->arg_raw_mem.mask |= BIT(slot);
 
@@ -10020,6 +10062,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p
 		err = process_dynptr_func(env, reg, argno, insn_idx, arg_type, meta);
 		if (err)
 			return err;
+		if (!arg && is_kfunc_dynptr_write(meta))
+			meta->dynptr_write_type = meta->dynptr.type;
 		break;
 	}
 	case ARG_PTR_TO_ITER:
@@ -10366,12 +10410,57 @@ bool bpf_allow_tail_call_in_subprogs(struct bpf_verifier_env *env)
 	       bpf_jit_supports_subprog_tailcalls();
 }
 
+/* May the map be used outside of an RCU read side critical section? */
+static bool map_needs_no_rcu(const struct bpf_map *map)
+{
+	switch (map->map_type) {
+	case BPF_MAP_TYPE_HASH:
+	case BPF_MAP_TYPE_RHASH:
+	case BPF_MAP_TYPE_LRU_HASH:
+	case BPF_MAP_TYPE_ARRAY:
+	case BPF_MAP_TYPE_PERCPU_HASH:
+	case BPF_MAP_TYPE_PERCPU_ARRAY:
+	case BPF_MAP_TYPE_LRU_PERCPU_HASH:
+	case BPF_MAP_TYPE_LPM_TRIE:
+	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
+	case BPF_MAP_TYPE_HASH_OF_MAPS:
+	case BPF_MAP_TYPE_RINGBUF:
+	case BPF_MAP_TYPE_USER_RINGBUF:
+	case BPF_MAP_TYPE_INODE_STORAGE:
+	case BPF_MAP_TYPE_SK_STORAGE:
+	case BPF_MAP_TYPE_TASK_STORAGE:
+	case BPF_MAP_TYPE_CGRP_STORAGE:
+	case BPF_MAP_TYPE_QUEUE:
+	case BPF_MAP_TYPE_STACK:
+	case BPF_MAP_TYPE_ARENA:
+	case BPF_MAP_TYPE_INSN_ARRAY:
+	case BPF_MAP_TYPE_PROG_ARRAY:
+	case BPF_MAP_TYPE_BLOOM_FILTER:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static int check_map_func_compatibility(struct bpf_verifier_env *env,
 					struct bpf_map *map, int func_id)
 {
 	if (!map)
 		return 0;
 
+	/*
+	 * check_map_prog_compatibility() asks the program.  That misses the
+	 * sleepable callback of another program, and an inner map.  They may
+	 * use any map under the RCU read lock.  Disabled preemption or
+	 * interrupts will not do: the maps ask for rcu_read_lock_held().
+	 */
+	if (in_sleepable(env) && !env->cur_state->active_rcu_locks &&
+	    !in_rcu_callback(env) && !map_needs_no_rcu(map)) {
+		verbose(env, "map '%s' needs bpf_rcu_read_lock() in sleepable context\n",
+			map->name);
+		return -EINVAL;
+	}
+
 	/* We need a two way check, first is from map perspective ... */
 	switch (map->map_type) {
 	case BPF_MAP_TYPE_PROG_ARRAY:
@@ -11211,6 +11300,8 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins
 					 is_async_cb_sleepable(env, insn));
 		if (IS_ERR(async_cb))
 			return PTR_ERR(async_cb);
+		if (is_async_cb_sleepable(env, insn))
+			mark_sleepable_async_cb(env);
 		callee = async_cb->frame[0];
 		callee->async_entry_cnt = state->frame[0]->async_entry_cnt + 1;
 
@@ -11530,6 +11621,19 @@ static int set_map_elem_callback_state(struct bpf_verifier_env *env,
 	if (err)
 		return err;
 
+	switch (map->map_type) {
+	case BPF_MAP_TYPE_HASH:
+	case BPF_MAP_TYPE_PERCPU_HASH:
+	case BPF_MAP_TYPE_LRU_HASH:
+	case BPF_MAP_TYPE_LRU_PERCPU_HASH:
+	case BPF_MAP_TYPE_RHASH:
+		/* Hash tables run the callback under rcu_read_lock(). */
+		callee->in_rcu_callback_fn = true;
+		break;
+	default:
+		break;
+	}
+
 	callee->in_callback_fn = true;
 	callee->callback_ret_range = retval_range(0, 1);
 	return 0;
@@ -11616,6 +11720,8 @@ static int set_find_vma_callback_state(struct bpf_verifier_env *env,
 	bpf_mark_reg_not_init(env, &callee->regs[BPF_REG_4]);
 	bpf_mark_reg_not_init(env, &callee->regs[BPF_REG_5]);
 	callee->in_callback_fn = true;
+	/* bpf_find_vma() runs the callback under mmap_lock and RCU. */
+	callee->in_rcu_callback_fn = true;
 	callee->callback_ret_range = retval_range(0, 1);
 	return 0;
 }
@@ -12273,10 +12379,22 @@ int bpf_get_helper_proto(struct bpf_verifier_env *env, int func_id,
 	return *ptr && (*ptr)->func ? 0 : -EINVAL;
 }
 
+/* Is any frame on the current path a callback that runs under RCU? */
+static bool in_rcu_callback(struct bpf_verifier_env *env)
+{
+	struct bpf_verifier_state *state = env->cur_state;
+	int i;
+
+	for (i = 0; i <= state->curframe; i++)
+		if (state->frame[i]->in_rcu_callback_fn)
+			return true;
+	return false;
+}
+
 /* Check if we're in a sleepable context. */
 static inline bool in_sleepable_context(struct bpf_verifier_env *env)
 {
-	return !in_rcu_cs(env);
+	return !in_rcu_cs(env) && !in_rcu_callback(env);
 }
 
 static const char *non_sleepable_context_description(struct bpf_verifier_env *env)
@@ -12290,6 +12408,7 @@ static const char *non_sleepable_context_description(struct bpf_verifier_env *en
 			return "IRQ-disabled region";
 		if (env->cur_state->active_locks)
 			return "lock region";
+		return "callback running under rcu_read_lock";
 	}
 	return "non-sleepable prog";
 }
@@ -12540,8 +12659,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 		if (dynptr_type == BPF_DYNPTR_TYPE_INVALID)
 			return -EFAULT;
 
-		if (dynptr_type == BPF_DYNPTR_TYPE_SKB ||
-		    dynptr_type == BPF_DYNPTR_TYPE_SKB_META)
+		if (dynptr_write_changes_pkt_data(dynptr_type))
 			/* this will trigger clear_all_pkt_pointers(), which will
 			 * invalidate all dynptr slices associated with the skb
 			 */
@@ -13590,9 +13708,36 @@ static bool is_kfunc_bpf_preempt_enable(struct bpf_call_arg_meta *meta)
 	return is_kfunc_call(meta, special_kfunc_list[KF_bpf_preempt_enable]);
 }
 
+/* These write to what their first argument, a dynptr, points to */
+BTF_SET_START(dynptr_write_kfuncs)
+BTF_ID(func, bpf_dynptr_copy)
+BTF_ID(func, bpf_dynptr_memset)
+#ifdef CONFIG_BPF_EVENTS
+BTF_ID(func, bpf_probe_read_user_dynptr)
+BTF_ID(func, bpf_probe_read_kernel_dynptr)
+BTF_ID(func, bpf_probe_read_user_str_dynptr)
+BTF_ID(func, bpf_probe_read_kernel_str_dynptr)
+BTF_ID(func, bpf_copy_from_user_dynptr)
+BTF_ID(func, bpf_copy_from_user_str_dynptr)
+BTF_ID(func, bpf_copy_from_user_task_dynptr)
+BTF_ID(func, bpf_copy_from_user_task_str_dynptr)
+#endif
+BTF_SET_END(dynptr_write_kfuncs)
+
+static bool is_kfunc_dynptr_write(struct bpf_call_arg_meta *meta)
+{
+	return meta->btf == btf_vmlinux &&
+	       btf_id_set_contains(&dynptr_write_kfuncs, meta->func_id);
+}
+
+/*
+ * A write through the dynptr of an skb may reallocate its head. Before the
+ * arguments are checked nobody knows what kind of dynptr it is.
+ */
 bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta)
 {
-	return is_kfunc_call(meta, special_kfunc_list[KF_bpf_xdp_pull_data]);
+	return is_kfunc_call(meta, special_kfunc_list[KF_bpf_xdp_pull_data]) ||
+	       is_kfunc_dynptr_write(meta);
 }
 
 static u32 kfunc_abi_slots(const struct btf_func_model *fm)
@@ -15530,7 +15675,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 		}
 	}
 
-	if (bpf_is_kfunc_pkt_changing(&meta))
+	if (is_kfunc_dynptr_write(&meta) ?
+	    dynptr_write_changes_pkt_data(meta.dynptr_write_type) :
+	    bpf_is_kfunc_pkt_changing(&meta))
 		clear_all_pkt_pointers(env);
 
 	proto_slots = kfunc_abi_slots(&desc->func_model);
@@ -18117,7 +18264,7 @@ static void regs_refine_cond_op(struct bpf_reg_state *reg1, struct bpf_reg_state
 		 * this restriction. I.e., !(r1 & 0x3) means neither bit 0 nor
 		 * bit 1 is set, which we can readily use in adjustments.
 		 */
-		if (!is_power_of_2(val))
+		if (hweight64(val) != 1)
 			break;
 		if (is_jmp32) {
 			t = tnum_or(tnum_subreg(reg1->var_off), tnum_const(val));
@@ -20633,35 +20780,11 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
 		return -EINVAL;
 	}
 
-	if (prog->sleepable)
-		switch (map->map_type) {
-		case BPF_MAP_TYPE_HASH:
-		case BPF_MAP_TYPE_RHASH:
-		case BPF_MAP_TYPE_LRU_HASH:
-		case BPF_MAP_TYPE_ARRAY:
-		case BPF_MAP_TYPE_PERCPU_HASH:
-		case BPF_MAP_TYPE_PERCPU_ARRAY:
-		case BPF_MAP_TYPE_LRU_PERCPU_HASH:
-		case BPF_MAP_TYPE_LPM_TRIE:
-		case BPF_MAP_TYPE_ARRAY_OF_MAPS:
-		case BPF_MAP_TYPE_HASH_OF_MAPS:
-		case BPF_MAP_TYPE_RINGBUF:
-		case BPF_MAP_TYPE_USER_RINGBUF:
-		case BPF_MAP_TYPE_INODE_STORAGE:
-		case BPF_MAP_TYPE_SK_STORAGE:
-		case BPF_MAP_TYPE_TASK_STORAGE:
-		case BPF_MAP_TYPE_CGRP_STORAGE:
-		case BPF_MAP_TYPE_QUEUE:
-		case BPF_MAP_TYPE_STACK:
-		case BPF_MAP_TYPE_ARENA:
-		case BPF_MAP_TYPE_INSN_ARRAY:
-		case BPF_MAP_TYPE_PROG_ARRAY:
-			break;
-		default:
-			verbose(env,
-				"Sleepable programs can only use array, hash, ringbuf and local storage maps\n");
-			return -EINVAL;
-		}
+	if (prog->sleepable && !map_needs_no_rcu(map)) {
+		verbose(env,
+			"Sleepable programs can only use array, hash, ringbuf and local storage maps\n");
+		return -EINVAL;
+	}
 
 	if (bpf_map_is_cgroup_storage(map) &&
 	    bpf_cgroup_storage_assign(env->prog->aux, map)) {
@@ -20746,7 +20869,7 @@ static int __add_used_map(struct bpf_verifier_env *env, struct bpf_map *map)
 	if (err)
 		return err;
 
-	if (env->prog->sleepable)
+	if (bpf_prog_runs_sleepable(env->prog))
 		atomic64_inc(&map->sleepable_refcnt);
 
 	/* hold the map. If the program is rejected by verifier,
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 5465e7eba2384..304b426bd44d4 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2209,6 +2209,7 @@ int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_raw_tp_link *
 	return tracepoint_probe_unregister(btp->tp, (void *)btp->bpf_func, link);
 }
 
+/* On success the caller releases *buf with kfree_const() */
 int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
 			    u32 *fd_type, const char **buf,
 			    u64 *probe_offset, u64 *probe_addr,
@@ -2218,6 +2219,12 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
 	struct bpf_prog *prog;
 	int flags, err = 0;
 
+	/*
+	 * The list of dynamic events is walked, and a probe which has siblings
+	 * can be deleted, with its strings, while its event is in use.
+	 */
+	guard(mutex)(&event_mutex);
+
 	prog = event->prog;
 	if (!prog)
 		return -ENOENT;
@@ -2258,6 +2265,12 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
 #endif
 	}
 
+	if (!err && *buf) {
+		*buf = kstrdup_const(*buf, GFP_KERNEL);
+		if (!*buf)
+			err = -ENOMEM;
+	}
+
 	return err;
 }
 
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index d73cd247f8cd0..3043a7393c29c 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -1656,20 +1656,19 @@ int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kat
 		ctx.selected_sk = NULL;
 		retval = BPF_PROG_SK_LOOKUP_RUN_ARRAY(progs, ctx, bpf_prog_run);
 	} while (bpf_test_timer_continue(&t, 1, repeat, &ret, &duration));
-	bpf_test_timer_leave(&t);
-
-	if (ret < 0)
-		goto out;
 
+	/* Nothing but RCU keeps the selected socket */
 	user_ctx->cookie = 0;
-	if (ctx.selected_sk) {
-		if (ctx.selected_sk->sk_reuseport && !ctx.no_reuseport) {
+	if (!ret && ctx.selected_sk) {
+		if (ctx.selected_sk->sk_reuseport && !ctx.no_reuseport)
 			ret = -EOPNOTSUPP;
-			goto out;
-		}
-
-		user_ctx->cookie = sock_gen_cookie(ctx.selected_sk);
+		else
+			user_ctx->cookie = sock_gen_cookie(ctx.selected_sk);
 	}
+	bpf_test_timer_leave(&t);
+
+	if (ret < 0)
+		goto out;
 
 	ret = bpf_test_finish(kattr, uattr, NULL, NULL, 0, 0, retval, duration);
 	if (!ret)
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 1d295a8769fad..1c59300af05c7 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -164,6 +164,13 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
 	if (!sk_storage || hlist_empty(&sk_storage->list))
 		goto out;
 
+	/*
+	 * The maps lead to newsk as soon as an element is linked, but
+	 * sk_clone() sets sk_refcnt only later.  Until then it holds whatever
+	 * the slab object held before: no reference can be had yet.
+	 */
+	refcount_set(&newsk->sk_refcnt, 0);
+
 	hlist_for_each_entry_rcu(selem, &sk_storage->list, snode) {
 		struct bpf_local_storage_elem *copy_selem;
 		struct bpf_local_storage_map *smap;
@@ -692,8 +699,37 @@ struct bpf_iter_seq_sk_storage_map_info {
 	struct bpf_map *map;
 	unsigned int bucket_id;
 	unsigned skip_elems;
+	struct rcu_head *dead_sks;
 };
 
+/*
+ * sock_put() in two halves. The end of a socket may want process context:
+ * rfcomm_sock_destruct() takes a mutex. If the iterator drops the last
+ * reference, it keeps the socket until it has left the RCU read side critical
+ * section. Nobody uses sk_rcu before sk_destruct().
+ */
+static void
+bpf_sk_storage_map_seq_put_sk(struct bpf_iter_seq_sk_storage_map_info *info,
+			      struct sock *sk)
+{
+	if (refcount_dec_and_test(&sk->sk_refcnt)) {
+		sk->sk_rcu.next = info->dead_sks;
+		info->dead_sks = &sk->sk_rcu;
+	}
+}
+
+static void
+bpf_sk_storage_map_seq_free_sks(struct bpf_iter_seq_sk_storage_map_info *info)
+{
+	struct sock *sk;
+
+	while (info->dead_sks) {
+		sk = container_of(info->dead_sks, struct sock, sk_rcu);
+		info->dead_sks = sk->sk_rcu.next;
+		sk_free(sk);
+	}
+}
+
 static struct bpf_local_storage_elem *
 bpf_sk_storage_map_seq_find_next(struct bpf_iter_seq_sk_storage_map_info *info,
 				 struct bpf_local_storage_elem *prev_selem)
@@ -722,6 +758,7 @@ bpf_sk_storage_map_seq_find_next(struct bpf_iter_seq_sk_storage_map_info *info,
 			/* not found, unlock and go to the next bucket */
 			b = &smap->buckets[bucket_id++];
 			rcu_read_unlock();
+			bpf_sk_storage_map_seq_free_sks(info);
 			skip_elems = 0;
 			break;
 		}
@@ -789,12 +826,44 @@ DEFINE_BPF_ITER_FUNC(bpf_sk_storage_map, struct bpf_iter_meta *meta,
 		     struct bpf_map *map, struct sock *sk,
 		     void *value)
 
+/*
+ * Take a reference on the socket which owns @selem. RCU keeps the element, not
+ * its owner. As long as the element is linked under the lock of the storage,
+ * the owner has not got past bpf_sk_storage_free(), unless that has given up
+ * on the lock. Then it still waits for owner_refcnt.
+ */
+static struct sock *
+bpf_sk_storage_selem_get_sk(struct bpf_local_storage_elem *selem)
+{
+	struct bpf_local_storage *sk_storage;
+	struct sock *sk = NULL;
+	unsigned long flags;
+
+	sk_storage = rcu_dereference(selem->local_storage);
+	/* reset since ->next() looked: the socket goes away */
+	if (!sk_storage)
+		return NULL;
+
+	if (raw_res_spin_lock_irqsave(&sk_storage->lock, flags))
+		return NULL;
+
+	if (!hlist_unhashed(&selem->snode) &&
+	    refcount_inc_not_zero(&sk_storage->owner_refcnt)) {
+		sk = sk_storage->owner;
+		if (!refcount_inc_not_zero(&sk->sk_refcnt))
+			sk = NULL;
+		bpf_local_storage_unpin_owner(sk_storage);
+	}
+	raw_res_spin_unlock_irqrestore(&sk_storage->lock, flags);
+
+	return sk;
+}
+
 static int __bpf_sk_storage_map_seq_show(struct seq_file *seq,
 					 struct bpf_local_storage_elem *selem)
 {
 	struct bpf_iter_seq_sk_storage_map_info *info = seq->private;
 	struct bpf_iter__bpf_sk_storage_map ctx = {};
-	struct bpf_local_storage *sk_storage;
 	struct bpf_iter_meta meta;
 	struct bpf_prog *prog;
 	int ret = 0;
@@ -805,11 +874,14 @@ static int __bpf_sk_storage_map_seq_show(struct seq_file *seq,
 		ctx.meta = &meta;
 		ctx.map = info->map;
 		if (selem) {
-			sk_storage = rcu_dereference(selem->local_storage);
-			ctx.sk = sk_storage->owner;
+			ctx.sk = bpf_sk_storage_selem_get_sk(selem);
+			if (!ctx.sk)
+				return SEQ_SKIP;
 			ctx.value = SDATA(selem)->data;
 		}
 		ret = bpf_iter_run_prog(prog, &ctx);
+		if (ctx.sk)
+			bpf_sk_storage_map_seq_put_sk(info, ctx.sk);
 	}
 
 	return ret;
@@ -827,6 +899,7 @@ static void bpf_sk_storage_map_seq_stop(struct seq_file *seq, void *v)
 		(void)__bpf_sk_storage_map_seq_show(seq, v);
 	else
 		rcu_read_unlock();
+	bpf_sk_storage_map_seq_free_sks(seq->private);
 }
 
 static int bpf_iter_init_sk_storage_map(void *priv_data,
@@ -846,6 +919,15 @@ static void bpf_iter_fini_sk_storage_map(void *priv_data)
 	bpf_map_put_with_uref(seq_info->map);
 }
 
+static int bpf_iter_map_check_prog(const struct bpf_prog *prog,
+				   const struct bpf_iter_aux_info *aux)
+{
+	if (prog->aux->max_rdwr_access > aux->map->value_size)
+		return -EACCES;
+
+	return bpf_iter_map_check_value_write(prog, aux->map);
+}
+
 static int bpf_iter_attach_map(struct bpf_prog *prog,
 			       union bpf_iter_link_info *linfo,
 			       struct bpf_iter_aux_info *aux)
@@ -863,12 +945,11 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,
 	if (map->map_type != BPF_MAP_TYPE_SK_STORAGE)
 		goto put_map;
 
-	if (prog->aux->max_rdwr_access > map->value_size) {
-		err = -EACCES;
+	aux->map = map;
+	err = bpf_iter_map_check_prog(prog, aux);
+	if (err)
 		goto put_map;
-	}
 
-	aux->map = map;
 	return 0;
 
 put_map:
@@ -899,6 +980,7 @@ static struct bpf_iter_reg bpf_sk_storage_map_reg_info = {
 	.target			= "bpf_sk_storage_map",
 	.attach_target		= bpf_iter_attach_map,
 	.detach_target		= bpf_iter_detach_map,
+	.check_prog		= bpf_iter_map_check_prog,
 	.show_fdinfo		= bpf_iter_map_show_fdinfo,
 	.fill_link_info		= bpf_iter_map_fill_link_info,
 	.ctx_arg_info_size	= 2,
diff --git a/net/core/filter.c b/net/core/filter.c
index ba536be2915fb..0e3261f8d322c 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1731,7 +1731,8 @@ BPF_CALL_5(bpf_skb_store_bytes, struct sk_buff *, skb, u32, offset,
 	if (flags & BPF_F_RECOMPUTE_CSUM)
 		__skb_postpull_rcsum(skb, ptr, len, offset);
 
-	memcpy(ptr, from, len);
+	/* through a dynptr the source may be an overlapping slice of the skb */
+	memmove(ptr, from, len);
 
 	if (flags & BPF_F_RECOMPUTE_CSUM)
 		__skb_postpush_rcsum(skb, ptr, len, offset);
@@ -1752,9 +1753,32 @@ static const struct bpf_func_proto bpf_skb_store_bytes_proto = {
 	.arg5_type	= ARG_ANYTHING,
 };
 
+/*
+ * The source of a write through a dynptr may be a slice of the same skb.
+ * Making the skb writable can move its head: follow the move.
+ */
+static int bpf_try_make_writable_from(struct sk_buff *skb, u32 write_len,
+				      const void **from)
+{
+	const void *head = skb->head;
+	bool in_head = *from >= head &&
+		       *from < (const void *)skb_end_pointer(skb);
+	int err;
+
+	err = bpf_try_make_writable(skb, write_len);
+	if (!err && in_head)
+		*from = skb->head + (*from - head);
+	return err;
+}
+
 int __bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from,
 			  u32 len, u64 flags)
 {
+	if (unlikely(offset > INT_MAX))
+		return -EFAULT;
+	if (unlikely(bpf_try_make_writable_from(skb, offset + len, &from)))
+		return -EFAULT;
+
 	return ____bpf_skb_store_bytes(skb, offset, from, len, flags);
 }
 
@@ -3612,6 +3636,11 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
 			return -ENOTSUPP;
 	}
 
+	/* The MSS is lowered by len_diff: something has to be left of it. */
+	if (skb_is_gso(skb) && !(flags & BPF_F_ADJ_ROOM_FIXED_GSO) &&
+	    skb_shinfo(skb)->gso_size <= len_diff)
+		return -ENOTSUPP;
+
 	ret = skb_cow_head(skb, meta_len + len_diff);
 	if (unlikely(ret < 0))
 		return ret;
@@ -7017,15 +7046,15 @@ static void bpf_update_srh_state(struct sk_buff *skb)
 {
 	struct seg6_bpf_srh_state *srh_state =
 		this_cpu_ptr(&seg6_bpf_srh_states);
-	int srhoff = 0;
 
-	if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0) {
-		srh_state->srh = NULL;
-	} else {
-		srh_state->srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
+	/* Behind a decapsulation this is a header that nobody has looked at */
+	srh_state->srh = seg6_get_srh(skb, 0);
+	if (srh_state->srh) {
 		srh_state->hdrlen = srh_state->srh->hdrlen << 3;
 		srh_state->valid = true;
 	}
+	/* it may have been pulled into the head */
+	bpf_compute_data_pointers(skb);
 }
 
 BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
@@ -7058,9 +7087,14 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
 
 		if (ipv6_find_hdr(skb, &hdroff, IPPROTO_IPV6, NULL, NULL) < 0)
 			return -EBADMSG;
-		if (!pskb_pull(skb, hdroff))
+		/* As long as nothing has been changed, the program goes on */
+		if (!pskb_may_pull(skb, hdroff + sizeof(struct ipv6hdr))) {
+			/* but the head may have moved */
+			bpf_update_srh_state(skb);
 			return -EBADMSG;
+		}
 
+		__skb_pull(skb, hdroff);
 		skb_postpull_rcsum(skb, skb_network_header(skb), hdroff);
 		skb_reset_network_header(skb);
 		skb_reset_transport_header(skb);
@@ -7074,8 +7108,8 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
 			return -EBADMSG;
 		err = bpf_push_seg6_encap(skb, BPF_LWT_ENCAP_SEG6_INLINE,
 					  param, param_len);
-		if (!err)
-			bpf_update_srh_state(skb);
+		/* The header can be in place although err says otherwise */
+		bpf_update_srh_state(skb);
 
 		return err;
 	case SEG6_LOCAL_ACTION_END_B6_ENCAP:
@@ -7083,8 +7117,8 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
 			return -EBADMSG;
 		err = bpf_push_seg6_encap(skb, BPF_LWT_ENCAP_SEG6,
 					  param, param_len);
-		if (!err)
-			bpf_update_srh_state(skb);
+		/* The header can be in place although err says otherwise */
+		bpf_update_srh_state(skb);
 
 		return err;
 	default:
@@ -12414,7 +12448,7 @@ int __bpf_skb_meta_store_bytes(struct sk_buff *skb, u32 offset,
 {
 	if (unlikely(flags))
 		return -EINVAL;
-	if (unlikely(bpf_try_make_writable(skb, 0)))
+	if (unlikely(bpf_try_make_writable_from(skb, 0, &from)))
 		return -EFAULT;
 
 	memmove(bpf_skb_meta_pointer(skb, offset), from, len);
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index 38df842843289..057e2f3c0265e 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -1933,6 +1933,15 @@ int sock_map_link_create(const union bpf_attr *attr, struct bpf_prog *prog)
 	return ret;
 }
 
+static int sock_map_iter_check_prog(const struct bpf_prog *prog,
+				    const struct bpf_iter_aux_info *aux)
+{
+	if (prog->aux->max_rdonly_access > aux->map->key_size)
+		return -EACCES;
+
+	return 0;
+}
+
 static int sock_map_iter_attach_target(struct bpf_prog *prog,
 				       union bpf_iter_link_info *linfo,
 				       struct bpf_iter_aux_info *aux)
@@ -1951,12 +1960,11 @@ static int sock_map_iter_attach_target(struct bpf_prog *prog,
 	    map->map_type != BPF_MAP_TYPE_SOCKHASH)
 		goto put_map;
 
-	if (prog->aux->max_rdonly_access > map->key_size) {
-		err = -EACCES;
+	aux->map = map;
+	err = sock_map_iter_check_prog(prog, aux);
+	if (err)
 		goto put_map;
-	}
 
-	aux->map = map;
 	return 0;
 
 put_map:
@@ -1973,6 +1981,7 @@ static struct bpf_iter_reg sock_map_iter_reg = {
 	.target			= "sockmap",
 	.attach_target		= sock_map_iter_attach_target,
 	.detach_target		= sock_map_iter_detach_target,
+	.check_prog		= sock_map_iter_check_prog,
 	.show_fdinfo		= bpf_iter_map_show_fdinfo,
 	.fill_link_info		= bpf_iter_map_fill_link_info,
 	.ctx_arg_info_size	= 2,

3/2 2026/10/17 07:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 28957
							output: 42
							thoughts: 1874
						

Thoughts:
**BPF Patch Evaluation for Syzkaller Fuzzing**

Alright, let's dive into this. The task is to determine if this BPF commit or patch series warrants fuzzing with syzkaller. First glance, and the file list screams BPF! We're touching core BPF subsystems. This is significant because BPF is a direct userspace entry point via the `bpf()` syscall and other interfaces. My experience tells me that changes in BPF are prime targets for fuzzing, given that it's listed under "Core Subsystems" that are directly reachable from userspace, so `WorthFuzzing=true!` is the starting point.

Now, let's get granular. I need to understand *what* this patch is doing within the BPF ecosystem. Is it a set of fixes, new features, or maybe a backport? A quick `git log` inspection is the best next step, but it looks like I need to read the files or use grepping to understand what's changed. My tools are: `grepper`, `codesearch-dir-index`, `read-file`, and `set-results`.

I need to understand the modified functions to identify which configurations to enable in the fuzzer. Let's start by inspecting key functions and modules:

I'm checking changes in these files: `kernel/bpf/bpf_iter.c`, `kernel/bpf/bpf_local_storage.c`, `kernel/bpf/btf.c`, `kernel/bpf/core.c`, `kernel/bpf/cpumap.c`, `kernel/bpf/hashtab.c`, `kernel/bpf/helpers.c`, `kernel/bpf/map_in_map.c`, `kernel/bpf/map_iter.c`, `kernel/bpf/offload.c`, `kernel/bpf/states.c`, `kernel/bpf/syscall.c`, `kernel/bpf/task_iter.c`, `kernel/bpf/token.c`, `kernel/bpf/verifier.c`, `kernel/trace/bpf_trace.c`, `net/bpf/test_run.c`, `net/core/bpf_sk_storage.c`, `net/core/filter.c`, `net/core/sock_map.c`.

I'll be looking for any indications of new functionality, bug fixes that might reveal new code paths, or potential security vulnerabilities. I need to pay close attention to the BPF verifier, memory access, and any interactions with networking or socket-related functions.

I also need to check the Kconfig dependencies to understand the configuration space that this patch introduces or modifies. Specifically, `BPF_SYSCALL` is a key configuration.



4/2 2026/10/17 07:02 tool grepper
0m Args:
{
  "Expression": "config BPF_SYSCALL",
  "PathPrefixes": [
    "kernel/bpf/Kconfig",
    "init/Kconfig"
  ]
}

Results:
{
  "Output": "kernel/bpf/Kconfig=29=menu \"BPF subsystem\"\nkernel/bpf/Kconfig-30-\nkernel/bpf/Kconfig:31:config BPF_SYSCALL\nkernel/bpf/Kconfig-32-\tbool \"Enable bpf() system call\"\n"
}

5/2 2026/10/17 07:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 31558
							output: 34
							thoughts: 22
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**BPF_SYSCALL Kconfig Deep Dive**

Alright, let's dive right in. My first thought is to meticulously review the `kernel/bpf/Kconfig` file, specifically the sections related to `BPF_SYSCALL`. I know this is the central configuration option that determines whether the BPF syscall is enabled, and therefore, whether we can even *begin* to leverage the power of eBPF within this kernel build. We need to understand precisely how this option is controlled, its dependencies, and any interactions with other features. I want to look for anything that could influence the availability, behavior, or default state of the BPF syscall. Are there any conditional dependencies? Are there any potential conflicts I need to be aware of? Are there any hidden implications of enabling or disabling this option that could impact performance or security in unforeseen ways? This is the bedrock, the foundation; we need a solid grasp of this config option before we can proceed to more advanced considerations.



6/2 2026/10/17 07:02 tool read-file
0m Args:
{
  "File": "kernel/bpf/Kconfig",
  "FirstLine": 30,
  "LineCount": 60
}

Results:
{
  "Contents": "  30:\t\n  31:\tconfig BPF_SYSCALL\n  32:\t\tbool \"Enable bpf() system call\"\n  33:\t\tselect BPF\n  34:\t\tselect IRQ_WORK\n  35:\t\tselect NEED_TASKS_RCU\n  36:\t\tselect TASKS_TRACE_RCU\n  37:\t\tselect BINARY_PRINTF\n  38:\t\tselect NET_SOCK_MSG if NET\n  39:\t\tselect NET_XGRESS if NET\n  40:\t\tselect PAGE_POOL if NET\n  41:\t\tdefault n\n  42:\t\thelp\n  43:\t\t  Enable the bpf() system call that allows to manipulate BPF programs\n  44:\t\t  and maps via file descriptors.\n  45:\t\n  46:\tconfig BPF_JIT\n  47:\t\tbool \"Enable BPF Just In Time compiler\"\n  48:\t\tdepends on BPF\n  49:\t\tdepends on HAVE_CBPF_JIT || HAVE_EBPF_JIT\n  50:\t\tselect EXECMEM\n  51:\t\thelp\n  52:\t\t  BPF programs are normally handled by a BPF interpreter. This option\n  53:\t\t  allows the kernel to generate native code when a program is loaded\n  54:\t\t  into the kernel. This will significantly speed-up processing of BPF\n  55:\t\t  programs.\n  56:\t\n  57:\t\t  Note, an admin should enable this feature changing:\n  58:\t\t  /proc/sys/net/core/bpf_jit_enable\n  59:\t\t  /proc/sys/net/core/bpf_jit_harden   (optional)\n  60:\t\t  /proc/sys/net/core/bpf_jit_kallsyms (optional)\n  61:\t\n  62:\tconfig BPF_JIT_ALWAYS_ON\n  63:\t\tbool \"Permanently enable BPF JIT and remove BPF interpreter\"\n  64:\t\tdepends on BPF_SYSCALL \u0026\u0026 HAVE_EBPF_JIT \u0026\u0026 BPF_JIT\n  65:\t\thelp\n  66:\t\t  Enables BPF JIT and removes BPF interpreter to avoid speculative\n  67:\t\t  execution of BPF instructions by the interpreter.\n  68:\t\n  69:\t\t  When CONFIG_BPF_JIT_ALWAYS_ON is enabled, /proc/sys/net/core/bpf_jit_enable\n  70:\t\t  is permanently set to 1 and setting any other value than that will\n  71:\t\t  return failure.\n  72:\t\n  73:\tconfig BPF_JIT_DEFAULT_ON\n  74:\t\tdef_bool ARCH_WANT_DEFAULT_BPF_JIT || BPF_JIT_ALWAYS_ON\n  75:\t\tdepends on HAVE_EBPF_JIT \u0026\u0026 BPF_JIT\n  76:\t\n  77:\tconfig BPF_UNPRIV_DEFAULT_OFF\n  78:\t\tbool \"Disable unprivileged BPF by default\"\n  79:\t\tdefault y\n  80:\t\tdepends on BPF_SYSCALL\n  81:\t\thelp\n  82:\t\t  Disables unprivileged BPF by default by setting the corresponding\n  83:\t\t  /proc/sys/kernel/unprivileged_bpf_disabled knob to 2. An admin can\n  84:\t\t  still reenable it by setting it to 0 later on, or permanently\n  85:\t\t  disable it by setting it to 1 (from which no other transition to\n  86:\t\t  0 is possible anymore).\n  87:\t\n  88:\t\t  Unprivileged BPF could be used to exploit certain potential\n  89:\t\t  speculative execution side-channel vulnerabilities on unmitigated\n"
}

7/2 2026/10/17 07:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 32765
							output: 32
							thoughts: 53
						

Thoughts:
Here's my summary, as the expert:

**Investigating the BPF Build Process**

Okay, so I need to understand how these BPF components are getting compiled and linked within the kernel. My first instinct is to dive into the `kernel/bpf/Makefile`. That's where all the build magic for the BPF subsystem should be happening. Specifically, I'm interested in how `bpf_iter.c`, `bpf_local_storage.c`, `cpumap.c`, and `devmap.c`, among others, are built. The Makefile should have the necessary rules and variables. This will help me understand how the dependencies are managed, the compiler flags being used, and how the object files are ultimately combined into whatever final artifacts the BPF subsystem produces.



8/2 2026/10/17 07:02 tool read-file
0m Args:
{
  "File": "kernel/bpf/Makefile",
  "FirstLine": 1,
  "LineCount": 60
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0\n   2:\tobj-y := core.o\n   3:\tifneq ($(CONFIG_BPF_JIT_ALWAYS_ON),y)\n   4:\t# ___bpf_prog_run() needs GCSE disabled on x86; see 3193c0836f203 for details\n   5:\tcflags-nogcse-$(CONFIG_X86)$(CONFIG_CC_IS_GCC) := -fno-gcse\n   6:\tendif\n   7:\tCFLAGS_core.o += -Wno-override-init $(cflags-nogcse-yy)\n   8:\t\n   9:\tobj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o cnum.o log.o token.o liveness.o const_fold.o diagnostics.o loops.o scev.o\n  10:\tobj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o\n  11:\tobj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o\n  12:\tobj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o bpf_insn_array.o\n  13:\tobj-$(CONFIG_BPF_SYSCALL) += bpf_local_storage.o bpf_task_storage.o\n  14:\tobj-$(CONFIG_BPF_SYSCALL) += fixups.o cfg.o states.o backtrack.o check_btf.o\n  15:\tobj-${CONFIG_BPF_LSM}\t  += bpf_inode_storage.o\n  16:\tobj-$(CONFIG_BPF_SYSCALL) += disasm.o mprog.o\n  17:\tobj-$(CONFIG_BPF_JIT) += trampoline.o\n  18:\tobj-$(CONFIG_BPF_SYSCALL) += btf.o memalloc.o rqspinlock.o stream.o\n  19:\tifeq ($(CONFIG_MMU)$(CONFIG_64BIT),yy)\n  20:\tobj-$(CONFIG_BPF_SYSCALL) += arena.o range_tree.o\n  21:\tendif\n  22:\tobj-$(CONFIG_BPF_JIT) += dispatcher.o\n  23:\tifeq ($(CONFIG_NET),y)\n  24:\tobj-$(CONFIG_BPF_SYSCALL) += devmap.o\n  25:\tobj-$(CONFIG_BPF_SYSCALL) += cpumap.o\n  26:\tobj-$(CONFIG_BPF_SYSCALL) += offload.o\n  27:\tobj-$(CONFIG_BPF_SYSCALL) += net_namespace.o\n  28:\tobj-$(CONFIG_BPF_SYSCALL) += tcx.o\n  29:\tendif\n  30:\tifeq ($(CONFIG_KEYS),y)\n  31:\tobj-$(CONFIG_BPF_SYSCALL) += keys.o\n  32:\tendif\n  33:\tifeq ($(CONFIG_PERF_EVENTS),y)\n  34:\tobj-$(CONFIG_BPF_SYSCALL) += stackmap.o\n  35:\tendif\n  36:\tifeq ($(CONFIG_CGROUPS),y)\n  37:\tobj-$(CONFIG_BPF_SYSCALL) += cgroup_iter.o bpf_cgrp_storage.o\n  38:\tendif\n  39:\tobj-$(CONFIG_CGROUP_BPF) += cgroup.o\n  40:\tifeq ($(CONFIG_INET),y)\n  41:\tobj-$(CONFIG_BPF_SYSCALL) += reuseport_array.o\n  42:\tendif\n  43:\tifeq ($(CONFIG_SYSFS),y)\n  44:\tobj-$(CONFIG_DEBUG_INFO_BTF) += sysfs_btf.o\n  45:\tobj-$(CONFIG_DEBUG_INFO_BTF_INLINE) += btf_vmlinux_inline.o\n  46:\tendif\n  47:\tifeq ($(CONFIG_BPF_JIT),y)\n  48:\tobj-$(CONFIG_BPF_SYSCALL) += bpf_struct_ops.o\n  49:\tobj-$(CONFIG_BPF_SYSCALL) += cpumask.o\n  50:\t# bpf_lsm_proto.o must precede bpf_lsm.o. The current pahole logic\n  51:\t# deduplicates function prototypes within\n  52:\t# btf_encoder__add_saved_func() by keeping the first instance seen. We\n  53:\t# need the function prototype(s) in bpf_lsm_proto.o to take precedence\n  54:\t# over those within bpf_lsm.o. Having bpf_lsm_proto.o precede\n  55:\t# bpf_lsm.o ensures its DWARF CU is processed early, forcing the\n  56:\t# generated BTF to contain the overrides.\n  57:\t#\n  58:\t# Notably, this is a temporary workaround whilst the deduplication\n  59:\t# semantics within pahole are revisited accordingly.\n  60:\tobj-${CONFIG_BPF_LSM} += bpf_lsm_proto.o bpf_lsm.o\n"
}

9/2 2026/10/17 07:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 34413
							output: 36
							thoughts: 31
						

Thoughts:
Here's my take on those thoughts:

**Delving Deeper into Network Core BPF Capabilities**

Okay, so we're looking at network-related BPF. I need to get a better handle on the implementation details and what's connected where. Let's dig into `net/core/Makefile`. This should point us to the object files, at least, and potentially the source. Specifically, I'm thinking about those BPF-related files... the ones that deal with socket storage and maps. I need to refresh my understanding of how `bpf_sk_storage.c` functions, and also, I'm especially curious about `sock_map.c`. Understanding those parts is going to give a clear view of the kernel implementation.



10/2 2026/10/17 07:02 tool grepper
0m Args:
{
  "Expression": "bpf_sk_storage|sock_map",
  "PathPrefixes": [
    "net/core/Makefile"
  ]
}

Results:
{
  "Output": "net/core/Makefile=44=obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o\nnet/core/Makefile:45:obj-$(CONFIG_BPF_SYSCALL) += sock_map.o\nnet/core/Makefile:46:obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o\nnet/core/Makefile-47-ifdef CONFIG_INET\n"
}

11/2 2026/10/17 07:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 34751
							output: 30
							thoughts: 25
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience, presented in the first person:

**Navigating the BPF Trace Landscape**

Alright, so I'm digging into something related to BPF tracing, and the initial hunch points me towards `kernel/trace/bpf_trace.c`. Naturally, my first instinct is to double-check the associated `Makefile` within that directory, specifically `kernel/trace/Makefile`. This is standard operating procedure, really; I need to understand how this particular `.c` file fits into the larger build process and dependencies of the tracing infrastructure. What are the build flags? Are there any conditional includes I should be aware of? Any specific linker scripts? This Makefile holds the key to the bigger picture. Understanding that file is crucial for a complete understanding of how `bpf_trace.c` interacts with the rest of the kernel, how it's compiled, and how its functionality gets integrated at runtime. It's the essential first step before I dive deeper into the code itself.



12/2 2026/10/17 07:02 tool grepper
0m Args:
{
  "Expression": "bpf_trace",
  "PathPrefixes": [
    "kernel/trace/Makefile"
  ]
}

Results:
{
  "Output": "kernel/trace/Makefile=54=KCOV_INSTRUMENT_trace_irqsoff.o := n\nkernel/trace/Makefile-55-\nkernel/trace/Makefile:56:CFLAGS_bpf_trace.o := -I$(src)\nkernel/trace/Makefile-57-\n--\nkernel/trace/Makefile=109=obj-$(CONFIG_USER_EVENTS) += trace_events_user.o\nkernel/trace/Makefile:110:obj-$(CONFIG_BPF_EVENTS) += bpf_trace.o\nkernel/trace/Makefile-111-obj-$(CONFIG_KPROBE_EVENTS) += trace_kprobe.o\n"
}

13/2 2026/10/17 07:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 35193
							output: 29
							thoughts: 26
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Diving into the BPF Testing Infrastructure**

Alright, so I'm currently working with BPF code. I need to understand how the tests are structured, so naturally, my mind drifts towards the testing infrastructure. My immediate thought is, "Let's see what's going on in `net/bpf/test_run.c`." That file likely contains the core logic for executing BPF tests, setting up the environment, and validating the results. But I can't just jump into the code without understanding the build process. So, the next thing I need to do is to check the `net/bpf/Makefile`. This will give me all the information that I need, as the build configuration will tell me the test executables, dependencies, and any specific compilation flags used for these BPF tests. Understanding the Makefile is crucial; it's the gateway to properly interpreting how these tests are structured and run.



14/2 2026/10/17 07:02 tool grepper
0m Args:
{
  "Expression": "test_run",
  "PathPrefixes": [
    "net/bpf/"
  ]
}

Results:
{
  "Output": "net/bpf/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\nnet/bpf/Makefile:2:obj-$(CONFIG_BPF_SYSCALL)\t:= test_run.o\nnet/bpf/Makefile-3-ifeq ($(CONFIG_BPF_JIT),y)\n--\nnet/bpf/bpf_dummy_struct_ops.c=82=static const struct bpf_ctx_arg_aux *find_ctx_arg_info(struct bpf_prog_aux *aux, int offset)\n--\nnet/bpf/bpf_dummy_struct_ops.c-95- */\nnet/bpf/bpf_dummy_struct_ops.c:96:static int check_test_run_args(struct bpf_prog *prog, struct bpf_dummy_ops_test_args *args)\nnet/bpf/bpf_dummy_struct_ops.c-97-{\n--\nnet/bpf/bpf_dummy_struct_ops.c=127=extern const struct bpf_link_ops bpf_struct_ops_link_lops;\nnet/bpf/bpf_dummy_struct_ops.c-128-\nnet/bpf/bpf_dummy_struct_ops.c:129:int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr,\nnet/bpf/bpf_dummy_struct_ops.c-130-\t\t\t    union bpf_attr __user *uattr)\n--\nnet/bpf/bpf_dummy_struct_ops.c-156-\nnet/bpf/bpf_dummy_struct_ops.c:157:\terr = check_test_run_args(prog, args);\nnet/bpf/bpf_dummy_struct_ops.c-158-\tif (err)\n--\nnet/bpf/test_run.c-28-#define CREATE_TRACE_POINTS\nnet/bpf/test_run.c:29:#include \u003ctrace/events/bpf_test_run.h\u003e\nnet/bpf/test_run.c-30-\n--\nnet/bpf/test_run.c=100=struct xdp_test_data {\n--\nnet/bpf/test_run.c-118-\nnet/bpf/test_run.c:119:static void xdp_test_run_init_page(netmem_ref netmem, void *arg)\nnet/bpf/test_run.c-120-{\n--\nnet/bpf/test_run.c-149-\nnet/bpf/test_run.c:150:static int xdp_test_run_setup(struct xdp_test_data *xdp, struct xdp_buff *orig_ctx)\nnet/bpf/test_run.c-151-{\n--\nnet/bpf/test_run.c-158-\t\t.nid = NUMA_NO_NODE,\nnet/bpf/test_run.c:159:\t\t.init_callback = xdp_test_run_init_page,\nnet/bpf/test_run.c-160-\t\t.init_arg = xdp,\n--\nnet/bpf/test_run.c-203-\nnet/bpf/test_run.c:204:static void xdp_test_run_teardown(struct xdp_test_data *xdp)\nnet/bpf/test_run.c-205-{\n--\nnet/bpf/test_run.c=241=static int xdp_recv_frames(struct xdp_frame **frames, int nframes,\n--\nnet/bpf/test_run.c-272-\nnet/bpf/test_run.c:273:static int xdp_test_run_batch(struct xdp_test_data *xdp, struct bpf_prog *prog,\nnet/bpf/test_run.c-274-\t\t\t      u32 repeat)\n--\nnet/bpf/test_run.c-359-\nnet/bpf/test_run.c:360:static int bpf_test_run_xdp_live(struct bpf_prog *prog, struct xdp_buff *ctx,\nnet/bpf/test_run.c-361-\t\t\t\t u32 repeat, u32 batch_size, u32 *time)\n--\nnet/bpf/test_run.c-370-\nnet/bpf/test_run.c:371:\tret = xdp_test_run_setup(\u0026xdp, ctx);\nnet/bpf/test_run.c-372-\tif (ret)\n--\nnet/bpf/test_run.c-377-\t\txdp.frame_cnt = 0;\nnet/bpf/test_run.c:378:\t\tret = xdp_test_run_batch(\u0026xdp, prog, repeat - t.i);\nnet/bpf/test_run.c-379-\t\tif (unlikely(ret \u003c 0))\n--\nnet/bpf/test_run.c-383-\nnet/bpf/test_run.c:384:\txdp_test_run_teardown(\u0026xdp);\nnet/bpf/test_run.c-385-\treturn ret;\n--\nnet/bpf/test_run.c-387-\nnet/bpf/test_run.c:388:static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat,\nnet/bpf/test_run.c-389-\t\t\tu32 *retval, u32 *time, bool xdp)\n--\nnet/bpf/test_run.c=663=static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size,\n--\nnet/bpf/test_run.c-684-\nnet/bpf/test_run.c:685:int bpf_prog_test_run_tracing(struct bpf_prog *prog,\nnet/bpf/test_run.c-686-\t\t\t      const union bpf_attr *kattr,\n--\nnet/bpf/test_run.c-738-\nnet/bpf/test_run.c:739:struct bpf_raw_tp_test_run_info {\nnet/bpf/test_run.c-740-\tstruct bpf_prog *prog;\n--\nnet/bpf/test_run.c=745=static void\nnet/bpf/test_run.c:746:__bpf_prog_test_run_raw_tp(void *data)\nnet/bpf/test_run.c-747-{\nnet/bpf/test_run.c:748:\tstruct bpf_raw_tp_test_run_info *info = data;\nnet/bpf/test_run.c-749-\tstruct srcu_ctr __percpu *scp = NULL;\n--\nnet/bpf/test_run.c-781-\nnet/bpf/test_run.c:782:int bpf_prog_test_run_raw_tp(struct bpf_prog *prog,\nnet/bpf/test_run.c-783-\t\t\t     const union bpf_attr *kattr,\n--\nnet/bpf/test_run.c-787-\t__u32 ctx_size_in = kattr-\u003etest.ctx_size_in;\nnet/bpf/test_run.c:788:\tstruct bpf_raw_tp_test_run_info info;\nnet/bpf/test_run.c-789-\tint cpu = kattr-\u003etest.cpu, err = 0;\n--\nnet/bpf/test_run.c-823-\tif (prog-\u003esleepable) {\nnet/bpf/test_run.c:824:\t\t__bpf_prog_test_run_raw_tp(\u0026info);\nnet/bpf/test_run.c-825-\t} else {\n--\nnet/bpf/test_run.c-828-\t\t    cpu == current_cpu) {\nnet/bpf/test_run.c:829:\t\t\t__bpf_prog_test_run_raw_tp(\u0026info);\nnet/bpf/test_run.c-830-\t\t} else if (cpu \u003e= nr_cpu_ids || !cpu_online(cpu)) {\n--\nnet/bpf/test_run.c-839-\t\t\terr = smp_call_function_single(cpu,\nnet/bpf/test_run.c:840:\t\t\t\t\t\t       __bpf_prog_test_run_raw_tp,\nnet/bpf/test_run.c-841-\t\t\t\t\t\t       \u0026info, 1);\n--\nnet/bpf/test_run.c=1029=static struct proto bpf_dummy_proto = {\n--\nnet/bpf/test_run.c-1034-\nnet/bpf/test_run.c:1035:int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,\nnet/bpf/test_run.c-1036-\t\t\t  union bpf_attr __user *uattr)\n--\nnet/bpf/test_run.c-1087-\t\tif (ctx-\u003edata_end) {\nnet/bpf/test_run.c:1088:\t\t\t/* Non-linear LWT test_run is unsupported for now. */\nnet/bpf/test_run.c-1089-\t\t\tif (is_lwt) {\n--\nnet/bpf/test_run.c-1224-\nnet/bpf/test_run.c:1225:\tret = bpf_test_run(prog, skb, repeat, \u0026retval, \u0026duration, false);\nnet/bpf/test_run.c-1226-\tif (ret)\n--\nnet/bpf/test_run.c=1326=static void xdp_convert_buff_to_md(struct xdp_buff *xdp, struct xdp_md *xdp_md)\n--\nnet/bpf/test_run.c-1337-\nnet/bpf/test_run.c:1338:int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,\nnet/bpf/test_run.c-1339-\t\t\t  union bpf_attr __user *uattr)\n--\nnet/bpf/test_run.c-1468-\tif (do_live)\nnet/bpf/test_run.c:1469:\t\tret = bpf_test_run_xdp_live(prog, \u0026xdp, repeat, batch_size, \u0026duration);\nnet/bpf/test_run.c-1470-\telse\nnet/bpf/test_run.c:1471:\t\tret = bpf_test_run(prog, \u0026xdp, repeat, \u0026retval, \u0026duration, true);\nnet/bpf/test_run.c-1472-out_put_dev:\n--\nnet/bpf/test_run.c=1500=static int verify_user_bpf_flow_keys(struct bpf_flow_keys *ctx)\n--\nnet/bpf/test_run.c-1514-\nnet/bpf/test_run.c:1515:int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,\nnet/bpf/test_run.c-1516-\t\t\t\t     const union bpf_attr *kattr,\n--\nnet/bpf/test_run.c-1583-\nnet/bpf/test_run.c:1584:int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kattr,\nnet/bpf/test_run.c-1585-\t\t\t\tunion bpf_attr __user *uattr)\n--\nnet/bpf/test_run.c-1682-\nnet/bpf/test_run.c:1683:int bpf_prog_test_run_syscall(struct bpf_prog *prog,\nnet/bpf/test_run.c-1684-\t\t\t      const union bpf_attr *kattr,\n--\nnet/bpf/test_run.c=1769=static __be16 nfproto_eth(int nfproto)\n--\nnet/bpf/test_run.c-1780-\nnet/bpf/test_run.c:1781:int bpf_prog_test_run_nf(struct bpf_prog *prog,\nnet/bpf/test_run.c-1782-\t\t\t const union bpf_attr *kattr,\n--\nnet/bpf/test_run.c-1868-\nnet/bpf/test_run.c:1869:\tret = bpf_test_run(prog, \u0026ctx, repeat, \u0026retval, \u0026duration, false);\nnet/bpf/test_run.c-1870-\tif (ret)\n--\nnet/bpf/test_run.c=1891=BTF_ID(func, bpf_kfunc_call_memb_release_dtor)\nnet/bpf/test_run.c-1892-\nnet/bpf/test_run.c:1893:static int __init bpf_prog_test_run_init(void)\nnet/bpf/test_run.c-1894-{\n--\nnet/bpf/test_run.c-1914-}\nnet/bpf/test_run.c:1915:late_initcall(bpf_prog_test_run_init);\n"
}

15/2 2026/10/17 07:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 38963
							output: 74
							thoughts: 3283
						

Thoughts:
**BPF Fuzzing Target Analysis**

Okay, so I've got a diff here, a big one. My task is to determine if it's a good candidate for fuzzing, and, if so, what the specific targets should be. First, I need to evaluate *reachability*. This is BPF; it's practically guaranteed to be reachable from userspace via the `bpf(2)` syscall, network operations, or via kfuncs, so yes, it is *definitely* reachable. Excellent, that's step one. Also syzkaller will have support for it, so there's an existing infrastructure.

Next, I look at the modified files. There are changes in BPF iterators, local storage, BTF handling, CFG, program management, cpumap, devmap, fixups, hashtables, helpers, map-in-map, map iterators, offloading, states, syscalls, task iterators, token handling, the all-important verifier, tracepoints, and networking components. A substantial overhaul, no doubt. The scope alone suggests that this is a significant area to consider.

Now for the *critical* question: what are the *FocusSymbols*? I can't just throw everything at the fuzzer. I need to avoid ubiquitous code and focus on the *specific* logic and entrypoints of the changes. I'll start with the verifier, as that's always a critical component. `check_buffer_access`, `check_map_func_compatibility`, `check_kfunc_call`, `check_func_arg`, `push_callback_call`, `set_map_elem_callback_state`, `regs_refine_cond_op`. They look like good targets. The verifier's entry point, `bpf_check` is potentially too broad, so let's refine this list.

I need to look at specific functions modified *across* the changed files. `bpf_iter_link_replace`, `bpf_iter_link_attach`, `bpf_iter_prog_supported`, `bpf_iter_map_check_value_write`, `bpf_iter_attach_map`, `bpf_selem_unlink_nofail`, `bpf_local_storage_destroy`, `bpf_sk_storage_clone`, `alloc_htab_elem`, `htab_map_update_elem`, `cpu_map_generic_redirect`, `bq_flush_to_queue`, `bpf_prog_realloc`, `bpf_prog_free_deferred`, `bpf_prog_free_images`, `bpf_prog_bind_map`, `bpf_task_fd_query`, `bpf_token_create`, `__bpf_skb_store_bytes`, `bpf_skb_net_grow`, `bpf_lwt_seg6_action`, `bpf_wq_work`, and `bpf_prog_test_run_sk_lookup` all warrant a deeper look. Then there are some BPF storage related functions as well.

I need to filter out any that might be internal to the subsystem, non-exported or static. Let's see... `bpf_iter_map_check_value_write` looks good as it's declared in `include/linux/bpf.h`. The same applies for some other functions:  `bpf_iter_link_attach`, `bpf_iter_prog_supported`, `bpf_token_create`, `bpf_prog_bind_map`, `bpf_task_fd_query`, `cpu_map_generic_redirect`, `bpf_sk_storage_clone`, `__bpf_skb_store_bytes`, `__bpf_skb_meta_store_bytes`, `bpf_lwt_seg6_action`, `htab_map_update_elem`, `bpf_local_storage_destroy`.

I'll need to check the declaration for `regs_refine_cond_op`, `check_kfunc_call`, and `check_map_func_compatibility` in `kernel/bpf/verifier.c` to see if they're static functions and remove them if they are. I am sure that all these will trigger interesting behavior when the fuzzer is set loose on them. This list is a good starting point.



16/2 2026/10/17 07:03 tool grepper
0m Args:
{
  "Expression": "^(static )?(int|void|bool) (regs_refine_cond_op|check_kfunc_call|check_map_func_compatibility|bpf_iter_map_check_value_write)",
  "PathPrefixes": [
    "kernel/bpf/"
  ]
}

Results:
{
  "Output": "kernel/bpf/map_iter.c=90=static struct bpf_iter_reg bpf_map_reg_info = {\n--\nkernel/bpf/map_iter.c-104- */\nkernel/bpf/map_iter.c:105:int bpf_iter_map_check_value_write(const struct bpf_prog *prog,\nkernel/bpf/map_iter.c-106-\t\t\t\t   const struct bpf_map *map)\n--\nkernel/bpf/verifier.c=10414=static bool map_needs_no_rcu(const struct bpf_map *map)\n--\nkernel/bpf/verifier.c-10444-\nkernel/bpf/verifier.c:10445:static int check_map_func_compatibility(struct bpf_verifier_env *env,\nkernel/bpf/verifier.c-10446-\t\t\t\t\tstruct bpf_map *map, int func_id)\n--\nkernel/bpf/verifier.c=15218=static int check_return_code(struct bpf_verifier_env *env, int regno, const char *reg_name);\nkernel/bpf/verifier.c-15219-\nkernel/bpf/verifier.c:15220:static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\nkernel/bpf/verifier.c-15221-\t\t\t    int *insn_idx_p)\n--\nkernel/bpf/verifier.c=17781=static void find_good_pkt_pointers(struct bpf_verifier_state *vstate,\n--\nkernel/bpf/verifier.c-17857-\nkernel/bpf/verifier.c:17858:static void regs_refine_cond_op(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2,\nkernel/bpf/verifier.c-17859-\t\t\t\tu8 opcode, bool is_jmp32);\n--\nkernel/bpf/verifier.c=18174=u8 bpf_rev_opcode(u8 opcode)\n--\nkernel/bpf/verifier.c-18196-/* Refine range knowledge for \u003creg1\u003e \u003cop\u003e \u003creg\u003e2 conditional operation. */\nkernel/bpf/verifier.c:18197:static void regs_refine_cond_op(struct bpf_reg_state *reg1, struct bpf_reg_state *reg2,\nkernel/bpf/verifier.c-18198-\t\t\t\tu8 opcode, bool is_jmp32)\n"
}

17/2 2026/10/17 07:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 43944
							output: 32
							thoughts: 938
						

Thoughts:
**Analyzing BPF Function Call Inlining and Dependencies**

Okay, so I'm looking at this `check_kfunc_call` function, and it's enormous. Given its size, thousands of lines, it's highly unlikely that GCC or Clang will inline it. Let's see about `regs_refine_cond_op` then; it's only about 70 lines, so whether it's inlined is more uncertain. I should check its callers to get a better sense.

First, let me survey the landscape of related functions in `kernel/bpf/verifier.c` and elsewhere. In `verifier.c`, besides `check_kfunc_call`, I see other relevant functions: `check_func_arg`, `check_helper_call`, `check_map_prog_compatibility`, and `check_map_func_compatibility`. That's a good starting point.

Now, let's broaden the search outside `verifier.c`. In `kernel/bpf/bpf_iter.c`, I spot `bpf_iter_link_replace`, `bpf_iter_link_attach`, and `bpf_iter_prog_supported`. Then, in `kernel/bpf/map_iter.c`, there's `bpf_iter_map_check_value_write` and `bpf_iter_attach_map`. Moving on to `net/core/bpf_sk_storage.c`, I see `bpf_sk_storage_clone` and `bpf_sk_storage_selem_get_sk`. `net/core/filter.c` gives me `__bpf_skb_store_bytes`, `bpf_skb_net_grow`, `bpf_lwt_seg6_action`, and `__bpf_skb_meta_store_bytes`. I also find `bpf_token_create` in `kernel/bpf/token.c`, `bpf_task_fd_query` and `bpf_prog_bind_map` in `kernel/bpf/syscall.c`, `bpf_prog_test_run_sk_lookup` in `net/bpf/test_run.c`, and `htab_map_update_elem` in `kernel/bpf/hashtab.c`. Okay, that gives me a good overview of the relevant code base.

Next, I need to understand the configuration dependencies. What configurations are required to compile and reach the modified code path? Let's check each file.

I've examined the following files and found they all require `CONFIG_BPF_SYSCALL=y`: `kernel/bpf/bpf_iter.c`, `kernel/bpf/map_iter.c`, `kernel/bpf/task_iter.c`, `kernel/bpf/syscall.c`, `kernel/bpf/verifier.c`, `kernel/bpf/hashtab.c`, and `kernel/bpf/bpf_local_storage.c`.

I also looked at `kernel/bpf/cpumap.c`, `kernel/bpf/devmap.c`, and `kernel/bpf/offload.c`, and it appears `CONFIG_NET` and `CONFIG_BPF_SYSCALL` are needed for these.

Similarly, `net/core/bpf_sk_storage.c` and `net/core/sock_map.c` also need `CONFIG_BPF_SYSCALL`, and `net/bpf/test_run.c` requires `CONFIG_BPF_SYSCALL` as well.

Ah, and finally, `kernel/trace/bpf_trace.c` is enabled with `CONFIG_BPF_EVENTS`. I should double-check which config options enable `BPF_EVENTS`. Gotta make sure I'm not missing anything critical in the build configurations.



18/2 2026/10/17 07:03 tool grepper
0m Args:
{
  "Expression": "config BPF_EVENTS",
  "PathPrefixes": [
    "kernel/trace/Kconfig"
  ]
}

Results:
{
  "Output": "kernel/trace/Kconfig=851=config EPROBE_EVENTS\n--\nkernel/trace/Kconfig-864-\nkernel/trace/Kconfig:865:config BPF_EVENTS\nkernel/trace/Kconfig-866-\tdepends on BPF_SYSCALL\n"
}

19/2 2026/10/17 07:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 45851
							output: 34
							thoughts: 19
						

Thoughts:
Here's my take on the kernel's tracing configuration:

**Diving into `kernel/trace/Kconfig`**

Alright, let's get down to brass tacks. I'm going to pull up `kernel/trace/Kconfig` and zoom in around line 865. I need to understand how this particular section of tracing functionality is configured. What's the context here? Are we dealing with a specific tracing feature, a module option, or something more fundamental to the overall tracing infrastructure? I need to analyze the surrounding lines for clues and dependencies. I'm looking for the defining characteristics of this section, what are the relevant symbols being defined, what options are available to control this behavior, and how does this fit into the broader tracing picture?



20/2 2026/10/17 07:03 tool read-file
0m Args:
{
  "File": "kernel/trace/Kconfig",
  "FirstLine": 860,
  "LineCount": 20
}

Results:
{
  "Contents": " 860:\t\t  events. It can be used to limit what fields are recorded in\n 861:\t\t  an event or even dereference a field of an event. It can\n 862:\t\t  convert the type of an event field. For example, turn an\n 863:\t\t  address into a string.\n 864:\t\n 865:\tconfig BPF_EVENTS\n 866:\t\tdepends on BPF_SYSCALL\n 867:\t\tdepends on (KPROBE_EVENTS || UPROBE_EVENTS) \u0026\u0026 PERF_EVENTS\n 868:\t\tbool\n 869:\t\tdefault y\n 870:\t\thelp\n 871:\t\t  This allows the user to attach BPF programs to kprobe, uprobe, and\n 872:\t\t  tracepoint events.\n 873:\t\n 874:\tconfig DYNAMIC_EVENTS\n 875:\t\tdef_bool n\n 876:\t\n 877:\tconfig PROBE_EVENTS\n 878:\t\tdef_bool n\n 879:\t\n"
}

21/2 2026/10/17 07:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 46346
							output: 38
							thoughts: 225
						

Thoughts:
**My Assessment of BPF Event Dependencies**

Okay, so I'm looking at the dependencies related to `BPF_EVENTS`. The code clearly shows it hinges on a few other configurations. Specifically, it needs `BPF_SYSCALL` and, depending on whether we're dealing with kernel or user space probes, either `KPROBE_EVENTS` or `UPROBE_EVENTS`, and critically, `PERF_EVENTS`. Got it. That seems logical from a systems perspective.

Now, digging deeper into `syscall.c` at lines 4088 and 4142, there are conditional compilations based on `#ifdef CONFIG_KPROBE_EVENTS` and `#ifdef CONFIG_UPROBE_EVENTS`. This reinforces the probe-specific requirements I just identified. Nothing unexpected there, so far.

Then, I jumped over to the verifier code, `kernel/bpf/verifier.c`. I see another `#ifdef CONFIG_BPF_EVENTS`. That's to be expected, but I want to see *how* it's being used. The `dynptr_write_kfuncs` section seems interesting: it's got a bunch of `BTF_ID(func, ...)` declarations for `bpf_probe_read_user_dynptr` and `bpf_probe_read_kernel_dynptr`. The use of BTF hints that it's handling dynamic probe reads. This is all standard stuff.

But wait, I need to check something else. What about `bpf_lwt_seg6_action` in `net/core/filter.c`? Is that related? I need to check what config guards `bpf_lwt_seg6_action`, or even the broader `SEG6` configuration. It's possible it has dependencies on events that I don't see. Need to follow those threads.



22/2 2026/10/17 07:03 tool grepper
0m Args:
{
  "Expression": "bpf_lwt_seg6_action",
  "PathPrefixes": [
    "net/core/filter.c"
  ]
}

Results:
{
  "Output": "net/core/filter.c=7045=static void bpf_update_srh_state(struct sk_buff *skb)\n--\nnet/core/filter.c-7059-\nnet/core/filter.c:7060:BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\nnet/core/filter.c-7061-\t   u32, action, void *, param, u32, param_len)\n--\nnet/core/filter.c-7128-\nnet/core/filter.c:7129:static const struct bpf_func_proto bpf_lwt_seg6_action_proto = {\nnet/core/filter.c:7130:\t.func\t\t= bpf_lwt_seg6_action,\nnet/core/filter.c-7131-\t.gpl_only\t= false,\n--\nnet/core/filter.c=9090=lwt_seg6local_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)\n--\nnet/core/filter.c-9098-\tcase BPF_FUNC_lwt_seg6_action:\nnet/core/filter.c:9099:\t\treturn \u0026bpf_lwt_seg6_action_proto;\nnet/core/filter.c-9100-\tcase BPF_FUNC_lwt_seg6_adjust_srh:\n"
}

23/2 2026/10/17 07:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 47395
							output: 36
							thoughts: 44
						

Thoughts:
Here's my summary, as if I were thinking it:

**Examining the BPF LWT Seg6 Action Guard**

Alright, let's dive into this `bpf_lwt_seg6_action` function, specifically within the `net/core/filter.c` file. I need to understand what's guarding this particular BPF action. Let me zero in on lines 7030 through 7050. That should give me the core context I need. Hopefully, the code there provides the key checks and conditions.



24/2 2026/10/17 07:03 tool read-file
0m Args:
{
  "File": "net/core/filter.c",
  "FirstLine": 7030,
  "LineCount": 25
}

Results:
{
  "Contents": "7030:\t\n7031:\t\tmemcpy(skb-\u003edata + offset, from, len);\n7032:\t\treturn 0;\n7033:\t}\n7034:\t\n7035:\tstatic const struct bpf_func_proto bpf_lwt_seg6_store_bytes_proto = {\n7036:\t\t.func\t\t= bpf_lwt_seg6_store_bytes,\n7037:\t\t.gpl_only\t= false,\n7038:\t\t.ret_type\t= RET_INTEGER,\n7039:\t\t.arg1_type\t= ARG_PTR_TO_CTX,\n7040:\t\t.arg2_type\t= ARG_ANYTHING,\n7041:\t\t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n7042:\t\t.arg4_type\t= ARG_MEM_SIZE\n7043:\t};\n7044:\t\n7045:\tstatic void bpf_update_srh_state(struct sk_buff *skb)\n7046:\t{\n7047:\t\tstruct seg6_bpf_srh_state *srh_state =\n7048:\t\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n7049:\t\n7050:\t\t/* Behind a decapsulation this is a header that nobody has looked at */\n7051:\t\tsrh_state-\u003esrh = seg6_get_srh(skb, 0);\n7052:\t\tif (srh_state-\u003esrh) {\n7053:\t\t\tsrh_state-\u003ehdrlen = srh_state-\u003esrh-\u003ehdrlen \u003c\u003c 3;\n7054:\t\t\tsrh_state-\u003evalid = true;\n"
}

25/2 2026/10/17 07:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 48056
							output: 38
							thoughts: 20
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Tracing the Definition of `seg6_bpf_srh_states`**

Okay, so I need to understand `seg6_bpf_srh_states`. My immediate instinct is to pinpoint where this thing is actually defined. Is it a structure, an enum, a variable? Is it declared in a header file? A macro? I have a feeling it's something internal to a particular module, given the naming convention, but let's not make any assumptions yet. I need the actual *definition*. Time to dive into the codebase and start tracing it down. Let's see if `grep` or my IDE's search function can quickly locate where that variable, structure, or macro is declared. This is the first step in understanding its purpose, how it's used, and, ultimately, how it fits into the overall SEG6_BPF architecture. It's time to follow the trail of definitions!



26/2 2026/10/17 07:03 tool grepper
0m Args:
{
  "Expression": "seg6_bpf_srh_states",
  "PathPrefixes": [
    "net/core/filter.c"
  ]
}

Results:
{
  "Output": "net/core/filter.c=7002=BPF_CALL_4(bpf_lwt_seg6_store_bytes, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c-7005-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7006:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7007-\tstruct ipv6_sr_hdr *srh = srh_state-\u003esrh;\n--\nnet/core/filter.c=7045=static void bpf_update_srh_state(struct sk_buff *skb)\n--\nnet/core/filter.c-7047-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7048:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7049-\n--\nnet/core/filter.c=7060=BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\n--\nnet/core/filter.c-7063-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7064:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7065-\tint hdroff = 0;\n--\nnet/core/filter.c=7139=BPF_CALL_3(bpf_lwt_seg6_adjust_srh, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c-7142-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7143:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7144-\tstruct ipv6_sr_hdr *srh = srh_state-\u003esrh;\n"
}

27/2 2026/10/17 07:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 48885
							output: 44
							thoughts: 28
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Tracing the Declaration of `seg6_bpf_srh_states`**

Alright, let's dive in. My immediate thought is to pinpoint the exact declaration of `seg6_bpf_srh_states`. I know it's related to BPF and likely handles state management for Segment Routing Header (SRH) processing within the kernel's network filtering framework. Given that context, my hunch is that it'll reside within `net/core/filter.c`. Time to confirm and get the precise declaration. This'll tell me its data type, scope, and how it's initialized, which are all crucial for understanding its role in the larger picture of SRH and BPF integration. It's a fundamental step for any deeper investigation into how this state is managed and utilized.



28/2 2026/10/17 07:03 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "DEFINE_PER_CPU.*seg6_bpf_srh_states",
  "PathPrefixes": [
    "net/core/filter.c"
  ]
}

Results:
{
  "error": "no matches"
}

29/2 2026/10/17 07:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 49159
							output: 24
							thoughts: 21
						

Thoughts:
Okay, here's my summary, tailored for an expert audience, as if I'm thinking these thoughts:

**Analyzing the Landscape for `seg6_bpf_srh_states`**

Alright, time to get my hands dirty. I need to understand the current state of play with `seg6_bpf_srh_states`. My instinct is to do a comprehensive search. I'm going to kick off a `grep` operation. I'll need to run this across the entire codebase to get a truly global perspective. It's the only way to avoid missing any subtle, potentially critical, usages or interactions. I'm anticipating that this will likely reveal where the variable is defined, how it's used – read, written, initialized, etc. – and in what context. I'm particularly interested in seeing how it's integrated with other relevant data structures and functions. I'll be keeping an eye out for potential race conditions or locking issues, of course. Given my experience, I expect that this will reveal the entire design intent within this segment. I'll need to check the results carefully to piece together the full picture.



30/2 2026/10/17 07:03 tool grepper
0m Args:
{
  "Expression": "seg6_bpf_srh_states"
}

Results:
{
  "Output": "include/net/seg6_local.h=21=struct seg6_bpf_srh_state {\n--\ninclude/net/seg6_local.h-27-\ninclude/net/seg6_local.h:28:DECLARE_PER_CPU(struct seg6_bpf_srh_state, seg6_bpf_srh_states);\ninclude/net/seg6_local.h-29-\n--\nnet/core/filter.c=7002=BPF_CALL_4(bpf_lwt_seg6_store_bytes, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c-7005-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7006:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7007-\tstruct ipv6_sr_hdr *srh = srh_state-\u003esrh;\n--\nnet/core/filter.c=7045=static void bpf_update_srh_state(struct sk_buff *skb)\n--\nnet/core/filter.c-7047-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7048:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7049-\n--\nnet/core/filter.c=7060=BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\n--\nnet/core/filter.c-7063-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7064:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7065-\tint hdroff = 0;\n--\nnet/core/filter.c=7139=BPF_CALL_3(bpf_lwt_seg6_adjust_srh, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c-7142-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7143:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7144-\tstruct ipv6_sr_hdr *srh = srh_state-\u003esrh;\n--\nnet/ipv6/seg6_local.c=1459=static int input_action_end_b6_encap(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-1493-\nnet/ipv6/seg6_local.c:1494:DEFINE_PER_CPU(struct seg6_bpf_srh_state, seg6_bpf_srh_states) = {\nnet/ipv6/seg6_local.c-1495-\t.bh_lock\t= INIT_LOCAL_LOCK(bh_lock),\n--\nnet/ipv6/seg6_local.c=1498=bool seg6_bpf_has_valid_srh(struct sk_buff *skb)\n--\nnet/ipv6/seg6_local.c-1500-\tstruct seg6_bpf_srh_state *srh_state =\nnet/ipv6/seg6_local.c:1501:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/ipv6/seg6_local.c-1502-\tstruct ipv6_sr_hdr *srh = srh_state-\u003esrh;\n--\nnet/ipv6/seg6_local.c=1522=static int input_action_end_bpf(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-1546-\t */\nnet/ipv6/seg6_local.c:1547:\tlocal_lock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\nnet/ipv6/seg6_local.c:1548:\tsrh_state = this_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/ipv6/seg6_local.c-1549-\tsrh_state-\u003esrh = srh;\n--\nnet/ipv6/seg6_local.c-1570-\t\tgoto drop;\nnet/ipv6/seg6_local.c:1571:\tlocal_unlock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\nnet/ipv6/seg6_local.c-1572-\n--\nnet/ipv6/seg6_local.c-1578-drop:\nnet/ipv6/seg6_local.c:1579:\tlocal_unlock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\nnet/ipv6/seg6_local.c-1580-\tkfree_skb(skb);\n"
}

31/2 2026/10/17 07:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 50759
							output: 33
							thoughts: 41
						

Thoughts:
Here's my analysis of the provided thought process, tailored for an expert audience:

**Investigating Security Contexts in `net/core/filter.c`**

Okay, so I'm diving into `net/core/filter.c` with the specific intent of pinpointing the security contexts, or lack thereof, around `lwt_seg6local_func_proto` or `bpf_lwt_seg6_action`. This suggests I'm concerned about potential vulnerabilities or privilege escalation possibilities related to Segment Routing IPv6 (SRv6) in this area. My thought process is clear: I want to understand how these functions, presumably related to the handling of Locally-Assigned Segments (LAS) with BPF programs, are guarded. Are there proper checks for BPF program permissions, are there any potential for exploitable memory access, or is the architecture sound with its access control mechanisms? I am thinking that any weak security here is a threat to the kernel.



32/2 2026/10/17 07:03 tool grepper
0m Args:
{
  "Expression": "CONFIG_IPV6_SEG6_BPF",
  "PathPrefixes": [
    "net/"
  ]
}

Results:
{
  "Output": "net/core/filter.c=6895=static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {\n--\nnet/core/filter.c-6906-\nnet/core/filter.c:6907:#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\nnet/core/filter.c-6908-static int bpf_push_seg6_encap(struct sk_buff *skb, u32 type, void *hdr, u32 len)\n--\nnet/core/filter.c-6939-}\nnet/core/filter.c:6940:#endif /* CONFIG_IPV6_SEG6_BPF */\nnet/core/filter.c-6941-\n--\nnet/core/filter.c=6950=BPF_CALL_4(bpf_lwt_in_push_encap, struct sk_buff *, skb, u32, type, void *, hdr,\n--\nnet/core/filter.c-6953-\tswitch (type) {\nnet/core/filter.c:6954:#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\nnet/core/filter.c-6955-\tcase BPF_LWT_ENCAP_SEG6:\n--\nnet/core/filter.c=6991=static const struct bpf_func_proto bpf_lwt_xmit_push_encap_proto = {\n--\nnet/core/filter.c-7000-\nnet/core/filter.c:7001:#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\nnet/core/filter.c-7002-BPF_CALL_4(bpf_lwt_seg6_store_bytes, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c=7190=static const struct bpf_func_proto bpf_lwt_seg6_adjust_srh_proto = {\n--\nnet/core/filter.c-7197-};\nnet/core/filter.c:7198:#endif /* CONFIG_IPV6_SEG6_BPF */\nnet/core/filter.c-7199-\n--\nnet/core/filter.c=9090=lwt_seg6local_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)\n--\nnet/core/filter.c-9094-\t\treturn NULL;\nnet/core/filter.c:9095:#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\nnet/core/filter.c-9096-\tcase BPF_FUNC_lwt_seg6_store_bytes:\n"
}

33/2 2026/10/17 07:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 51738
							output: 24
							thoughts: 44
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Analyzing the IPv6 Segment Routing with BPF Configuration Option**

Right, so `CONFIG_IPV6_SEG6_BPF` is the gatekeeper for a specific chunk of code within `net/core/filter.c`. My immediate thought is, "Ah, that's where the BPF integration for IPv6 Segment Routing lives!" That guard is key, and it directly controls the conditional compilation.

The next logical step, of course, is to dive straight into `Kconfig`. I need to understand *exactly* how `IPV6_SEG6_BPF` is defined, what dependencies it has, and what the potential implications are of enabling or disabling it within a build. I'll need to check the relationships it might have with other, seemingly related, configuration options, and see whether there might be any unexpected interactions. This will define whether the code is compiled into the image, and is available for configuration at runtime.



34/2 2026/10/17 07:03 tool grepper
0m Args:
{
  "Expression": "config IPV6_SEG6_BPF"
}

Results:
{
  "Output": "net/ipv6/Kconfig=300=config IPV6_SEG6_HMAC\n--\nnet/ipv6/Kconfig-311-\nnet/ipv6/Kconfig:312:config IPV6_SEG6_BPF\nnet/ipv6/Kconfig-313-\tdef_bool y\n"
}

35/2 2026/10/17 07:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 52110
							output: 35
							thoughts: 20
						

Thoughts:
Okay, here's the summary, assuming I'm the expert you describe:

**Delving into IPv6 Configuration**

Alright, let's get down to brass tacks. I'm going to pull up `net/ipv6/Kconfig` and zoom in around line 312. I need to understand this section related to... *[I'm pausing here because I don't know the specific context and am waiting for more text to continue]* ... Whatever the relevant functionality or setting is in that region of the config file. I'm going to start by quickly scanning the surrounding code, focusing on the dependencies, default values, and help text. This should give me the crucial context I need to fully grasp what's being configured. From there, I'll assess the implications of different settings and how they might affect the overall IPv6 implementation. I will quickly look for any potentially dangerous settings. I'll need to know whether the existing documentation is thorough and accurate, or whether I will need to delve further into the code. My experience tells me that line numbers in config files can be tricky.



36/2 2026/10/17 07:04 tool read-file
0m Args:
{
  "File": "net/ipv6/Kconfig",
  "FirstLine": 310,
  "LineCount": 15
}

Results:
{
  "Contents": " 310:\t\t  If unsure, say N.\n 311:\t\n 312:\tconfig IPV6_SEG6_BPF\n 313:\t\tdef_bool y\n 314:\t\tdepends on IPV6_SEG6_LWTUNNEL\n 315:\t\tdepends on IPV6 = y\n 316:\t\n 317:\tconfig IPV6_RPL_LWTUNNEL\n 318:\t\tbool \"IPv6: RPL Source Routing Header support\"\n 319:\t\tdepends on IPV6\n 320:\t\tselect LWTUNNEL\n 321:\t\tselect DST_CACHE\n 322:\t\thelp\n 323:\t\t  Support for RFC6554 RPL Source Routing Header using the lightweight\n 324:\t\t  tunnels mechanism.\n"
}

37/2 2026/10/17 07:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 52615
							output: 26
							thoughts: 20
						

Thoughts:
Here's my analysis of the `IPV6_SEG6_LWTUNNEL` dependency situation:

**Deconstructing IPV6_SEG6_LWTUNNEL Dependencies**

Okay, so I need to understand what `IPV6_SEG6_LWTUNNEL` is built on. My approach is to trace its dependencies. This means digging into the kernel configuration options and the code itself to see what other features or modules *must* be enabled or present for `IPV6_SEG6_LWTUNNEL` to function correctly. I'll need to consider not just direct dependencies, but also indirect ones – the things that *those* dependencies rely on. I'm essentially reverse-engineering the build process in my mind. This means looking for things like:

*   Does it rely on other IPv6-related features (e.g., core IPv6 stack, routing)?
*   Does it need specific networking infrastructure (e.g., tunnels, netfilter)?
*   Are there any hardware dependencies that it assumes are available (e.g. specific NICs)?
*   How does this interact with other technologies I know in my field.

I'll be looking for configuration options that act as prerequisites, like the need for a specific version of some other module or function. This usually involves inspecting the kernel source and looking at the Kconfig files, or similar. Essentially, I need to form a detailed, hierarchical dependency tree, mapping out every layer required for `IPV6_SEG6_LWTUNNEL` to do its job. It's about building a robust mental model of the requirements.



38/2 2026/10/17 07:04 tool grepper
0m Args:
{
  "Expression": "config IPV6_SEG6_LWTUNNEL"
}

Results:
{
  "Output": "net/ipv6/Kconfig=279=config IPV6_PIMSM_V2\n--\nnet/ipv6/Kconfig-285-\nnet/ipv6/Kconfig:286:config IPV6_SEG6_LWTUNNEL\nnet/ipv6/Kconfig-287-\tbool \"IPv6: Segment Routing Header encapsulation support\"\n"
}

39/2 2026/10/17 07:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 53102
							output: 436
							thoughts: 3953
						

Thoughts:
**Analysis of BPF Patch and Configuration Requirements**

Okay, let's break this down. We're looking at a patch series that significantly touches various aspects of the BPF subsystem within the Linux kernel. My focus is on ensuring a robust fuzzing configuration. First, I need to identify all the necessary kernel configurations. Based on the files modified and the dependencies within the kernel source (Kconfig files, #ifdef guards, and Makefiles), it's clear that the following configurations are mandatory: `BPF_SYSCALL` (critical as it enables the BPF syscall and core BPF functionality), `NET` (essential for networking-related BPF code, including filters, devmap, and cpumap), `BPF_EVENTS` (needed for BPF tracepoints and related functionalities), `KPROBE_EVENTS` / `UPROBE_EVENTS` (for probe-related changes), and `IPV6_SEG6_LWTUNNEL` (for segment routing features).

Next, I have to determine the *focus* of our fuzzing efforts.  I need to avoid the common pitfalls - we want to target specific feature logic and entry points, not generic, ubiquitous kernel functions.  Therefore, I've carefully reviewed the modified functions and identified a subset that are *direct* entrypoints or crucial components of the changes: `bpf_iter_map_check_value_write`, `bpf_iter_link_replace`, `bpf_selem_unlink_nofail`, `bpf_sk_storage_clone`, `bpf_sk_storage_selem_get_sk`, `htab_map_update_elem`, `cpu_map_generic_redirect`, `cpu_map_kthread_run`, `bpf_token_create`, `bpf_task_fd_query`, `bpf_prog_test_run_sk_lookup`, `__bpf_skb_store_bytes`, `bpf_skb_net_grow`, `bpf_lwt_seg6_action`, `check_buffer_access`, `check_kfunc_call`, `check_map_func_compatibility`, `push_callback_call` among others. These are all functions that are either new, modified, or directly involved in the critical logic being altered by the patch. I've also verified their presence in the kernel source, excluding any static inlines, which wouldn't have addressable symbols.

The fuzzing strategy is designed to directly target the BPF changes. The patch alters code in core BPF, networking filters, iterators, local storage, syscall handlers, verifier, tracing, and map functionality. The core reason for fuzzing is the potential for concurrency issues, use-after-free conditions, verification bypasses, memory leaks, and regressions in map/iterator lifetime handling. These functions will exercise the affected code paths through the `bpf()` syscall, socket operations, iterators, and test runs. I'm satisfied that this configuration is thorough and focused.



40/2 2026/10/17 07:04 tool set-results
0m Args:
{
  "EnableConfigs": [
    "BPF_SYSCALL",
    "NET",
    "BPF_EVENTS",
    "KPROBE_EVENTS",
    "UPROBE_EVENTS",
    "IPV6_SEG6_LWTUNNEL"
  ],
  "FocusSymbols": [
    "bpf_iter_map_check_value_write",
    "bpf_iter_link_replace",
    "bpf_selem_unlink_nofail",
    "bpf_sk_storage_clone",
    "bpf_sk_storage_selem_get_sk",
    "htab_map_update_elem",
    "cpu_map_generic_redirect",
    "cpu_map_kthread_run",
    "bpf_token_create",
    "bpf_task_fd_query",
    "bpf_prog_test_run_sk_lookup",
    "__bpf_skb_store_bytes",
    "bpf_skb_net_grow",
    "bpf_lwt_seg6_action",
    "check_buffer_access",
    "check_kfunc_call",
    "check_map_func_compatibility",
    "push_callback_call"
  ],
  "Reasoning": "The patch series modifies core BPF subsystem logic, including the BPF verifier (dynptr writes, sleepable async callbacks, RCU callback tracking, buffer access ranges), BPF iterators (map/vma/sk_storage iteration, link replacement, program capability checks), map lifetime and concurrency (local storage refcounting/unlinking, hashtab extra elements, map-in-map), networking helpers (skb store bytes, seg6 actions, cpumap device reference holding), and syscall interfaces. These paths are directly reachable and exercisable from unprivileged or privileged userspace via the bpf() system call, socket operations, and perf/tracepoints. Fuzzing is warranted to uncover regressions, verification bypasses, or concurrency issues.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "BPF_SYSCALL",
    "NET",
    "BPF_EVENTS",
    "KPROBE_EVENTS",
    "UPROBE_EVENTS",
    "IPV6_SEG6_LWTUNNEL"
  ],
  "FocusSymbols": [
    "bpf_iter_map_check_value_write",
    "bpf_iter_link_replace",
    "bpf_selem_unlink_nofail",
    "bpf_sk_storage_clone",
    "bpf_sk_storage_selem_get_sk",
    "htab_map_update_elem",
    "cpu_map_generic_redirect",
    "cpu_map_kthread_run",
    "bpf_token_create",
    "bpf_task_fd_query",
    "bpf_prog_test_run_sk_lookup",
    "__bpf_skb_store_bytes",
    "bpf_skb_net_grow",
    "bpf_lwt_seg6_action",
    "check_buffer_access",
    "check_kfunc_call",
    "check_map_func_compatibility",
    "push_callback_call"
  ],
  "Reasoning": "The patch series modifies core BPF subsystem logic, including the BPF verifier (dynptr writes, sleepable async callbacks, RCU callback tracking, buffer access ranges), BPF iterators (map/vma/sk_storage iteration, link replacement, program capability checks), map lifetime and concurrency (local storage refcounting/unlinking, hashtab extra elements, map-in-map), networking helpers (skb store bytes, seg6 actions, cpumap device reference holding), and syscall interfaces. These paths are directly reachable and exercisable from unprivileged or privileged userspace via the bpf() system call, socket operations, and perf/tracepoints. Fuzzing is warranted to uncover regressions, verification bypasses, or concurrency issues.",
  "WorthFuzzing": true
}

41/1 2026/10/17 07:04 action If
4m Args:
{
  "WorthFuzzing": true
}

Results:
null

42/2 2026/10/17 07:04 agent kmsan-evaluator
4m Model:
core

Args:
null

Results:
{
  "KMSANReasoning": "The patch series addresses several issues across the BPF subsystem, including:\n1. Use-after-free and lifetime bugs: invalidating dynptr packet slices on skb writes, tracking moved packet headers in bpf_skb_store_bytes/bpf_skb_meta_store_bytes, deferring BPF JIT image freeing through RCU work, keeping net_device references in cpumap, and tracking socket references in bpf_sk_storage iterator.\n2. Memory leaks and reference counting: adding missing iput() on token creation error, adding kfree_const() for strings duplicated with kstrdup_const() in perf event info queries and fdinfo dumps.\n3. Concurrency and locking: using try_cmpxchg_local for per-cpu extra elems in hashtab, enforcing RCU critical sections for sleepable programs and iterator callbacks, and adding NOSLEEP restrictions on task_vma iterator.\n4. Verifier bounds checking: adding tracking for rdwr buffer writes (min_rdwr_write / max_rdwr_write) to prevent BPF programs from corrupting special BTF record fields (bpf_spin_lock, bpf_timer, etc.) in map values.\n\nKMSAN vs. KASAN analysis:\n- All new struct fields (such as min_rdwr_write, max_rdwr_write, sleepable_async_cb, rwork, in_rcu_callback_fn, dynptr_write_type, dead_sks, held, nr_held) reside within objects allocated with __GFP_ZERO or kzalloc (e.g., bpf_prog_aux, bpf_func_state, bpf_cpu_map_entry, seq_file private data).\n- The patch explicitly eliminates a potential uninitialized slab read in bpf_sk_storage_clone() by setting refcount_set(\u0026newsk-\u003esk_refcnt, 0) before linking elements.\n- No uninitialized data or struct padding is exposed or copied to user space. The changes touching user copy routines (bpf_perf_link_fill_common, bpf_task_fd_query) only ensure allocated buffers are properly freed with kfree_const().\n- The modified bounds checks and verifier logic tighten constraints rather than opening up uninitialized buffer reads.\n- The bugs targeted by these changes (UAF, memory leaks, concurrency races, refcount underflows) are comprehensively covered by KASAN, KMEMLEAK, and LOCKDEP in standard fuzzing builds.\n\nTherefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

Instruction:
You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.

CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
  a comprehensive suite of debugging tools and sanitizers, including KASAN
  (out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
  (locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
  or page allocations) and kernel-to-user memory info-leaks.

Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.

Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.

Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
   attributes, ioctl output arguments, socket options, or BPF buffers) where fields
   or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
   or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
   could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
   uninitialized bytes of existing buffers.

Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
  dereferences, locking deadlocks, or use-after-free bugs (these are already caught
  by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
  or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.

Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 1117fabc0498a30e4d022f35e627ac586b1db367
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Oct 17 07:02:07 2026 +0000

    syz-cluster: applied patch under review

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 54144372281cb..c1d92fd10ef12 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -341,6 +341,7 @@ struct bpf_map {
 	bool frozen; /* write-once; write-protected by freeze_mutex */
 	bool free_after_mult_rcu_gp;
 	bool free_after_rcu_gp;
+	bool was_inner_map;
 	atomic64_t sleepable_refcnt;
 	s64 __percpu *elem_count;
 	u64 cookie; /* write-once */
@@ -1858,6 +1859,9 @@ struct bpf_prog_aux {
 	u32 ctx_arg_info_size;
 	u32 max_rdonly_access;
 	u32 max_rdwr_access;
+	/* [min, max): the bytes of a rdwr buffer that may be written */
+	u32 min_rdwr_write;
+	u32 max_rdwr_write;
 	u32 subprog_start;
 	struct btf *attach_btf;
 	struct bpf_ctx_arg_aux *ctx_arg_info;
@@ -1873,6 +1877,7 @@ struct bpf_prog_aux {
 	bool attach_btf_trace; /* true if attaching to BTF-enabled raw tp */
 	bool attach_tracing_prog; /* true if tracing another tracing program */
 	bool tramp_linked; /* true if it was ever linked to a trampoline */
+	bool sleepable_async_cb; /* has a bpf_wq or bpf_task_work callback */
 	bool func_proto_unreliable;
 	bool tail_call_reachable;
 	bool xdp_has_frags;
@@ -1958,6 +1963,7 @@ struct bpf_prog_aux {
 	union {
 		struct work_struct work;
 		struct rcu_head	rcu;
+		struct rcu_work rwork;
 	};
 	struct bpf_stream *stream[2];
 	struct mutex st_ops_assoc_mutex;
@@ -2006,6 +2012,15 @@ struct bpf_prog {
 	};
 };
 
+/*
+ * Does the program, or a callback of it, run under RCU Tasks Trace protection
+ * only, outside of any RCU read side critical section?
+ */
+static inline bool bpf_prog_runs_sleepable(const struct bpf_prog *prog)
+{
+	return prog->sleepable || prog->aux->sleepable_async_cb;
+}
+
 struct bpf_array_aux {
 	/* Programs with direct jumps into programs part of this array. */
 	struct list_head poke_progs;
@@ -3128,6 +3143,8 @@ typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *prog,
 					union bpf_iter_link_info *linfo,
 					struct bpf_iter_aux_info *aux);
 typedef void (*bpf_iter_detach_target_t)(struct bpf_iter_aux_info *aux);
+typedef int (*bpf_iter_check_prog_t)(const struct bpf_prog *prog,
+				     const struct bpf_iter_aux_info *aux);
 typedef void (*bpf_iter_show_fdinfo_t) (const struct bpf_iter_aux_info *aux,
 					struct seq_file *seq);
 typedef int (*bpf_iter_fill_link_info_t)(const struct bpf_iter_aux_info *aux,
@@ -3137,7 +3154,8 @@ typedef const struct bpf_func_proto *
 			     const struct bpf_prog *prog);
 
 enum bpf_iter_feature {
-	BPF_ITER_RESCHED	= BIT(0),
+	BPF_ITER_RESCHED	= BIT(0),	/* may cond_resched() between objects */
+	BPF_ITER_NOSLEEP	= BIT(1),	/* ->show() can't run sleepable progs */
 };
 
 #define BPF_ITER_CTX_ARG_MAX 2
@@ -3145,6 +3163,8 @@ struct bpf_iter_reg {
 	const char *target;
 	bpf_iter_attach_target_t attach_target;
 	bpf_iter_detach_target_t detach_target;
+	/* may the program run on what the link is attached to? */
+	bpf_iter_check_prog_t check_prog;
 	bpf_iter_show_fdinfo_t show_fdinfo;
 	bpf_iter_fill_link_info_t fill_link_info;
 	bpf_iter_get_func_proto_t get_func_proto;
@@ -3181,6 +3201,8 @@ void bpf_iter_map_show_fdinfo(const struct bpf_iter_aux_info *aux,
 			      struct seq_file *seq);
 int bpf_iter_map_fill_link_info(const struct bpf_iter_aux_info *aux,
 				struct bpf_link_info *info);
+int bpf_iter_map_check_value_write(const struct bpf_prog *prog,
+				   const struct bpf_map *map);
 
 int map_set_for_each_callback_args(struct bpf_verifier_env *env,
 				   struct bpf_func_state *caller,
diff --git a/include/linux/bpf_local_storage.h b/include/linux/bpf_local_storage.h
index 9e4f5c45c974d..6c643ac510799 100644
--- a/include/linux/bpf_local_storage.h
+++ b/include/linux/bpf_local_storage.h
@@ -104,6 +104,19 @@ struct bpf_local_storage {
 	refcount_t owner_refcnt;/* Used to pin owner when map_free is uncharging */
 };
 
+/*
+ * Drop a reference got by refcount_inc_not_zero(&local_storage->owner_refcnt).
+ * bpf_local_storage_destroy() may have dropped the owner's reference meanwhile
+ * and wait for the count to reach zero, so this one can be the last.
+ */
+static inline void
+bpf_local_storage_unpin_owner(struct bpf_local_storage *local_storage)
+{
+	bool last __maybe_unused;
+
+	last = refcount_dec_and_test(&local_storage->owner_refcnt);
+}
+
 /* U16_MAX is much more than enough for sk local storage
  * considering a tcp_sock is ~2k.
  */
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 112ca1511da4d..1ca03f8cfd838 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -379,6 +379,11 @@ struct bpf_func_state {
 	bool in_async_callback_fn;
 	bool in_exception_callback_fn;
 	bool no_stack_arg_load;
+	/*
+	 * The helper invokes this callback under rcu_read_lock(), so the
+	 * callback and its callees run in an RCU read-side critical section.
+	 */
+	bool in_rcu_callback_fn;
 	/* For callback calling functions that limit number of possible
 	 * callback executions (e.g. bpf_loop) keeps track of current
 	 * simulated iteration number.
@@ -1796,6 +1801,8 @@ struct bpf_call_arg_meta {
 	u32 kfunc_flags;
 	const char *func_name;
 	struct arg_constant_desc arg_constant;
+	/* The type of the dynptr that the kfunc writes through */
+	enum bpf_dynptr_type dynptr_write_type;
 
 	/* arg_{btf,btf_id,owning_ref} are used by kfunc-specific handling,
 	 * generally to pass info about user-defined local kptr types to later
diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
index b40eb404adab9..5fd376bd210b0 100644
--- a/kernel/bpf/bpf_iter.c
+++ b/kernel/bpf/bpf_iter.c
@@ -72,6 +72,15 @@ static inline bool bpf_iter_target_support_resched(const struct bpf_iter_target_
 	return tinfo->reg_info->feature & BPF_ITER_RESCHED;
 }
 
+/* Only allow sleepable program for resched-able iterator that can run one */
+static bool bpf_iter_target_support_prog(const struct bpf_iter_target_info *tinfo,
+					 const struct bpf_prog *prog)
+{
+	return !prog->sleepable ||
+	       (bpf_iter_target_support_resched(tinfo) &&
+		!(tinfo->reg_info->feature & BPF_ITER_NOSLEEP));
+}
+
 static bool bpf_iter_support_resched(struct seq_file *seq)
 {
 	struct bpf_iter_priv_data *iter_priv;
@@ -342,6 +351,13 @@ int bpf_iter_prog_supported(struct bpf_prog *prog)
 	const char *prefix = BPF_ITER_FUNC_PREFIX;
 	int prefix_len = strlen(prefix);
 
+	/*
+	 * The attach function of an extension is a subprogram of the iterator
+	 * program that it extends, whatever its name is.
+	 */
+	if (prog->type == BPF_PROG_TYPE_EXT)
+		return -EINVAL;
+
 	if (strncmp(attach_fname, prefix, prefix_len))
 		return -EINVAL;
 
@@ -409,6 +425,8 @@ static int bpf_iter_link_replace(struct bpf_link *link,
 				 struct bpf_prog *new_prog,
 				 struct bpf_prog *old_prog)
 {
+	struct bpf_iter_link *iter_link =
+		container_of(link, struct bpf_iter_link, link);
 	int ret = 0;
 
 	mutex_lock(&link_mutex);
@@ -419,11 +437,19 @@ static int bpf_iter_link_replace(struct bpf_link *link,
 
 	if (link->prog->type != new_prog->type ||
 	    link->prog->expected_attach_type != new_prog->expected_attach_type ||
-	    link->prog->aux->attach_btf_id != new_prog->aux->attach_btf_id) {
+	    link->prog->aux->attach_btf_id != new_prog->aux->attach_btf_id ||
+	    !bpf_iter_target_support_prog(iter_link->tinfo, new_prog)) {
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 
+	if (iter_link->tinfo->reg_info->check_prog) {
+		ret = iter_link->tinfo->reg_info->check_prog(new_prog,
+							     &iter_link->aux);
+		if (ret)
+			goto out_unlock;
+	}
+
 	old_prog = xchg(&link->prog, new_prog);
 	bpf_prog_put(old_prog);
 
@@ -544,8 +570,7 @@ int bpf_iter_link_attach(const union bpf_attr *attr, bpfptr_t uattr,
 	if (!tinfo)
 		return -ENOENT;
 
-	/* Only allow sleepable program for resched-able iterator */
-	if (prog->sleepable && !bpf_iter_target_support_resched(tinfo))
+	if (!bpf_iter_target_support_prog(tinfo, prog))
 		return -EINVAL;
 
 	link = kzalloc_obj(*link, GFP_USER | __GFP_NOWARN);
diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c
index 4642da062f0f8..3d0c455d258c2 100644
--- a/kernel/bpf/bpf_local_storage.c
+++ b/kernel/bpf/bpf_local_storage.c
@@ -199,7 +199,7 @@ static void bpf_selem_unlink_storage_nolock_misc(struct bpf_local_storage_elem *
 	}
 
 	if (pin_owner)
-		refcount_dec(&local_storage->owner_refcnt);
+		bpf_local_storage_unpin_owner(local_storage);
 }
 
 /* local_storage->lock must be held and selem->local_storage == local_storage.
@@ -352,7 +352,7 @@ int bpf_selem_unlink(struct bpf_local_storage_elem *selem)
 static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,
 				    struct bpf_local_storage_map_bucket *b)
 {
-	bool in_map_free = !!b, free_storage = false;
+	bool in_map_free = !!b, free_storage = false, sleepable_users = false;
 	struct bpf_local_storage *local_storage;
 	struct bpf_local_storage_map *smap;
 	unsigned long flags;
@@ -362,6 +362,10 @@ static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,
 	smap = rcu_dereference_check(SDATA(selem)->smap, bpf_rcu_lock_held());
 
 	if (smap) {
+		/* A map that is freed, or NULL here, has no program left. */
+		sleepable_users = !in_map_free &&
+				  (atomic64_read(&smap->map.sleepable_refcnt) ||
+				   READ_ONCE(smap->map.was_inner_map));
 		b = b ? : select_bucket(smap, local_storage);
 		err = raw_res_spin_lock_irqsave(&b->lock, flags);
 		if (!err) {
@@ -431,13 +435,18 @@ static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,
 	 * then freed after an RCU grace period. However, if destroy() and map_free() are
 	 * racing or rqspinlock returns errors in unlikely situations (unlink != 2), free
 	 * the selem only after both map_free() and destroy() see the selem.
+	 *
+	 * The owner that map_free() takes an selem from is alive: sleepable code, which
+	 * is in no RCU read side critical section, may be walking its list for another
+	 * map.  And it can still use a value that it got before it let go of an owner
+	 * that destroy() is called for.
 	 */
 	if (unlink == 2 ||
 	    atomic_cmpxchg(&selem->state, SELEM_UNLINKED, SELEM_TOFREE) == SELEM_UNLINKED)
-		bpf_selem_free(selem, true);
+		bpf_selem_free(selem, !in_map_free && !sleepable_users);
 
 	if (free_storage)
-		bpf_local_storage_free(local_storage, true);
+		bpf_local_storage_free(local_storage, !in_map_free);
 }
 
 void __bpf_local_storage_insert_cache(struct bpf_local_storage *local_storage,
@@ -753,8 +762,8 @@ u32 bpf_local_storage_destroy(struct bpf_local_storage *local_storage)
 		while (refcount_read(&local_storage->owner_refcnt))
 			cpu_relax();
 		/*
-		 * Paired with refcount_dec() in bpf_selem_unlink_nofail()
-		 * to make sure destroy() sees the correct local_storage->mem_charge.
+		 * Paired with bpf_local_storage_unpin_owner() to make sure
+		 * destroy() sees the correct local_storage->mem_charge.
 		 */
 		smp_mb();
 	}
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 64c78434fa050..a9bf4c3c0a273 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -1081,6 +1081,8 @@ static const struct btf_type *btf_type_skip_qualifiers(const struct btf *btf,
 }
 
 #define BTF_SHOW_MAX_ITER	10
+/* nested structs and arrays shown; __btf_show_indent() has as many columns */
+#define BTF_SHOW_MAX_DEPTH	32
 
 #define BTF_KIND_BIT(kind)	(1ULL << kind)
 
@@ -1474,8 +1476,18 @@ static void *btf_show_start_aggr_type(struct btf_show *show,
 				      const struct btf_type *t,
 				      u32 type_id, void *data)
 {
-	void *safe_data = btf_show_start_type(show, t, type_id, data);
+	void *safe_data;
 
+	/*
+	 * Structs and arrays are shown by recursion.  BTF loading bounds the
+	 * depth of one resolve walk, not how deep resolved types may nest.
+	 */
+	if (show->state.depth >= BTF_SHOW_MAX_DEPTH) {
+		show->state.status = -E2BIG;
+		return NULL;
+	}
+
+	safe_data = btf_show_start_type(show, t, type_id, data);
 	if (!safe_data)
 		return safe_data;
 
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index bce7b5abcfda3..2ee950e9ac829 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -598,7 +598,9 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
 			 */
 			if (ret == 0 && fp->might_sleep)
 				mark_subprog_might_sleep(env, t);
-			if (bpf_helper_changes_pkt_data(insn->imm))
+			/* nobody knows yet whether the dynptr is that of an skb */
+			if (bpf_helper_changes_pkt_data(insn->imm) ||
+			    insn->imm == BPF_FUNC_dynptr_write)
 				mark_subprog_changes_pkt_data(env, t);
 		} else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
 			struct bpf_call_arg_meta meta;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 642f0ab8eb2d8..956555fc5e9f5 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -269,6 +269,8 @@ struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
 		memcpy(fp, fp_old, fp_old->pages * PAGE_SIZE);
 		fp->pages = pages;
 		fp->aux->prog = fp;
+		if (fp->aux->offload)
+			fp->aux->offload->prog = fp;
 
 		/* We keep fp->aux from fp_old around in the new
 		 * reallocated structure.
@@ -3042,7 +3044,7 @@ void __bpf_free_used_maps(struct bpf_prog_aux *aux,
 	bool sleepable;
 	u32 i;
 
-	sleepable = aux->prog->sleepable;
+	sleepable = bpf_prog_runs_sleepable(aux->prog);
 	for (i = 0; i < len; i++) {
 		map = used_maps[i];
 		if (map->ops->map_poke_untrack)
@@ -3085,12 +3087,40 @@ static void bpf_free_used_btfs(struct bpf_prog_aux *aux)
 	kfree(aux->used_btfs);
 }
 
-static void bpf_prog_free_deferred(struct work_struct *work)
+static void bpf_prog_free_images(struct work_struct *work)
 {
 	struct bpf_prog_aux *aux;
 	int i;
 
+	aux = container_of(to_rcu_work(work), struct bpf_prog_aux, rwork);
+	for (i = 0; i < aux->real_func_cnt; i++) {
+		/* We can just unlink the subprog poke descriptor table as
+		 * it was originally linked to the main program and is also
+		 * released along with it.
+		 */
+		aux->func[i]->aux->poke_tab = NULL;
+		bpf_jit_free(aux->func[i]);
+	}
+	if (aux->real_func_cnt) {
+		kfree(aux->func);
+		bpf_prog_unlock_free(aux->prog);
+	} else {
+		bpf_jit_free(aux->prog);
+	}
+}
+
+static void bpf_prog_free_deferred(struct work_struct *work)
+{
+	struct bpf_prog_aux *aux;
+	bool ksyms;
+
 	aux = container_of(work, struct bpf_prog_aux, work);
+	/*
+	 * A prog that still runs when its last reference goes needs its symbols,
+	 * by which its exception table is found.  It has ended by now.
+	 */
+	ksyms = aux->real_func_cnt || !list_empty(&aux->ksym.lnode);
+	bpf_prog_kallsyms_del_all(aux->prog);
 #ifdef CONFIG_BPF_SYSCALL
 	bpf_free_kfunc_btf_tab(aux->kfunc_btf_tab);
 #endif
@@ -3109,20 +3139,12 @@ static void bpf_prog_free_deferred(struct work_struct *work)
 #endif
 	if (aux->dst_trampoline)
 		bpf_trampoline_put(aux->dst_trampoline);
-	for (i = 0; i < aux->real_func_cnt; i++) {
-		/* We can just unlink the subprog poke descriptor table as
-		 * it was originally linked to the main program and is also
-		 * released along with it.
-		 */
-		aux->func[i]->aux->poke_tab = NULL;
-		bpf_jit_free(aux->func[i]);
-	}
-	if (aux->real_func_cnt) {
-		kfree(aux->func);
-		bpf_prog_unlock_free(aux->prog);
-	} else {
-		bpf_jit_free(aux->prog);
-	}
+	/* The symbols are looked up under rcu_read_lock() */
+	INIT_RCU_WORK(&aux->rwork, bpf_prog_free_images);
+	if (ksyms)
+		queue_rcu_work(system_percpu_wq, &aux->rwork);
+	else
+		bpf_prog_free_images(&aux->rwork.work);
 }
 
 void bpf_prog_free(struct bpf_prog *fp)
diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
index 5e59ab896f058..eb87131b1bef5 100644
--- a/kernel/bpf/cpumap.c
+++ b/kernel/bpf/cpumap.c
@@ -45,6 +45,7 @@
  */
 
 #define CPU_MAP_BULK_SIZE 8  /* 8 == one cacheline on 64-bit archs */
+#define CPU_MAP_HELD_DEVS 2048
 struct bpf_cpu_map_entry;
 struct bpf_cpu_map;
 
@@ -74,6 +75,13 @@ struct bpf_cpu_map_entry {
 
 	struct completion kthread_running;
 	struct rcu_work free_work;
+
+	/*
+	 * Every frame and skb in the queue holds a reference to its device.
+	 * The kthread keeps it until nothing is left in GRO.
+	 */
+	struct net_device *held[CPU_MAP_HELD_DEVS];
+	u32 nr_held;
 };
 
 struct bpf_cpu_map {
@@ -129,9 +137,11 @@ static void __cpu_map_ring_cleanup(struct ptr_ring *ring)
 		WARN_ON_ONCE(1);
 		if (unlikely(__ptr_test_bit(0, &ptr))) {
 			__ptr_clear_bit(0, &ptr);
+			dev_put(((struct sk_buff *)ptr)->dev);
 			kfree_skb(ptr);
 			continue;
 		}
+		dev_put(((struct xdp_frame *)ptr)->dev_rx);
 		xdp_return_frame(ptr);
 	}
 }
@@ -311,7 +321,7 @@ static int cpu_map_kthread_run(void *data)
 		void *frames[CPUMAP_BATCH];
 		void *skbs[CPUMAP_BATCH];
 		u32 i, n, m;
-		bool empty;
+		bool empty, full;
 
 		/* Release CPU reschedule checks */
 		if (__ptr_ring_empty(rcpu->queue)) {
@@ -344,10 +354,12 @@ static int cpu_map_kthread_run(void *data)
 				struct sk_buff *skb = f;
 
 				__ptr_clear_bit(0, &skb);
+				rcpu->held[rcpu->nr_held++] = skb->dev;
 				skbs[ret.skb_n++] = skb;
 				continue;
 			}
 
+			rcpu->held[rcpu->nr_held++] = ((struct xdp_frame *)f)->dev_rx;
 			frames[ret.xdp_n++] = f;
 			page = virt_to_page(f);
 
@@ -398,10 +410,13 @@ static int cpu_map_kthread_run(void *data)
 		/* Flush either every 64 packets or in case of empty ring */
 		packets += n;
 		empty = __ptr_ring_empty(rcpu->queue);
-		if (packets >= NAPI_POLL_WEIGHT || empty) {
-			cpu_map_gro_flush(rcpu, empty);
+		full = empty || rcpu->nr_held > CPU_MAP_HELD_DEVS - CPUMAP_BATCH;
+		if (packets >= NAPI_POLL_WEIGHT || full) {
+			cpu_map_gro_flush(rcpu, full);
 			packets = 0;
 		}
+		while (full && rcpu->nr_held)
+			dev_put(rcpu->held[--rcpu->nr_held]);
 
 		local_bh_enable(); /* resched point, may call do_softirq() */
 	}
@@ -738,12 +753,14 @@ static void bq_flush_to_queue(struct xdp_bulk_queue *bq)
 
 	for (i = 0; i < bq->count; i++) {
 		struct xdp_frame *xdpf = bq->q[i];
-		int err;
 
-		err = __ptr_ring_produce(q, xdpf);
-		if (err) {
+		if (__ptr_ring_full(q)) {
 			drops++;
 			xdp_return_frame_rx_napi(xdpf);
+		} else {
+			/* The device cannot go before the flush, from now on it can */
+			dev_hold(xdpf->dev_rx);
+			__ptr_ring_produce(q, xdpf);
 		}
 		processed++;
 	}
@@ -807,11 +824,15 @@ int cpu_map_generic_redirect(struct bpf_cpu_map_entry *rcpu,
 
 	__skb_pull(skb, skb->mac_len);
 	skb_set_redirected(skb, false);
+	dev_hold(skb->dev);
 	__ptr_set_bit(0, &skb);
 
 	ret = ptr_ring_produce(rcpu->queue, skb);
-	if (ret < 0)
+	if (ret < 0) {
+		__ptr_clear_bit(0, &skb);
+		dev_put(skb->dev);
 		goto trace;
+	}
 
 	wake_up_process(rcpu->kthread);
 trace:
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index dc7b859e8bbfd..1b8f0d7f84552 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -350,6 +350,7 @@ static int dev_map_bpf_prog_run(struct bpf_prog *xdp_prog,
 
 		xdp_convert_frame_to_buff(xdpf, &xdp);
 		xdp.txq = &txq;
+		rxq.mem.type = xdpf->mem_type;
 		xdp.rxq = &rxq;
 
 		act = bpf_prog_run_xdp(xdp_prog, &xdp);
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 608621d7f225c..fe59e3114d828 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -2151,6 +2151,10 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
 			if (!bpf_allow_tail_call_in_subprogs(env))
 				prog->aux->stack_depth = MAX_BPF_STACK;
 			prog->aux->max_pkt_offset = MAX_PACKET_OFF;
+			prog->aux->max_rdonly_access = U32_MAX;
+			prog->aux->max_rdwr_access = U32_MAX;
+			if (prog->type == BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE)
+				prog->aux->max_tp_access = U32_MAX;
 
 			/* mark bpf_tail_call as different opcode to avoid
 			 * conditional branch in the interpreter for every normal
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index 9d4791ee17411..923fec694747b 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -1279,11 +1279,17 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
 	if (prealloc) {
 		if (old_elem) {
 			/* if we're updating the existing element,
-			 * use per-cpu extra elems to avoid freelist_pop/push
+			 * use per-cpu extra elems to avoid freelist_pop/push.
+			 * The caller puts old_elem into the slot once it is
+			 * unlinked. Until then the slot is empty for an NMI
+			 * or a kprobe that updates this map on this cpu.
 			 */
 			pl_new = this_cpu_ptr(htab->extra_elems);
-			l_new = *pl_new;
-			*pl_new = old_elem;
+			l_new = READ_ONCE(*pl_new);
+			do {
+				if (!l_new)
+					return ERR_PTR(-EBUSY);
+			} while (!try_cmpxchg_local(pl_new, &l_new, NULL));
 		} else {
 			struct pcpu_freelist_node *l;
 
@@ -1459,11 +1465,14 @@ static long htab_map_update_elem(struct bpf_map *map, void *key, void *value,
 	if (l_old) {
 		hlist_nulls_del_rcu(&l_old->hash_node);
 
-		/* l_old has already been stashed in htab->extra_elems, cancel
-		 * its reusable special fields before it is available for reuse.
+		/* l_old replaces the extra element that alloc_htab_elem() took,
+		 * cancel its reusable special fields before the next update on
+		 * this cpu reuses it.
 		 */
-		if (htab_is_prealloc(htab))
+		if (htab_is_prealloc(htab)) {
+			WRITE_ONCE(*this_cpu_ptr(htab->extra_elems), l_old);
 			check_and_cancel_fields(htab, l_old);
+		}
 	}
 	htab_unlock_bucket(b, flags);
 	if (l_old && !htab_is_prealloc(htab))
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 439370d73cc5f..648abe1ba63ae 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -1262,18 +1262,21 @@ static void bpf_wq_work(struct work_struct *work)
 
 	BTF_TYPE_EMIT(struct bpf_wq);
 
+	/* keeps the program that callback_fn belongs to */
+	rcu_read_lock_trace();
+
 	callback_fn = READ_ONCE(cb->callback_fn);
 	if (!callback_fn)
-		return;
+		goto out;
 
 	key = map_key_from_value(map, value, &idx);
 
-        rcu_read_lock_trace();
-        migrate_disable();
+	migrate_disable();
 
 	callback_fn((u64)(long)map, (u64)(long)key, (u64)(long)value, 0, 0);
 
 	migrate_enable();
+out:
 	rcu_read_unlock_trace();
 }
 
diff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c
index 5ee8aae7435ba..0fa3f2ac0f992 100644
--- a/kernel/bpf/map_in_map.c
+++ b/kernel/bpf/map_in_map.c
@@ -110,10 +110,13 @@ void *bpf_map_fd_get_ptr(struct bpf_map *map,
 		return ERR_PTR(-ENOTSUPP);
 
 	inner_map_meta = map->inner_map_meta;
-	if (inner_map_meta->ops->map_meta_equal(inner_map_meta, inner_map))
+	if (inner_map_meta->ops->map_meta_equal(inner_map_meta, inner_map)) {
 		bpf_map_inc(inner_map);
-	else
+		/* Its users are those of the outer maps from now on */
+		WRITE_ONCE(inner_map->was_inner_map, true);
+	} else {
 		inner_map = ERR_PTR(-EINVAL);
+	}
 
 	return inner_map;
 }
diff --git a/kernel/bpf/map_iter.c b/kernel/bpf/map_iter.c
index 2077d46d167c7..a58c148692e6c 100644
--- a/kernel/bpf/map_iter.c
+++ b/kernel/bpf/map_iter.c
@@ -97,13 +97,57 @@ static struct bpf_iter_reg bpf_map_reg_info = {
 	.seq_info		= &bpf_map_seq_info,
 };
 
+/*
+ * For an iterator that hands the live map value to the program as a writable
+ * buffer: the verifier knows nothing of the map, so the special fields of the
+ * value have to lie outside of what the program may write.
+ */
+int bpf_iter_map_check_value_write(const struct bpf_prog *prog,
+				   const struct bpf_map *map)
+{
+	const struct btf_record *rec = map->record;
+	const struct btf_field *field;
+	u32 i;
+
+	if (IS_ERR_OR_NULL(rec) || !prog->aux->max_rdwr_write)
+		return 0;
+
+	for (i = 0; i < rec->cnt; i++) {
+		field = &rec->fields[i];
+		if (field->offset < prog->aux->max_rdwr_write &&
+		    field->offset + field->size > prog->aux->min_rdwr_write)
+			return -EACCES;
+	}
+
+	return 0;
+}
+
+static int bpf_iter_map_check_prog(const struct bpf_prog *prog,
+				   const struct bpf_iter_aux_info *aux)
+{
+	const struct bpf_map *map = aux->map;
+	u32 value_size = map->value_size;
+	bool is_percpu;
+
+	is_percpu = map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
+		    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
+		    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
+	if (is_percpu)
+		value_size = round_up(value_size, 8) * num_possible_cpus();
+
+	if (prog->aux->max_rdonly_access > map->key_size ||
+	    prog->aux->max_rdwr_access > value_size)
+		return -EACCES;
+
+	/* the program gets a copy of a per-cpu value */
+	return is_percpu ? 0 : bpf_iter_map_check_value_write(prog, map);
+}
+
 static int bpf_iter_attach_map(struct bpf_prog *prog,
 			       union bpf_iter_link_info *linfo,
 			       struct bpf_iter_aux_info *aux)
 {
-	u32 key_acc_size, value_acc_size, key_size, value_size;
 	struct bpf_map *map;
-	bool is_percpu = false;
 	int err = -EINVAL;
 
 	if (!linfo->map.map_fd)
@@ -123,30 +167,20 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,
 		goto put_map;
 	}
 
-	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
-	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
-	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
-		is_percpu = true;
-	else if (map->map_type != BPF_MAP_TYPE_HASH &&
-		 map->map_type != BPF_MAP_TYPE_LRU_HASH &&
-		 map->map_type != BPF_MAP_TYPE_ARRAY &&
-		 map->map_type != BPF_MAP_TYPE_RHASH)
+	if (map->map_type != BPF_MAP_TYPE_PERCPU_HASH &&
+	    map->map_type != BPF_MAP_TYPE_LRU_PERCPU_HASH &&
+	    map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY &&
+	    map->map_type != BPF_MAP_TYPE_HASH &&
+	    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
+	    map->map_type != BPF_MAP_TYPE_ARRAY &&
+	    map->map_type != BPF_MAP_TYPE_RHASH)
 		goto put_map;
 
-	key_acc_size = prog->aux->max_rdonly_access;
-	value_acc_size = prog->aux->max_rdwr_access;
-	key_size = map->key_size;
-	if (!is_percpu)
-		value_size = map->value_size;
-	else
-		value_size = round_up(map->value_size, 8) * num_possible_cpus();
-
-	if (key_acc_size > key_size || value_acc_size > value_size) {
-		err = -EACCES;
+	aux->map = map;
+	err = bpf_iter_map_check_prog(prog, aux);
+	if (err)
 		goto put_map;
-	}
 
-	aux->map = map;
 	return 0;
 
 put_map:
@@ -179,6 +213,7 @@ static const struct bpf_iter_reg bpf_map_elem_reg_info = {
 	.target			= "bpf_map_elem",
 	.attach_target		= bpf_iter_attach_map,
 	.detach_target		= bpf_iter_detach_map,
+	.check_prog		= bpf_iter_map_check_prog,
 	.show_fdinfo		= bpf_iter_map_show_fdinfo,
 	.fill_link_info		= bpf_iter_map_fill_link_info,
 	.ctx_arg_info_size	= 2,
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
index d855399812eec..c615ed46f6293 100644
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@ -250,7 +250,14 @@ int bpf_prog_dev_bound_init(struct bpf_prog *prog, union bpf_attr *attr)
 	prog->aux->offload_requested = !(attr->prog_flags & BPF_F_XDP_DEV_BOUND_ONLY);
 
 	down_write(&bpf_devs_lock);
-	err = __bpf_prog_dev_bound_init(prog, netdev);
+	/*
+	 * Behind bpf_dev_bound_netdev_unregister() nobody would take the
+	 * program off the device, which goes once the reference is dropped.
+	 */
+	if (READ_ONCE(netdev->reg_state) == NETREG_REGISTERED)
+		err = __bpf_prog_dev_bound_init(prog, netdev);
+	else
+		err = -EINVAL;
 	up_write(&bpf_devs_lock);
 
 out:
diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 953700822fa73..b3d250caaaa65 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -995,6 +995,9 @@ static bool func_states_equal(struct bpf_verifier_env *env, struct bpf_func_stat
 	if (!old->no_stack_arg_load && cur->no_stack_arg_load)
 		return false;
 
+	if (old->in_rcu_callback_fn != cur->in_rcu_callback_fn)
+		return false;
+
 	for (i = 0; i < MAX_BPF_REG; i++)
 		if (((1 << i) & live_regs) &&
 		    !regsafe(env, &old->regs[i], &cur->regs[i],
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 654f896af265b..c8bd92c95ac02 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2461,6 +2461,8 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu)
 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
 
 	btf_put(aux->btf);
+	kvfree(aux->jited_linfo);
+	kvfree(aux->linfo);
 	kvfree(aux->func_info);
 	kfree(aux->func_info_aux);
 	free_uid(aux->user);
@@ -2477,7 +2479,7 @@ static void __bpf_prog_put_rcu_tasks(struct rcu_head *rcu)
 {
 	struct bpf_prog *prog = container_of(rcu, struct bpf_prog_aux, rcu)->prog;
 
-	if (prog->sleepable)
+	if (bpf_prog_runs_sleepable(prog))
 		call_rcu_tasks_trace(rcu, __bpf_prog_put_rcu);
 	else
 		call_rcu(rcu, __bpf_prog_put_rcu);
@@ -2485,10 +2487,7 @@ static void __bpf_prog_put_rcu_tasks(struct rcu_head *rcu)
 
 static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
 {
-	bpf_prog_kallsyms_del_all(prog);
 	module_put(prog->aux->mod);
-	kvfree(prog->aux->jited_linfo);
-	kvfree(prog->aux->linfo);
 	kfree(prog->aux->kfunc_tab);
 	kfree(prog->aux->ctx_arg_info);
 	if (prog->aux->attach_btf)
@@ -2497,7 +2496,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
 	if (deferred) {
 		if (IS_ENABLED(CONFIG_TASKS_RCU) && prog->aux->tramp_linked)
 			call_rcu_tasks(&prog->aux->rcu, __bpf_prog_put_rcu_tasks);
-		else if (prog->sleepable)
+		else if (bpf_prog_runs_sleepable(prog))
 			call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu);
 		else
 			call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
@@ -4020,19 +4019,19 @@ static int bpf_perf_link_fill_common(const struct perf_event *event,
 		*ulenp = 1;
 	}
 	if (!uname)
-		return 0;
+		goto out;
 
 	if (buf) {
 		err = bpf_copy_to_user(uname, buf, ulen, len);
-		if (err)
-			return err;
 	} else {
 		char zero = '\0';
 
 		if (put_user(zero, uname))
-			return -EFAULT;
+			err = -EFAULT;
 	}
-	return 0;
+out:
+	kfree_const(buf);
+	return err;
 }
 
 #ifdef CONFIG_KPROBE_EVENTS
@@ -4089,6 +4088,7 @@ static void bpf_perf_link_fdinfo_kprobe(const struct perf_event *event,
 		   name, offset, missed, addr,
 		   type == BPF_FD_TYPE_KRETPROBE ?  "kretprobe" : "kprobe",
 		   event->bpf_cookie);
+	kfree_const(name);
 }
 #endif
 
@@ -4142,6 +4142,7 @@ static void bpf_perf_link_fdinfo_uprobe(const struct perf_event *event,
 		   name, offset, ref_ctr_offset,
 		   type == BPF_FD_TYPE_URETPROBE ?  "uretprobe" : "uprobe",
 		   event->bpf_cookie);
+	kfree_const(name);
 }
 #endif
 
@@ -4240,6 +4241,7 @@ static void bpf_tracepoint_link_show_fdinfo(const struct perf_event *event,
 		   "event_type:\t%s\n"
 		   "cookie:\t%llu\n",
 		   name, "tracepoint", event->bpf_cookie);
+	kfree_const(name);
 }
 
 static void bpf_probe_link_show_fdinfo(const struct perf_event *event,
@@ -5763,11 +5765,13 @@ static int bpf_task_fd_query(const union bpf_attr *attr,
 		err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
 					      &buf, &probe_offset,
 					      &probe_addr, NULL);
-		if (!err)
+		if (!err) {
 			err = bpf_task_fd_query_copy(attr, uattr, prog_id,
 						     fd_type, buf,
 						     probe_offset,
 						     probe_addr);
+			kfree_const(buf);
+		}
 		goto put_file;
 	}
 
@@ -6248,7 +6252,7 @@ static int bpf_prog_bind_map(union bpf_attr *attr)
 	/* The bpf program will not access the bpf map, but for the sake of
 	 * simplicity, increase sleepable_refcnt for sleepable program as well.
 	 */
-	if (prog->sleepable)
+	if (bpf_prog_runs_sleepable(prog))
 		atomic64_inc(&map->sleepable_refcnt);
 	memcpy(used_maps_new, used_maps_old,
 	       sizeof(used_maps_old[0]) * prog->aux->used_map_cnt);
diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
index 13e1aabe6f886..2fa6b8dae8c4f 100644
--- a/kernel/bpf/task_iter.c
+++ b/kernel/bpf/task_iter.c
@@ -737,7 +737,11 @@ static const struct bpf_iter_seq_info task_vma_seq_info = {
 static struct bpf_iter_reg task_vma_reg_info = {
 	.target			= "task_vma",
 	.attach_target		= bpf_iter_attach_task,
-	.feature		= BPF_ITER_RESCHED,
+	/*
+	 * ->show() runs with the mmap_lock of the iterated mm held, which a
+	 * sleepable program takes again when it faults on user memory.
+	 */
+	.feature		= BPF_ITER_RESCHED | BPF_ITER_NOSLEEP,
 	.ctx_arg_info_size	= 2,
 	.ctx_arg_info		= {
 		{ offsetof(struct bpf_iter__task_vma, task),
@@ -806,8 +810,14 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
 	vma = find_vma(mm, start);
 
 	if (vma && vma->vm_start <= start && vma->vm_end > start) {
+		/*
+		 * The callback must not sleep while mmap_lock is held, and the
+		 * verifier checks it as an RCU read-side critical section.
+		 */
+		rcu_read_lock();
 		callback_fn((u64)(long)task, (u64)(long)vma,
 			    (u64)(long)callback_ctx, 0, 0);
+		rcu_read_unlock();
 		ret = 0;
 	}
 	bpf_mmap_unlock_mm(work, mm);
diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c
index e85a179523f02..19660ef95ddbd 100644
--- a/kernel/bpf/token.c
+++ b/kernel/bpf/token.c
@@ -169,8 +169,11 @@ int bpf_token_create(union bpf_attr *attr)
 	FD_PREPARE(fdf, O_CLOEXEC,
 		   alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME,
 				     O_RDWR, &bpf_token_fops));
-	if (fdf.err)
+	if (fdf.err) {
+		/* no file took over the inode reference */
+		iput(inode);
 		return fdf.err;
+	}
 
 	token = kzalloc_obj(*token, GFP_USER);
 	if (!token)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index ddfa0c6d2755f..1cf7f2e57a161 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -219,6 +219,7 @@ static int ref_set_non_owning(struct bpf_verifier_env *env,
 			      struct bpf_reg_state *reg);
 static bool is_trusted_reg(struct bpf_verifier_env *env, const struct bpf_reg_state *reg);
 static inline bool in_sleepable_context(struct bpf_verifier_env *env);
+static bool in_rcu_callback(struct bpf_verifier_env *env);
 static const char *non_sleepable_context_description(struct bpf_verifier_env *env);
 static void scalar32_min_max_add(struct bpf_reg_state *dst_reg, struct bpf_reg_state *src_reg);
 static void scalar_min_max_add(struct bpf_reg_state *dst_reg, struct bpf_reg_state *src_reg);
@@ -593,6 +594,19 @@ static bool is_async_cb_sleepable(struct bpf_verifier_env *env, struct bpf_insn
 	return false;
 }
 
+/* From here on the maps of the program count it as a sleepable user. */
+static void mark_sleepable_async_cb(struct bpf_verifier_env *env)
+{
+	int i;
+
+	if (bpf_prog_runs_sleepable(env->prog))
+		return;
+
+	env->prog->aux->sleepable_async_cb = true;
+	for (i = 0; i < env->used_map_cnt; i++)
+		atomic64_inc(&env->used_maps[i]->sleepable_refcnt);
+}
+
 bool bpf_is_may_goto_insn(struct bpf_insn *insn)
 {
 	return insn->code == (BPF_JMP | BPF_JCOND) && insn->src_reg == BPF_MAY_GOTO;
@@ -988,6 +1002,11 @@ static enum bpf_dynptr_type dynptr_reg_type(struct bpf_verifier_env *env, struct
 	return bpf_stack_slot(state, spi)->spilled_ptr.dynptr.type;
 }
 
+static bool dynptr_write_changes_pkt_data(enum bpf_dynptr_type type)
+{
+	return type == BPF_DYNPTR_TYPE_SKB || type == BPF_DYNPTR_TYPE_SKB_META;
+}
+
 static bool is_dynptr_type_expected(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
 				    enum bpf_arg_type arg_type)
 {
@@ -6039,9 +6058,10 @@ static int check_buffer_access(struct bpf_verifier_env *env,
 			       const struct bpf_reg_state *reg,
 			       argno_t argno, int off, int size,
 			       bool zero_size_allowed,
-			       u32 *max_access)
+			       u32 *max_access, bool write)
 {
 	const char *buf_info = type_is_rdonly_mem(reg->type) ? "rdonly" : "rdwr";
+	struct bpf_prog_aux *aux = env->prog->aux;
 	u32 access_end;
 	int err;
 
@@ -6050,6 +6070,11 @@ static int check_buffer_access(struct bpf_verifier_env *env,
 		return err;
 
 	*max_access = max(access_end, *max_access);
+	if (write && size) {
+		if (!aux->max_rdwr_write || access_end - size < aux->min_rdwr_write)
+			aux->min_rdwr_write = access_end - size;
+		aux->max_rdwr_write = max(access_end, aux->max_rdwr_write);
+	}
 
 	return 0;
 }
@@ -7325,7 +7350,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
 		}
 
 		err = check_buffer_access(env, reg, argno, off, size, false,
-					  max_access);
+					  max_access, t == BPF_WRITE);
 
 		if (!err && value_regno >= 0 && (rdonly_mem || t == BPF_READ))
 			mark_reg_unknown(env, regs, value_regno);
@@ -7838,7 +7863,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, struct bpf_reg_
 		}
 		return check_buffer_access(env, reg, argno, 0,
 					   access_size, zero_size_allowed,
-					   max_access);
+					   max_access, access_type == BPF_WRITE);
 	case PTR_TO_STACK:
 		return check_stack_range_initialized(
 				env, reg,
@@ -8391,6 +8416,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
 			       argno_t argno, int insn_idx, enum bpf_arg_type arg_type,
 			       struct bpf_call_arg_meta *meta)
 {
+	bool is_arg = reg->type == CONST_PTR_TO_DYNPTR;
 	int spi, err = 0;
 
 	/*  MEM_UNINIT - Points to memory that is an appropriate candidate for
@@ -8477,7 +8503,12 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
 			reg = &bpf_stack_slot(state, spi)->spilled_ptr;
 		}
 
-		meta->dynptr.type = reg->dynptr.type;
+		/*
+		 * The callers of a global function may hand in a dynptr of any
+		 * type. Take it for that of an skb, so that a write through it
+		 * and its slices are treated with care.
+		 */
+		meta->dynptr.type = is_arg ? BPF_DYNPTR_TYPE_SKB : reg->dynptr.type;
 		meta->dynptr.id = reg->id;
 		meta->dynptr.parent_id = reg->parent_id;
 	}
@@ -8956,6 +8987,7 @@ static bool is_kfunc_arg_scalar_with_name(const struct btf *btf,
 static bool is_bpf_cast_to_kern_ctx_kfunc(const struct bpf_call_arg_meta *meta);
 static bool is_bpf_dynptr_clone_kfunc(const struct bpf_call_arg_meta *meta);
 static bool is_bpf_iter_css_task_new_kfunc(const struct bpf_call_arg_meta *meta);
+static bool is_kfunc_dynptr_write(struct bpf_call_arg_meta *meta);
 static bool is_bpf_obj_drop_kfunc(u32 func_id);
 static bool is_bpf_percpu_obj_drop_kfunc(u32 func_id);
 static bool is_bpf_rbtree_add_kfunc(u32 func_id);
@@ -9661,6 +9693,16 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p
 	if (err)
 		return err;
 
+	/*
+	 * A slice of a packet is packet data under another name. A helper which
+	 * may reallocate the packet must not go on reading from the old one.
+	 */
+	if (is_helper(meta) && reg_is_dynptr_slice_pkt(reg) &&
+	    bpf_helper_changes_pkt_data(meta->func_id)) {
+		verbose(env, "function access to the packet is not allowed\n");
+		return -EACCES;
+	}
+
 	if (arg_type_is_raw_mem(arg_type))
 		meta->arg_raw_mem.mask |= BIT(slot);
 
@@ -10020,6 +10062,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p
 		err = process_dynptr_func(env, reg, argno, insn_idx, arg_type, meta);
 		if (err)
 			return err;
+		if (!arg && is_kfunc_dynptr_write(meta))
+			meta->dynptr_write_type = meta->dynptr.type;
 		break;
 	}
 	case ARG_PTR_TO_ITER:
@@ -10366,12 +10410,57 @@ bool bpf_allow_tail_call_in_subprogs(struct bpf_verifier_env *env)
 	       bpf_jit_supports_subprog_tailcalls();
 }
 
+/* May the map be used outside of an RCU read side critical section? */
+static bool map_needs_no_rcu(const struct bpf_map *map)
+{
+	switch (map->map_type) {
+	case BPF_MAP_TYPE_HASH:
+	case BPF_MAP_TYPE_RHASH:
+	case BPF_MAP_TYPE_LRU_HASH:
+	case BPF_MAP_TYPE_ARRAY:
+	case BPF_MAP_TYPE_PERCPU_HASH:
+	case BPF_MAP_TYPE_PERCPU_ARRAY:
+	case BPF_MAP_TYPE_LRU_PERCPU_HASH:
+	case BPF_MAP_TYPE_LPM_TRIE:
+	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
+	case BPF_MAP_TYPE_HASH_OF_MAPS:
+	case BPF_MAP_TYPE_RINGBUF:
+	case BPF_MAP_TYPE_USER_RINGBUF:
+	case BPF_MAP_TYPE_INODE_STORAGE:
+	case BPF_MAP_TYPE_SK_STORAGE:
+	case BPF_MAP_TYPE_TASK_STORAGE:
+	case BPF_MAP_TYPE_CGRP_STORAGE:
+	case BPF_MAP_TYPE_QUEUE:
+	case BPF_MAP_TYPE_STACK:
+	case BPF_MAP_TYPE_ARENA:
+	case BPF_MAP_TYPE_INSN_ARRAY:
+	case BPF_MAP_TYPE_PROG_ARRAY:
+	case BPF_MAP_TYPE_BLOOM_FILTER:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static int check_map_func_compatibility(struct bpf_verifier_env *env,
 					struct bpf_map *map, int func_id)
 {
 	if (!map)
 		return 0;
 
+	/*
+	 * check_map_prog_compatibility() asks the program.  That misses the
+	 * sleepable callback of another program, and an inner map.  They may
+	 * use any map under the RCU read lock.  Disabled preemption or
+	 * interrupts will not do: the maps ask for rcu_read_lock_held().
+	 */
+	if (in_sleepable(env) && !env->cur_state->active_rcu_locks &&
+	    !in_rcu_callback(env) && !map_needs_no_rcu(map)) {
+		verbose(env, "map '%s' needs bpf_rcu_read_lock() in sleepable context\n",
+			map->name);
+		return -EINVAL;
+	}
+
 	/* We need a two way check, first is from map perspective ... */
 	switch (map->map_type) {
 	case BPF_MAP_TYPE_PROG_ARRAY:
@@ -11211,6 +11300,8 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins
 					 is_async_cb_sleepable(env, insn));
 		if (IS_ERR(async_cb))
 			return PTR_ERR(async_cb);
+		if (is_async_cb_sleepable(env, insn))
+			mark_sleepable_async_cb(env);
 		callee = async_cb->frame[0];
 		callee->async_entry_cnt = state->frame[0]->async_entry_cnt + 1;
 
@@ -11530,6 +11621,19 @@ static int set_map_elem_callback_state(struct bpf_verifier_env *env,
 	if (err)
 		return err;
 
+	switch (map->map_type) {
+	case BPF_MAP_TYPE_HASH:
+	case BPF_MAP_TYPE_PERCPU_HASH:
+	case BPF_MAP_TYPE_LRU_HASH:
+	case BPF_MAP_TYPE_LRU_PERCPU_HASH:
+	case BPF_MAP_TYPE_RHASH:
+		/* Hash tables run the callback under rcu_read_lock(). */
+		callee->in_rcu_callback_fn = true;
+		break;
+	default:
+		break;
+	}
+
 	callee->in_callback_fn = true;
 	callee->callback_ret_range = retval_range(0, 1);
 	return 0;
@@ -11616,6 +11720,8 @@ static int set_find_vma_callback_state(struct bpf_verifier_env *env,
 	bpf_mark_reg_not_init(env, &callee->regs[BPF_REG_4]);
 	bpf_mark_reg_not_init(env, &callee->regs[BPF_REG_5]);
 	callee->in_callback_fn = true;
+	/* bpf_find_vma() runs the callback under mmap_lock and RCU. */
+	callee->in_rcu_callback_fn = true;
 	callee->callback_ret_range = retval_range(0, 1);
 	return 0;
 }
@@ -12273,10 +12379,22 @@ int bpf_get_helper_proto(struct bpf_verifier_env *env, int func_id,
 	return *ptr && (*ptr)->func ? 0 : -EINVAL;
 }
 
+/* Is any frame on the current path a callback that runs under RCU? */
+static bool in_rcu_callback(struct bpf_verifier_env *env)
+{
+	struct bpf_verifier_state *state = env->cur_state;
+	int i;
+
+	for (i = 0; i <= state->curframe; i++)
+		if (state->frame[i]->in_rcu_callback_fn)
+			return true;
+	return false;
+}
+
 /* Check if we're in a sleepable context. */
 static inline bool in_sleepable_context(struct bpf_verifier_env *env)
 {
-	return !in_rcu_cs(env);
+	return !in_rcu_cs(env) && !in_rcu_callback(env);
 }
 
 static const char *non_sleepable_context_description(struct bpf_verifier_env *env)
@@ -12290,6 +12408,7 @@ static const char *non_sleepable_context_description(struct bpf_verifier_env *en
 			return "IRQ-disabled region";
 		if (env->cur_state->active_locks)
 			return "lock region";
+		return "callback running under rcu_read_lock";
 	}
 	return "non-sleepable prog";
 }
@@ -12540,8 +12659,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 		if (dynptr_type == BPF_DYNPTR_TYPE_INVALID)
 			return -EFAULT;
 
-		if (dynptr_type == BPF_DYNPTR_TYPE_SKB ||
-		    dynptr_type == BPF_DYNPTR_TYPE_SKB_META)
+		if (dynptr_write_changes_pkt_data(dynptr_type))
 			/* this will trigger clear_all_pkt_pointers(), which will
 			 * invalidate all dynptr slices associated with the skb
 			 */
@@ -13590,9 +13708,36 @@ static bool is_kfunc_bpf_preempt_enable(struct bpf_call_arg_meta *meta)
 	return is_kfunc_call(meta, special_kfunc_list[KF_bpf_preempt_enable]);
 }
 
+/* These write to what their first argument, a dynptr, points to */
+BTF_SET_START(dynptr_write_kfuncs)
+BTF_ID(func, bpf_dynptr_copy)
+BTF_ID(func, bpf_dynptr_memset)
+#ifdef CONFIG_BPF_EVENTS
+BTF_ID(func, bpf_probe_read_user_dynptr)
+BTF_ID(func, bpf_probe_read_kernel_dynptr)
+BTF_ID(func, bpf_probe_read_user_str_dynptr)
+BTF_ID(func, bpf_probe_read_kernel_str_dynptr)
+BTF_ID(func, bpf_copy_from_user_dynptr)
+BTF_ID(func, bpf_copy_from_user_str_dynptr)
+BTF_ID(func, bpf_copy_from_user_task_dynptr)
+BTF_ID(func, bpf_copy_from_user_task_str_dynptr)
+#endif
+BTF_SET_END(dynptr_write_kfuncs)
+
+static bool is_kfunc_dynptr_write(struct bpf_call_arg_meta *meta)
+{
+	return meta->btf == btf_vmlinux &&
+	       btf_id_set_contains(&dynptr_write_kfuncs, meta->func_id);
+}
+
+/*
+ * A write through the dynptr of an skb may reallocate its head. Before the
+ * arguments are checked nobody knows what kind of dynptr it is.
+ */
 bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta)
 {
-	return is_kfunc_call(meta, special_kfunc_list[KF_bpf_xdp_pull_data]);
+	return is_kfunc_call(meta, special_kfunc_list[KF_bpf_xdp_pull_data]) ||
+	       is_kfunc_dynptr_write(meta);
 }
 
 static u32 kfunc_abi_slots(const struct btf_func_model *fm)
@@ -15530,7 +15675,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 		}
 	}
 
-	if (bpf_is_kfunc_pkt_changing(&meta))
+	if (is_kfunc_dynptr_write(&meta) ?
+	    dynptr_write_changes_pkt_data(meta.dynptr_write_type) :
+	    bpf_is_kfunc_pkt_changing(&meta))
 		clear_all_pkt_pointers(env);
 
 	proto_slots = kfunc_abi_slots(&desc->func_model);
@@ -18117,7 +18264,7 @@ static void regs_refine_cond_op(struct bpf_reg_state *reg1, struct bpf_reg_state
 		 * this restriction. I.e., !(r1 & 0x3) means neither bit 0 nor
 		 * bit 1 is set, which we can readily use in adjustments.
 		 */
-		if (!is_power_of_2(val))
+		if (hweight64(val) != 1)
 			break;
 		if (is_jmp32) {
 			t = tnum_or(tnum_subreg(reg1->var_off), tnum_const(val));
@@ -20633,35 +20780,11 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
 		return -EINVAL;
 	}
 
-	if (prog->sleepable)
-		switch (map->map_type) {
-		case BPF_MAP_TYPE_HASH:
-		case BPF_MAP_TYPE_RHASH:
-		case BPF_MAP_TYPE_LRU_HASH:
-		case BPF_MAP_TYPE_ARRAY:
-		case BPF_MAP_TYPE_PERCPU_HASH:
-		case BPF_MAP_TYPE_PERCPU_ARRAY:
-		case BPF_MAP_TYPE_LRU_PERCPU_HASH:
-		case BPF_MAP_TYPE_LPM_TRIE:
-		case BPF_MAP_TYPE_ARRAY_OF_MAPS:
-		case BPF_MAP_TYPE_HASH_OF_MAPS:
-		case BPF_MAP_TYPE_RINGBUF:
-		case BPF_MAP_TYPE_USER_RINGBUF:
-		case BPF_MAP_TYPE_INODE_STORAGE:
-		case BPF_MAP_TYPE_SK_STORAGE:
-		case BPF_MAP_TYPE_TASK_STORAGE:
-		case BPF_MAP_TYPE_CGRP_STORAGE:
-		case BPF_MAP_TYPE_QUEUE:
-		case BPF_MAP_TYPE_STACK:
-		case BPF_MAP_TYPE_ARENA:
-		case BPF_MAP_TYPE_INSN_ARRAY:
-		case BPF_MAP_TYPE_PROG_ARRAY:
-			break;
-		default:
-			verbose(env,
-				"Sleepable programs can only use array, hash, ringbuf and local storage maps\n");
-			return -EINVAL;
-		}
+	if (prog->sleepable && !map_needs_no_rcu(map)) {
+		verbose(env,
+			"Sleepable programs can only use array, hash, ringbuf and local storage maps\n");
+		return -EINVAL;
+	}
 
 	if (bpf_map_is_cgroup_storage(map) &&
 	    bpf_cgroup_storage_assign(env->prog->aux, map)) {
@@ -20746,7 +20869,7 @@ static int __add_used_map(struct bpf_verifier_env *env, struct bpf_map *map)
 	if (err)
 		return err;
 
-	if (env->prog->sleepable)
+	if (bpf_prog_runs_sleepable(env->prog))
 		atomic64_inc(&map->sleepable_refcnt);
 
 	/* hold the map. If the program is rejected by verifier,
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 5465e7eba2384..304b426bd44d4 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2209,6 +2209,7 @@ int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_raw_tp_link *
 	return tracepoint_probe_unregister(btp->tp, (void *)btp->bpf_func, link);
 }
 
+/* On success the caller releases *buf with kfree_const() */
 int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
 			    u32 *fd_type, const char **buf,
 			    u64 *probe_offset, u64 *probe_addr,
@@ -2218,6 +2219,12 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
 	struct bpf_prog *prog;
 	int flags, err = 0;
 
+	/*
+	 * The list of dynamic events is walked, and a probe which has siblings
+	 * can be deleted, with its strings, while its event is in use.
+	 */
+	guard(mutex)(&event_mutex);
+
 	prog = event->prog;
 	if (!prog)
 		return -ENOENT;
@@ -2258,6 +2265,12 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
 #endif
 	}
 
+	if (!err && *buf) {
+		*buf = kstrdup_const(*buf, GFP_KERNEL);
+		if (!*buf)
+			err = -ENOMEM;
+	}
+
 	return err;
 }
 
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index d73cd247f8cd0..3043a7393c29c 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -1656,20 +1656,19 @@ int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kat
 		ctx.selected_sk = NULL;
 		retval = BPF_PROG_SK_LOOKUP_RUN_ARRAY(progs, ctx, bpf_prog_run);
 	} while (bpf_test_timer_continue(&t, 1, repeat, &ret, &duration));
-	bpf_test_timer_leave(&t);
-
-	if (ret < 0)
-		goto out;
 
+	/* Nothing but RCU keeps the selected socket */
 	user_ctx->cookie = 0;
-	if (ctx.selected_sk) {
-		if (ctx.selected_sk->sk_reuseport && !ctx.no_reuseport) {
+	if (!ret && ctx.selected_sk) {
+		if (ctx.selected_sk->sk_reuseport && !ctx.no_reuseport)
 			ret = -EOPNOTSUPP;
-			goto out;
-		}
-
-		user_ctx->cookie = sock_gen_cookie(ctx.selected_sk);
+		else
+			user_ctx->cookie = sock_gen_cookie(ctx.selected_sk);
 	}
+	bpf_test_timer_leave(&t);
+
+	if (ret < 0)
+		goto out;
 
 	ret = bpf_test_finish(kattr, uattr, NULL, NULL, 0, 0, retval, duration);
 	if (!ret)
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 1d295a8769fad..1c59300af05c7 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -164,6 +164,13 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
 	if (!sk_storage || hlist_empty(&sk_storage->list))
 		goto out;
 
+	/*
+	 * The maps lead to newsk as soon as an element is linked, but
+	 * sk_clone() sets sk_refcnt only later.  Until then it holds whatever
+	 * the slab object held before: no reference can be had yet.
+	 */
+	refcount_set(&newsk->sk_refcnt, 0);
+
 	hlist_for_each_entry_rcu(selem, &sk_storage->list, snode) {
 		struct bpf_local_storage_elem *copy_selem;
 		struct bpf_local_storage_map *smap;
@@ -692,8 +699,37 @@ struct bpf_iter_seq_sk_storage_map_info {
 	struct bpf_map *map;
 	unsigned int bucket_id;
 	unsigned skip_elems;
+	struct rcu_head *dead_sks;
 };
 
+/*
+ * sock_put() in two halves. The end of a socket may want process context:
+ * rfcomm_sock_destruct() takes a mutex. If the iterator drops the last
+ * reference, it keeps the socket until it has left the RCU read side critical
+ * section. Nobody uses sk_rcu before sk_destruct().
+ */
+static void
+bpf_sk_storage_map_seq_put_sk(struct bpf_iter_seq_sk_storage_map_info *info,
+			      struct sock *sk)
+{
+	if (refcount_dec_and_test(&sk->sk_refcnt)) {
+		sk->sk_rcu.next = info->dead_sks;
+		info->dead_sks = &sk->sk_rcu;
+	}
+}
+
+static void
+bpf_sk_storage_map_seq_free_sks(struct bpf_iter_seq_sk_storage_map_info *info)
+{
+	struct sock *sk;
+
+	while (info->dead_sks) {
+		sk = container_of(info->dead_sks, struct sock, sk_rcu);
+		info->dead_sks = sk->sk_rcu.next;
+		sk_free(sk);
+	}
+}
+
 static struct bpf_local_storage_elem *
 bpf_sk_storage_map_seq_find_next(struct bpf_iter_seq_sk_storage_map_info *info,
 				 struct bpf_local_storage_elem *prev_selem)
@@ -722,6 +758,7 @@ bpf_sk_storage_map_seq_find_next(struct bpf_iter_seq_sk_storage_map_info *info,
 			/* not found, unlock and go to the next bucket */
 			b = &smap->buckets[bucket_id++];
 			rcu_read_unlock();
+			bpf_sk_storage_map_seq_free_sks(info);
 			skip_elems = 0;
 			break;
 		}
@@ -789,12 +826,44 @@ DEFINE_BPF_ITER_FUNC(bpf_sk_storage_map, struct bpf_iter_meta *meta,
 		     struct bpf_map *map, struct sock *sk,
 		     void *value)
 
+/*
+ * Take a reference on the socket which owns @selem. RCU keeps the element, not
+ * its owner. As long as the element is linked under the lock of the storage,
+ * the owner has not got past bpf_sk_storage_free(), unless that has given up
+ * on the lock. Then it still waits for owner_refcnt.
+ */
+static struct sock *
+bpf_sk_storage_selem_get_sk(struct bpf_local_storage_elem *selem)
+{
+	struct bpf_local_storage *sk_storage;
+	struct sock *sk = NULL;
+	unsigned long flags;
+
+	sk_storage = rcu_dereference(selem->local_storage);
+	/* reset since ->next() looked: the socket goes away */
+	if (!sk_storage)
+		return NULL;
+
+	if (raw_res_spin_lock_irqsave(&sk_storage->lock, flags))
+		return NULL;
+
+	if (!hlist_unhashed(&selem->snode) &&
+	    refcount_inc_not_zero(&sk_storage->owner_refcnt)) {
+		sk = sk_storage->owner;
+		if (!refcount_inc_not_zero(&sk->sk_refcnt))
+			sk = NULL;
+		bpf_local_storage_unpin_owner(sk_storage);
+	}
+	raw_res_spin_unlock_irqrestore(&sk_storage->lock, flags);
+
+	return sk;
+}
+
 static int __bpf_sk_storage_map_seq_show(struct seq_file *seq,
 					 struct bpf_local_storage_elem *selem)
 {
 	struct bpf_iter_seq_sk_storage_map_info *info = seq->private;
 	struct bpf_iter__bpf_sk_storage_map ctx = {};
-	struct bpf_local_storage *sk_storage;
 	struct bpf_iter_meta meta;
 	struct bpf_prog *prog;
 	int ret = 0;
@@ -805,11 +874,14 @@ static int __bpf_sk_storage_map_seq_show(struct seq_file *seq,
 		ctx.meta = &meta;
 		ctx.map = info->map;
 		if (selem) {
-			sk_storage = rcu_dereference(selem->local_storage);
-			ctx.sk = sk_storage->owner;
+			ctx.sk = bpf_sk_storage_selem_get_sk(selem);
+			if (!ctx.sk)
+				return SEQ_SKIP;
 			ctx.value = SDATA(selem)->data;
 		}
 		ret = bpf_iter_run_prog(prog, &ctx);
+		if (ctx.sk)
+			bpf_sk_storage_map_seq_put_sk(info, ctx.sk);
 	}
 
 	return ret;
@@ -827,6 +899,7 @@ static void bpf_sk_storage_map_seq_stop(struct seq_file *seq, void *v)
 		(void)__bpf_sk_storage_map_seq_show(seq, v);
 	else
 		rcu_read_unlock();
+	bpf_sk_storage_map_seq_free_sks(seq->private);
 }
 
 static int bpf_iter_init_sk_storage_map(void *priv_data,
@@ -846,6 +919,15 @@ static void bpf_iter_fini_sk_storage_map(void *priv_data)
 	bpf_map_put_with_uref(seq_info->map);
 }
 
+static int bpf_iter_map_check_prog(const struct bpf_prog *prog,
+				   const struct bpf_iter_aux_info *aux)
+{
+	if (prog->aux->max_rdwr_access > aux->map->value_size)
+		return -EACCES;
+
+	return bpf_iter_map_check_value_write(prog, aux->map);
+}
+
 static int bpf_iter_attach_map(struct bpf_prog *prog,
 			       union bpf_iter_link_info *linfo,
 			       struct bpf_iter_aux_info *aux)
@@ -863,12 +945,11 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,
 	if (map->map_type != BPF_MAP_TYPE_SK_STORAGE)
 		goto put_map;
 
-	if (prog->aux->max_rdwr_access > map->value_size) {
-		err = -EACCES;
+	aux->map = map;
+	err = bpf_iter_map_check_prog(prog, aux);
+	if (err)
 		goto put_map;
-	}
 
-	aux->map = map;
 	return 0;
 
 put_map:
@@ -899,6 +980,7 @@ static struct bpf_iter_reg bpf_sk_storage_map_reg_info = {
 	.target			= "bpf_sk_storage_map",
 	.attach_target		= bpf_iter_attach_map,
 	.detach_target		= bpf_iter_detach_map,
+	.check_prog		= bpf_iter_map_check_prog,
 	.show_fdinfo		= bpf_iter_map_show_fdinfo,
 	.fill_link_info		= bpf_iter_map_fill_link_info,
 	.ctx_arg_info_size	= 2,
diff --git a/net/core/filter.c b/net/core/filter.c
index ba536be2915fb..0e3261f8d322c 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1731,7 +1731,8 @@ BPF_CALL_5(bpf_skb_store_bytes, struct sk_buff *, skb, u32, offset,
 	if (flags & BPF_F_RECOMPUTE_CSUM)
 		__skb_postpull_rcsum(skb, ptr, len, offset);
 
-	memcpy(ptr, from, len);
+	/* through a dynptr the source may be an overlapping slice of the skb */
+	memmove(ptr, from, len);
 
 	if (flags & BPF_F_RECOMPUTE_CSUM)
 		__skb_postpush_rcsum(skb, ptr, len, offset);
@@ -1752,9 +1753,32 @@ static const struct bpf_func_proto bpf_skb_store_bytes_proto = {
 	.arg5_type	= ARG_ANYTHING,
 };
 
+/*
+ * The source of a write through a dynptr may be a slice of the same skb.
+ * Making the skb writable can move its head: follow the move.
+ */
+static int bpf_try_make_writable_from(struct sk_buff *skb, u32 write_len,
+				      const void **from)
+{
+	const void *head = skb->head;
+	bool in_head = *from >= head &&
+		       *from < (const void *)skb_end_pointer(skb);
+	int err;
+
+	err = bpf_try_make_writable(skb, write_len);
+	if (!err && in_head)
+		*from = skb->head + (*from - head);
+	return err;
+}
+
 int __bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from,
 			  u32 len, u64 flags)
 {
+	if (unlikely(offset > INT_MAX))
+		return -EFAULT;
+	if (unlikely(bpf_try_make_writable_from(skb, offset + len, &from)))
+		return -EFAULT;
+
 	return ____bpf_skb_store_bytes(skb, offset, from, len, flags);
 }
 
@@ -3612,6 +3636,11 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
 			return -ENOTSUPP;
 	}
 
+	/* The MSS is lowered by len_diff: something has to be left of it. */
+	if (skb_is_gso(skb) && !(flags & BPF_F_ADJ_ROOM_FIXED_GSO) &&
+	    skb_shinfo(skb)->gso_size <= len_diff)
+		return -ENOTSUPP;
+
 	ret = skb_cow_head(skb, meta_len + len_diff);
 	if (unlikely(ret < 0))
 		return ret;
@@ -7017,15 +7046,15 @@ static void bpf_update_srh_state(struct sk_buff *skb)
 {
 	struct seg6_bpf_srh_state *srh_state =
 		this_cpu_ptr(&seg6_bpf_srh_states);
-	int srhoff = 0;
 
-	if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0) {
-		srh_state->srh = NULL;
-	} else {
-		srh_state->srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
+	/* Behind a decapsulation this is a header that nobody has looked at */
+	srh_state->srh = seg6_get_srh(skb, 0);
+	if (srh_state->srh) {
 		srh_state->hdrlen = srh_state->srh->hdrlen << 3;
 		srh_state->valid = true;
 	}
+	/* it may have been pulled into the head */
+	bpf_compute_data_pointers(skb);
 }
 
 BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
@@ -7058,9 +7087,14 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
 
 		if (ipv6_find_hdr(skb, &hdroff, IPPROTO_IPV6, NULL, NULL) < 0)
 			return -EBADMSG;
-		if (!pskb_pull(skb, hdroff))
+		/* As long as nothing has been changed, the program goes on */
+		if (!pskb_may_pull(skb, hdroff + sizeof(struct ipv6hdr))) {
+			/* but the head may have moved */
+			bpf_update_srh_state(skb);
 			return -EBADMSG;
+		}
 
+		__skb_pull(skb, hdroff);
 		skb_postpull_rcsum(skb, skb_network_header(skb), hdroff);
 		skb_reset_network_header(skb);
 		skb_reset_transport_header(skb);
@@ -7074,8 +7108,8 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
 			return -EBADMSG;
 		err = bpf_push_seg6_encap(skb, BPF_LWT_ENCAP_SEG6_INLINE,
 					  param, param_len);
-		if (!err)
-			bpf_update_srh_state(skb);
+		/* The header can be in place although err says otherwise */
+		bpf_update_srh_state(skb);
 
 		return err;
 	case SEG6_LOCAL_ACTION_END_B6_ENCAP:
@@ -7083,8 +7117,8 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
 			return -EBADMSG;
 		err = bpf_push_seg6_encap(skb, BPF_LWT_ENCAP_SEG6,
 					  param, param_len);
-		if (!err)
-			bpf_update_srh_state(skb);
+		/* The header can be in place although err says otherwise */
+		bpf_update_srh_state(skb);
 
 		return err;
 	default:
@@ -12414,7 +12448,7 @@ int __bpf_skb_meta_store_bytes(struct sk_buff *skb, u32 offset,
 {
 	if (unlikely(flags))
 		return -EINVAL;
-	if (unlikely(bpf_try_make_writable(skb, 0)))
+	if (unlikely(bpf_try_make_writable_from(skb, 0, &from)))
 		return -EFAULT;
 
 	memmove(bpf_skb_meta_pointer(skb, offset), from, len);
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index 38df842843289..057e2f3c0265e 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -1933,6 +1933,15 @@ int sock_map_link_create(const union bpf_attr *attr, struct bpf_prog *prog)
 	return ret;
 }
 
+static int sock_map_iter_check_prog(const struct bpf_prog *prog,
+				    const struct bpf_iter_aux_info *aux)
+{
+	if (prog->aux->max_rdonly_access > aux->map->key_size)
+		return -EACCES;
+
+	return 0;
+}
+
 static int sock_map_iter_attach_target(struct bpf_prog *prog,
 				       union bpf_iter_link_info *linfo,
 				       struct bpf_iter_aux_info *aux)
@@ -1951,12 +1960,11 @@ static int sock_map_iter_attach_target(struct bpf_prog *prog,
 	    map->map_type != BPF_MAP_TYPE_SOCKHASH)
 		goto put_map;
 
-	if (prog->aux->max_rdonly_access > map->key_size) {
-		err = -EACCES;
+	aux->map = map;
+	err = sock_map_iter_check_prog(prog, aux);
+	if (err)
 		goto put_map;
-	}
 
-	aux->map = map;
 	return 0;
 
 put_map:
@@ -1973,6 +1981,7 @@ static struct bpf_iter_reg sock_map_iter_reg = {
 	.target			= "sockmap",
 	.attach_target		= sock_map_iter_attach_target,
 	.detach_target		= sock_map_iter_detach_target,
+	.check_prog		= sock_map_iter_check_prog,
 	.show_fdinfo		= bpf_iter_map_show_fdinfo,
 	.fill_link_info		= bpf_iter_map_fill_link_info,
 	.ctx_arg_info_size	= 2,

43/3 2026/10/17 07:04 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 28169
							output: 37
							thoughts: 3618
						

Thoughts:
**KMSAN Fuzzing Session Analysis: BPF Subsystem Patch Series**

Okay, let's break down this patch series. My goal is to determine if these BPF changes justify a dedicated KMSAN fuzzing session, beyond the standard KASAN coverage.  Remember, KMSAN is for catching reads of uninitialized memory, *specifically* risks *not* addressed by KASAN (OOB, UAF, etc.) or other standard detectors. A dedicated session is expensive, so it has to be warranted. The guiding rule here is clear: **no KMSAN if KASAN (or LOCKDEP, etc.) already covers the risk.**

First, I need to methodically check for potential info-leaks to user-space *and* conditional logic based on uninitialized data, and allocation/initialization of data structures where uninitialized fields could cause trouble. I also need to check for bounds logic that could allow the surrounding code to access uninitialized memory.

I see several additions in `include/linux/bpf.h`, including new fields in `struct bpf_map` and `struct bpf_prog_aux`. Some new fields are `bool was_inner_map;`, `u32 min_rdwr_write; u32 max_rdwr_write;`, `bool sleepable_async_cb;` and a new `struct rcu_work rwork;`. While these additions are notable, I don't see anything immediately screaming "uninitialized memory leak" here. However, I need to follow the usage of these new fields carefully.

There's a bunch of stuff in `include/linux/bpf_local_storage.h` related to local storage refcounting and new functions related to RCU. Nothing too concerning yet. Similarly, new fields in `include/linux/bpf_verifier.h` seem to be mostly about tracking state during verification (`in_rcu_callback_fn`, `dynptr_write_type`). I'll need to check how these are used, of course.

The changes in `kernel/bpf/bpf_iter.c` introduce checks, particularly concerning sleepable programs, and also involve iterators and program support logic, which should be fine. The addition of new local storage features in `kernel/bpf/bpf_local_storage.c` looks safe too, based on the `refcount_dec_and_test` usage.

The changes in `kernel/bpf/btf.c` with recursion stack overflow prevention logic doesn't raise any uninitialized memory flags to me. The `kernel/bpf/cfg.c` changes look safe.

The `kernel/bpf/core.c` fixes and new code don't immediately suggest uninitialized memory problems. Same with the fixup related to cpumap entries and concurrency fixes in `kernel/bpf/hashtab.c`. The `kernel/bpf/helpers.c` code is using RCU locks which is fine. The `kernel/bpf/map_in_map.c` addition of `inner_map->was_inner_map = true;` does not appear to expose uninitialized memory.  The additions and checks in `kernel/bpf/map_iter.c` again seem to be about safety and not uninitialized reads.

Then, there are the changes in `kernel/bpf/offload.c` which check `netdev->reg_state`, and the state pruning logic in `kernel/bpf/states.c`.

Now, I'm focusing on anything that involves copying data to user space. `kernel/bpf/syscall.c` contains several functions like `bpf_perf_link_fill_common`, `bpf_task_fd_query`, and other `_fdinfo` related functions.  *This* is where my radar really goes up. I'm going to look at the memory that is copied to the userspace.

Okay, let's dig into `bpf_perf_link_fill_common`. Ah, there's `kfree_const(buf)` being added.  I remember now! `bpf_get_perf_event_info` now uses `kstrdup_const`, duplicating the string that is returned to prevent a UAF (use-after-free). This looks good. The `bpf_task_fd_query` also has this `kfree_const(buf)` pattern. I'm seeing this being used in conjunction with copying data into userspace. This is good to see as it confirms the effort that went into the code.

Checking the `kernel/bpf/devmap.c` change involving `xdp_convert_frame_to_buff`, the `rxq.mem.type = xdpf->mem


44/3 2026/10/17 07:05 tool read-file
0m Args:
{
  "File": "kernel/bpf/devmap.c",
  "FirstLine": 330,
  "LineCount": 40
}

Results:
{
  "Contents": " 330:\t\t\t}\n 331:\t\t}\n 332:\t\n 333:\t\treturn -ENOENT;\n 334:\t}\n 335:\t\n 336:\tstatic int dev_map_bpf_prog_run(struct bpf_prog *xdp_prog,\n 337:\t\t\t\t\tstruct xdp_frame **frames, int n,\n 338:\t\t\t\t\tstruct net_device *tx_dev,\n 339:\t\t\t\t\tstruct net_device *rx_dev)\n 340:\t{\n 341:\t\tstruct xdp_txq_info txq = { .dev = tx_dev };\n 342:\t\tstruct xdp_rxq_info rxq = { .dev = rx_dev };\n 343:\t\tstruct xdp_buff xdp;\n 344:\t\tint i, nframes = 0;\n 345:\t\n 346:\t\tfor (i = 0; i \u003c n; i++) {\n 347:\t\t\tstruct xdp_frame *xdpf = frames[i];\n 348:\t\t\tu32 act;\n 349:\t\t\tint err;\n 350:\t\n 351:\t\t\txdp_convert_frame_to_buff(xdpf, \u0026xdp);\n 352:\t\t\txdp.txq = \u0026txq;\n 353:\t\t\trxq.mem.type = xdpf-\u003emem_type;\n 354:\t\t\txdp.rxq = \u0026rxq;\n 355:\t\n 356:\t\t\tact = bpf_prog_run_xdp(xdp_prog, \u0026xdp);\n 357:\t\t\tswitch (act) {\n 358:\t\t\tcase XDP_PASS:\n 359:\t\t\t\terr = xdp_update_frame_from_buff(\u0026xdp, xdpf);\n 360:\t\t\t\tif (unlikely(err \u003c 0))\n 361:\t\t\t\t\txdp_return_frame_rx_napi(xdpf);\n 362:\t\t\t\telse\n 363:\t\t\t\t\tframes[nframes++] = xdpf;\n 364:\t\t\t\tbreak;\n 365:\t\t\tdefault:\n 366:\t\t\t\tbpf_warn_invalid_xdp_action(NULL, xdp_prog, act);\n 367:\t\t\t\tfallthrough;\n 368:\t\t\tcase XDP_ABORTED:\n 369:\t\t\t\ttrace_xdp_exception(tx_dev, xdp_prog, act);\n"
}

45/3 2026/10/17 07:05 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 33489
							output: 35
							thoughts: 981
						

Thoughts:
**Analyzing Recent BPF Changes**

Okay, let's break down these BPF code modifications. First, I see a clear initialization change in `xdp_rxq_info`. The `rxq.mem.type` field is now explicitly initialized from `xdpf->mem_type`.  Before, it was implicitly 0, potentially due to being a default or `MEM_TYPE_PAGE_SHARED`. This looks like a straightforward attempt to ensure that this variable has a definite type. Given the structure initialization with a designated initializer, all other fields were already zero anyway.

Next, I'm examining `net/bpf/test_run.c`, specifically `bpf_prog_test_run_sk_lookup`.  The key here seems to be the order of operations.  Previously, `user_ctx->cookie` was initialized to zero and then conditionally assigned via `sock_gen_cookie` if a socket (`ctx.selected_sk`) was selected, *after* some checks. Now, the `sock_gen_cookie` call is made unconditionally if the socket is present, before the `bpf_test_timer_leave(&t)` call. This reordering is likely done to fix a race condition since the timer code held the RCU lock. It's a subtle but important change to ensure the integrity of the cookie generation within the timing context.

Finally, I'm looking at the changes related to iterators, specifically `bpf_iter_map_check_value_write`.  The verifier code is being updated to handle iterators that provide a writable buffer of live map values to BPF programs.  The verifier needs to make sure that the program can't write to any "special" fields within the map value. The code calculates `min_rdwr_write` and `max_rdwr_write`. These values define the area where programs are allowed to write. I see that the verifier is using `min_rdwr_write` and `max_rdwr_write` to check whether the program tries to overwrite fields from the map. It's using `check_buffer_access`. Also, these variables are tracked via `check_buffer_access`, with `min_rdwr_write` initialized from zero-allocated struct `bpf_prog_aux` in `bpf_prog_alloc` and `bpf_prog_alloc_no_stats` functions. Seems like a zero allocation for these variables. I should verify `bpf_prog_alloc` in `kernel/bpf/core.c`.



46/3 2026/10/17 07:05 tool grepper
0m Args:
{
  "Expression": "bpf_prog_alloc",
  "PathPrefixes": [
    "kernel/bpf/core.c"
  ]
}

Results:
{
  "Output": "kernel/bpf/core.c=98=enum page_size_enum {\n--\nkernel/bpf/core.c-101-\nkernel/bpf/core.c:102:struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flags)\nkernel/bpf/core.c-103-{\n--\nkernel/bpf/core.c-148-\nkernel/bpf/core.c:149:struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags)\nkernel/bpf/core.c-150-{\n--\nkernel/bpf/core.c-154-\nkernel/bpf/core.c:155:\tprog = bpf_prog_alloc_no_stats(size, gfp_extra_flags);\nkernel/bpf/core.c-156-\tif (!prog)\n--\nkernel/bpf/core.c-175-\nkernel/bpf/core.c:176:int bpf_prog_alloc_jited_linfo(struct bpf_prog *prog)\nkernel/bpf/core.c-177-{\n--\nkernel/bpf/core.c=2676=struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct bpf_prog *fp,\n--\nkernel/bpf/core.c-2698-\tif (!bpf_prog_is_offloaded(fp-\u003eaux)) {\nkernel/bpf/core.c:2699:\t\t*err = bpf_prog_alloc_jited_linfo(fp);\nkernel/bpf/core.c-2700-\t\tif (*err)\n"
}

47/3 2026/10/17 07:05 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 35508
							output: 36
							thoughts: 16
						

Thoughts:
Okay, let's dive into this `bpf_prog_alloc_no_stats` function. I need to understand its role within the BPF system. From the name, I'm inferring it's related to program allocation, and the "no_stats" part suggests it might be a variation that bypasses some performance metric tracking, maybe for efficiency or specific use cases. I need to carefully consider the implications, as this suggests a trade-off. Is this for a high-frequency program? A debugging tool? What's the design rationale behind providing an allocation path *without* statistics gathering? This seems like a potential optimization or a specific niche use-case, I will have to investigate what its function is. It is important I understand the implications before I continue to use it, to be sure I am working with all the correct information.



48/3 2026/10/17 07:05 tool read-file
0m Args:
{
  "File": "kernel/bpf/core.c",
  "FirstLine": 102,
  "LineCount": 35
}

Results:
{
  "Contents": " 102:\tstruct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flags)\n 103:\t{\n 104:\t\tgfp_t gfp_flags = bpf_memcg_flags(GFP_KERNEL | __GFP_ZERO | gfp_extra_flags);\n 105:\t\tstruct bpf_prog_aux *aux;\n 106:\t\tstruct bpf_prog *fp;\n 107:\t\n 108:\t\tsize = round_up(size, __PAGE_SIZE);\n 109:\t\tfp = __vmalloc(size, gfp_flags);\n 110:\t\tif (fp == NULL)\n 111:\t\t\treturn NULL;\n 112:\t\n 113:\t\taux = kzalloc_obj(*aux, bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));\n 114:\t\tif (aux == NULL) {\n 115:\t\t\tvfree(fp);\n 116:\t\t\treturn NULL;\n 117:\t\t}\n 118:\t\tfp-\u003eactive = __alloc_percpu_gfp(sizeof(u8[BPF_NR_CONTEXTS]), 4,\n 119:\t\t\t\t\t\tbpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));\n 120:\t\tif (!fp-\u003eactive) {\n 121:\t\t\tvfree(fp);\n 122:\t\t\tkfree(aux);\n 123:\t\t\treturn NULL;\n 124:\t\t}\n 125:\t\n 126:\t\tfp-\u003epages = size / PAGE_SIZE;\n 127:\t\tfp-\u003eaux = aux;\n 128:\t\tfp-\u003eaux-\u003emain_prog_aux = aux;\n 129:\t\tfp-\u003eaux-\u003eprog = fp;\n 130:\t\tfp-\u003ejit_requested = ebpf_jit_enabled();\n 131:\t\tfp-\u003ejit_required = IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON);\n 132:\t\tfp-\u003eblinding_requested = bpf_jit_blinding_enabled(fp);\n 133:\t#ifdef CONFIG_CGROUP_BPF\n 134:\t\taux-\u003ecgroup_atype = CGROUP_BPF_ATTACH_TYPE_INVALID;\n 135:\t#endif\n 136:\t\n"
}

49/3 2026/10/17 07:05 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 36350
							output: 31
							thoughts: 666
						

Thoughts:
**Analyzing Socket Clone Initialization in the BPF Context**

Okay, so I'm digging into this `aux` object initialization. It's zero-initialized with `kzalloc_obj`, which is good. My initial concern was about uninitialized reads with `min_rdwr_write` and `max_rdwr_write`, but those are set to 0 initially. Then, if `max_rdwr_write` is zero, we initialize `min_rdwr_write`.

Now, the interesting bit is in `bpf_sk_storage_clone` from `net/core/bpf_sk_storage.c`. That comment... it's key. "The maps lead to `newsk` as soon as an element is linked, but `sk_clone()` sets `sk_refcnt` only later." That signals a potential issue. The `newsk` object inherits whatever rubbish was in the slab's memory. Meaning the `sk_refcnt` from a *previous* object.

And here we see the crucial line: `refcount_set(&newsk->sk_refcnt, 0);`. *That* prevents a race, or an access to an incompletely initialized object. I think that's it! If we didn't set this explicitly to zero, and the *previous* object in the slab had a non-zero refcount, then `refcount_inc_not_zero` could have *succeeded* on an uninitialized socket! We're preventing someone from erroneously taking a reference.

So, setting it to zero ensures that no one can get a reference to the incomplete sock until its fully initialized. Good!

Now, I'm thinking about the implications. Is this a truly safe approach, or is this still a race? To completely confirm this, I need to see *how* `bpf_sk_storage_clone` is called, and *when* `sk_refcnt` is actually initialized, so let's look at `bpf_sk_storage_selem_get_sk(selem)`. Ah, I see: there is a `refcount_inc_not_zero(&sk->sk_refcnt)` call! But the `refcount_set` call prevents this from causing trouble. Now I need to check the call to `bpf_sk_storage_clone` is done. Let's see how `bpf_sk_storage_clone` is called and when `sk_refcnt` is initialized in `sk_clone_lock`.



50/3 2026/10/17 07:05 tool grepper
0m Args:
{
  "Expression": "bpf_sk_storage_clone",
  "PathPrefixes": [
    "net/"
  ]
}

Results:
{
  "Output": "net/core/bpf_sk_storage.c=35=static int bpf_sk_storage_del(struct sock *sk, struct bpf_map *map)\n--\nnet/core/bpf_sk_storage.c-45-\nnet/core/bpf_sk_storage.c:46:/* Called by __sk_destruct() \u0026 bpf_sk_storage_clone() */\nnet/core/bpf_sk_storage.c-47-void bpf_sk_storage_free(struct sock *sk)\n--\nnet/core/bpf_sk_storage.c=133=static struct bpf_local_storage_elem *\nnet/core/bpf_sk_storage.c:134:bpf_sk_storage_clone_elem(struct sock *newsk,\nnet/core/bpf_sk_storage.c-135-\t\t\t  struct bpf_local_storage_map *smap,\n--\nnet/core/bpf_sk_storage.c-153-\nnet/core/bpf_sk_storage.c:154:int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)\nnet/core/bpf_sk_storage.c-155-{\n--\nnet/core/bpf_sk_storage.c-191-\nnet/core/bpf_sk_storage.c:192:\t\tcopy_selem = bpf_sk_storage_clone_elem(newsk, smap, selem);\nnet/core/bpf_sk_storage.c-193-\t\tif (!copy_selem) {\n--\nnet/core/sock.c=2480=struct sock *sk_clone(const struct sock *sk, const gfp_t priority,\n--\nnet/core/sock.c-2579-\nnet/core/sock.c:2580:\tif (bpf_sk_storage_clone(sk, newsk))\nnet/core/sock.c-2581-\t\tgoto free;\n"
}

51/3 2026/10/17 07:05 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 38099
							output: 36
							thoughts: 26
						

Thoughts:
Okay, here's my take on those lines of code.

**Diving into `net/core/sock.c` - Lines 2570-2600**

Right, let's pull up that section of `net/core/sock.c`. Lines 2570 to 2600... Aha, I recall this area. It's likely involved in a core socket operation, probably related to the handling of data transmission or reception, or perhaps socket state management. Given the surrounding code and my familiarity with this module, I'm guessing this might be where they handle some kind of locking, queue manipulation, or signaling related to socket buffers or the socket's internal state machine. I'm keen to see if this region implements the congestion control mechanism, or a queue for packets. If I'm lucky, this'll involve a good, clean example of atomic operations or a spinlock, which is always interesting to dissect. It could be some subtle interaction with the network stack's interrupt handling, given the potential for race conditions within socket operations. Let's see if my mental model lines up with what the actual code is doing here.



52/3 2026/10/17 07:05 tool read-file
0m Args:
{
  "File": "net/core/sock.c",
  "FirstLine": 2570,
  "LineCount": 35
}

Results:
{
  "Contents": "2570:\t\t\t/* We need to make sure that we don't uncharge the new\n2571:\t\t\t * socket if we couldn't charge it in the first place\n2572:\t\t\t * as otherwise we uncharge the parent's filter.\n2573:\t\t\t */\n2574:\t\t\tif (!is_charged)\n2575:\t\t\t\tRCU_INIT_POINTER(newsk-\u003esk_filter, NULL);\n2576:\t\n2577:\t\t\tgoto free;\n2578:\t\t}\n2579:\t\n2580:\t\tif (bpf_sk_storage_clone(sk, newsk))\n2581:\t\t\tgoto free;\n2582:\t\n2583:\t\t/* Clear sk_user_data if parent had the pointer tagged\n2584:\t\t * as not suitable for copying when cloning.\n2585:\t\t */\n2586:\t\tif (sk_user_data_is_nocopy(newsk))\n2587:\t\t\tnewsk-\u003esk_user_data = NULL;\n2588:\t\n2589:\t\tnewsk-\u003esk_err\t   = 0;\n2590:\t\tnewsk-\u003esk_err_soft = 0;\n2591:\t\tnewsk-\u003esk_priority = 0;\n2592:\t\tnewsk-\u003esk_incoming_cpu = raw_smp_processor_id();\n2593:\t\n2594:\t\t/* Before updating sk_refcnt, we must commit prior changes to memory\n2595:\t\t * (Documentation/RCU/rculist_nulls.rst for details)\n2596:\t\t */\n2597:\t\tsmp_wmb();\n2598:\t\trefcount_set(\u0026newsk-\u003esk_refcnt, 2);\n2599:\t\n2600:\t\tsk_set_socket(newsk, NULL);\n2601:\t\tsk_tx_queue_clear(newsk);\n2602:\t\tsk_rx_queue_clear(newsk);\n2603:\t\tRCU_INIT_POINTER(newsk-\u003esk_wq, NULL);\n2604:\t\n"
}

53/3 2026/10/17 07:05 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 38962
							output: 42
							thoughts: 159
						

Thoughts:
**Analyzing the Socket Cloning Mechanism**

Okay, here we go. Diving into `sk_clone`, my immediate observation is the allocation of `newsk` using `sk_prot_alloc`. I need to ensure the correct allocation occurs and its implications. In the code, I see:

```c
	struct sock *newsk;
	bool is_charged = true;

	newsk = sk_prot_alloc(sk->sk_prot, priority, sk->sk_family);
	if (!newsk)
		goto out;

	sock_copy(newsk, sk);
```

Ah, right! `sk_prot_alloc` is called to create the new socket structure, `newsk`. Now, the crucial part: `sock_copy(newsk, sk)`. This is where the core socket information gets transferred from the original socket (`sk`) to the new one. This is interesting... I need to understand exactly what that copy entails. I need to know what happens to the reference count specifically. I need to verify what the reference count on `newsk` will be *after* the `sock_copy` call completes. Time to go check `sock_copy`.



54/3 2026/10/17 07:05 tool grepper
0m Args:
{
  "Expression": "void sock_copy",
  "PathPrefixes": [
    "net/core/sock.c",
    "include/net/sock.h"
  ]
}

Results:
{
  "Output": "include/net/sock.h=991=enum sock_flags {\n--\ninclude/net/sock.h-1034-\ninclude/net/sock.h:1035:static inline void sock_copy_flags(struct sock *nsk, const struct sock *osk)\ninclude/net/sock.h-1036-{\n--\nnet/core/sock.c=2185=static inline void sock_lock_init(struct sock *sk)\n--\nnet/core/sock.c-2209- */\nnet/core/sock.c:2210:static void sock_copy(struct sock *nsk, const struct sock *osk)\nnet/core/sock.c-2211-{\n"
}

55/3 2026/10/17 07:05 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 39604
							output: 36
							thoughts: 19
						

Thoughts:
Okay, here's my interpretation of what's going through my mind as I approach this code:

**Diving into `sock_copy` in `net/core/sock.c`**

Alright, time to dig in. I'm going to start by looking at `sock_copy` in `net/core/sock.c`. I know this function is crucial for data transfer within the networking stack, so I'm expecting to find the nitty-gritty details of how data moves around, potentially including buffer management, copy optimizations, and maybe even some lock interactions, depending on how it's implemented. I'm particularly interested in seeing how it handles different socket types and the implications of its design on performance. I'll need to pay close attention to the data structures involved, like `skb` (socket buffer) and possibly any associated reference counting mechanisms, to understand the flow control and memory implications. My goal is to get a solid grasp of its purpose, the conditions it's designed to handle, and any potential bottlenecks it might introduce in the overall network performance. I'm ready to get my hands dirty.



56/3 2026/10/17 07:05 tool read-file
0m Args:
{
  "File": "net/core/sock.c",
  "FirstLine": 2210,
  "LineCount": 25
}

Results:
{
  "Contents": "2210:\tstatic void sock_copy(struct sock *nsk, const struct sock *osk)\n2211:\t{\n2212:\t\tconst struct proto *prot = READ_ONCE(osk-\u003esk_prot);\n2213:\t#ifdef CONFIG_SECURITY_NETWORK\n2214:\t\tvoid *sptr = nsk-\u003esk_security;\n2215:\t#endif\n2216:\t\n2217:\t\t/* If we move sk_tx_queue_mapping out of the private section,\n2218:\t\t * we must check if sk_tx_queue_clear() is called after\n2219:\t\t * sock_copy() in sk_clone_lock().\n2220:\t\t */\n2221:\t\tBUILD_BUG_ON(offsetof(struct sock, sk_tx_queue_mapping) \u003c\n2222:\t\t\t     offsetof(struct sock, sk_dontcopy_begin) ||\n2223:\t\t\t     offsetof(struct sock, sk_tx_queue_mapping) \u003e=\n2224:\t\t\t     offsetof(struct sock, sk_dontcopy_end));\n2225:\t\n2226:\t\tmemcpy(nsk, osk, offsetof(struct sock, sk_dontcopy_begin));\n2227:\t\n2228:\t\tunsafe_memcpy(\u0026nsk-\u003esk_dontcopy_end, \u0026osk-\u003esk_dontcopy_end,\n2229:\t\t\t      prot-\u003eobj_size - offsetof(struct sock, sk_dontcopy_end),\n2230:\t\t\t      /* alloc is larger than struct, see sk_prot_alloc() */);\n2231:\t\n2232:\t#ifdef CONFIG_SECURITY_NETWORK\n2233:\t\tnsk-\u003esk_security = sptr;\n2234:\t\tsecurity_sk_clone(osk, nsk);\n"
}

57/3 2026/10/17 07:05 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 40355
							output: 32
							thoughts: 53
						

Thoughts:
Here's my thought process, as if I were analyzing this code:

**Finding the Reference Count**

Okay, so I see a comment about a section not being copied, delimited by `sk_dontcopy_begin` and `sk_dontcopy_end`. That's a helpful marker! Now, I need to understand what's *not* being copied, and more importantly, where the reference count (`sk_refcnt`) lives. Let's dig into the code and determine which structure `sk_dontcopy_begin` applies to. Given the context, it's highly likely it has something to do with `struct sock`. I'll immediately jump to `include/net/sock.h` and start looking around the `sk_dontcopy_begin` marker. The goal is to correlate the `dontcopy` section with `sk_refcnt` within the `struct sock` definition. Hopefully, the connection will be clear from the surrounding code. It is highly probable, given my experience, that the reference count is closely linked to whatever memory is protected by this section. I need to be sure!



58/3 2026/10/17 07:05 tool grepper
0m Args:
{
  "Expression": "sk_dontcopy",
  "PathPrefixes": [
    "include/net/sock.h"
  ]
}

Results:
{
  "Output": "include/net/sock.h=365=struct sock {\n--\ninclude/net/sock.h-378-\ninclude/net/sock.h:379:#define sk_dontcopy_begin\t__sk_common.skc_dontcopy_begin\ninclude/net/sock.h:380:#define sk_dontcopy_end\t\t__sk_common.skc_dontcopy_end\ninclude/net/sock.h-381-#define sk_hash\t\t\t__sk_common.skc_hash\n"
}

59/3 2026/10/17 07:05 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 40811
							output: 33
							thoughts: 36
						

Thoughts:
Here's a summary of my thought process:

**Diving into `include/net/sock.h`**

Alright, let's get down to brass tacks. I'm going to take a look at the `include/net/sock.h` file. Specifically, I'm interested in what's tucked away between the `skc_dontcopy_begin` and `skc_dontcopy_end` markers. I know these are likely some sort of compiler directives or conditional sections, potentially related to memory management or data structure initialization specific to the socket layer, and I'm keen to understand their purpose in detail. My intuition tells me this is something core, that I need to be across. I want to grok precisely what code is being excluded, potentially conditionally.



60/3 2026/10/17 07:05 tool grepper
0m Args:
{
  "Expression": "skc_dontcopy",
  "PathPrefixes": [
    "include/net/sock.h"
  ]
}

Results:
{
  "Output": "include/net/sock.h=156=struct sock_common {\n--\ninclude/net/sock.h-213-\t/* private: */\ninclude/net/sock.h:214:\tint\t\t\tskc_dontcopy_begin[0];\ninclude/net/sock.h-215-\t/* public: */\n--\ninclude/net/sock.h-231-\t/* private: */\ninclude/net/sock.h:232:\tint                     skc_dontcopy_end[0];\ninclude/net/sock.h-233-\tunion {\n--\ninclude/net/sock.h=365=struct sock {\n--\ninclude/net/sock.h-378-\ninclude/net/sock.h:379:#define sk_dontcopy_begin\t__sk_common.skc_dontcopy_begin\ninclude/net/sock.h:380:#define sk_dontcopy_end\t\t__sk_common.skc_dontcopy_end\ninclude/net/sock.h-381-#define sk_hash\t\t\t__sk_common.skc_hash\n"
}

61/3 2026/10/17 07:05 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 41329
							output: 35
							thoughts: 23
						

Thoughts:
Okay, let's dive into this. I'm going to quickly refresh my memory on the socket infrastructure, specifically focusing on the core definitions. Let's start by looking at `include/net/sock.h`, and, in particular, I want to zero in on lines 210 through 235. This should give me a good grounding in the data structures related to sockets, without getting bogged down in implementation details. I suspect this will define the fundamental `struct sock` or related structures and maybe some core flags. I need a quick overview before I dive into the complexities later. Let's see what we've got.



62/3 2026/10/17 07:06 tool read-file
0m Args:
{
  "File": "include/net/sock.h",
  "FirstLine": 210,
  "LineCount": 26
}

Results:
{
  "Contents": " 210:\t\t * fields between dontcopy_begin/dontcopy_end\n 211:\t\t * are not copied in sock_copy()\n 212:\t\t */\n 213:\t\t/* private: */\n 214:\t\tint\t\t\tskc_dontcopy_begin[0];\n 215:\t\t/* public: */\n 216:\t\tunion {\n 217:\t\t\tstruct hlist_node\tskc_node;\n 218:\t\t\tstruct hlist_nulls_node skc_nulls_node;\n 219:\t\t};\n 220:\t\tunsigned short\t\tskc_tx_queue_mapping;\n 221:\t#ifdef CONFIG_SOCK_RX_QUEUE_MAPPING\n 222:\t\tunsigned short\t\tskc_rx_queue_mapping;\n 223:\t#endif\n 224:\t\tunion {\n 225:\t\t\tint\t\tskc_incoming_cpu;\n 226:\t\t\tu32\t\tskc_rcv_wnd;\n 227:\t\t\tu32\t\tskc_tw_rcv_nxt; /* struct tcp_timewait_sock  */\n 228:\t\t};\n 229:\t\n 230:\t\trefcount_t\t\tskc_refcnt;\n 231:\t\t/* private: */\n 232:\t\tint                     skc_dontcopy_end[0];\n 233:\t\tunion {\n 234:\t\t\tu32\t\tskc_rxhash;\n 235:\t\t\tu32\t\tskc_window_clamp;\n"
}

63/3 2026/10/17 07:06 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 41927
							output: 33
							thoughts: 87
						

Thoughts:
Okay, here's my assessment of this code snippet, distilled into a first-person perspective, assuming I'm already well-versed in kernel internals:

**Investigating a Socket Object Allocation**

Alright, take a look at this. I'm seeing that `skc_refcnt` is currently sitting somewhere between `skc_dontcopy_begin` and `skc_dontcopy_end`. This is interesting; I need to keep this in mind as I continue digging. The next line, `newsk = sk_prot_alloc(...)`, is the socket slab object allocation. The allocation itself is crucial, especially regarding memory management.

A crucial point now: Is this using `sk_prot_alloc` allocating memory, or allocating it from a pre-defined SLAB cache? That’s what I've got to find out. I need to dive into the implementation of `sk_prot_alloc` itself to understand exactly how this memory is being handled. This could have implications for performance and memory fragmentation, so let's get right to it.



64/3 2026/10/17 07:06 tool grepper
0m Args:
{
  "Expression": "sk_prot_alloc",
  "PathPrefixes": [
    "net/core/sock.c"
  ]
}

Results:
{
  "Output": "net/core/sock.c=2210=static void sock_copy(struct sock *nsk, const struct sock *osk)\n--\nnet/core/sock.c-2229-\t\t      prot-\u003eobj_size - offsetof(struct sock, sk_dontcopy_end),\nnet/core/sock.c:2230:\t\t      /* alloc is larger than struct, see sk_prot_alloc() */);\nnet/core/sock.c-2231-\n--\nnet/core/sock.c-2237-\nnet/core/sock.c:2238:static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,\nnet/core/sock.c-2239-\t\tint family)\n--\nnet/core/sock.c=2303=struct sock *sk_alloc(struct net *net, int family, gfp_t priority,\n--\nnet/core/sock.c-2307-\nnet/core/sock.c:2308:\tsk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);\nnet/core/sock.c-2309-\tif (sk) {\n--\nnet/core/sock.c=2480=struct sock *sk_clone(const struct sock *sk, const gfp_t priority,\n--\nnet/core/sock.c-2487-\nnet/core/sock.c:2488:\tnewsk = sk_prot_alloc(prot, priority, sk-\u003esk_family);\nnet/core/sock.c-2489-\tif (!newsk)\n"
}

65/3 2026/10/17 07:06 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 42679
							output: 40
							thoughts: 595
						

Thoughts:
**Deep Dive into `sk_alloc` and `sk_clone` – A Critical Refcount Saga**

Okay, hold on a second. Line 2488 versus line 2308… something's amiss here. In `sk_alloc`, we have `sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);` –  the allocation *zeros* the memory. But in `sk_clone`, it's `newsk = sk_prot_alloc(prot, priority, sk->sk_family);` – no `__GFP_ZERO`! And *`sk_prot_alloc` itself* uses `kmem_cache_alloc` without zeroing! This is important.

So, `sock_copy` meticulously copies everything, *except* from `dontcopy_begin` to `dontcopy_end`. It means, *between* those points, the `skc_refcnt` field – it's uninitialized slab memory! We're talking garbage here!

Okay, *now* I'm tracking. But when does `refcount_inc_not_zero(&sk->sk_refcnt)` get called? Let's trace it through `bpf_sk_storage_clone`...Ah, yes, here we go...

```c
int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
{
	struct bpf_local_storage *sk_storage;
	struct bpf_local_storage_elem *selem;

	sk_storage = rcu_dereference_check(sk->sk_bpf_storage, bpf_rcu_lock_held());
	if (!sk_storage || hlist_empty(&sk_storage->list))
		goto out;

+	/*
+	 * The maps lead to newsk as soon as an element is linked, but
+	 * sk_clone() sets sk_refcnt only later.  Until then it holds whatever
+	 * the slab object held before: no reference can be had yet.
+	 */
+	refcount_set(&newsk->sk_refcnt, 0);

	hlist_for_each_entry_rcu(selem, &sk_storage->list, snode) {
		struct bpf_local_storage_elem *copy_selem;
		struct bpf_local_storage_map *smap;

		smap = rcu_dereference_check(SDATA(selem)->smap, bpf_rcu_lock_held());
		if (!smap)
			continue;

		copy_selem = bpf_sk_storage_clone_elem(newsk, smap, selem);
...
```

Right, the *key* observation is in the comment, "The maps lead to newsk as soon as an element is linked, but `sk_clone()` sets `sk_refcnt` only later. Until then it holds whatever the slab object held before: no reference can be had yet." Therefore, they specifically set `refcount_set(&newsk->sk_refcnt, 0);` to initialize the refcount. It prevents the potential from starting with an invalid (potentially high) refcount.

But what did `bpf_sk_storage_clone_elem` *do* with it? I should check it now. I'll read that function in `net/core/bpf_sk_storage.c`.



66/3 2026/10/17 07:06 tool read-file
0m Args:
{
  "File": "net/core/bpf_sk_storage.c",
  "FirstLine": 133,
  "LineCount": 35
}

Results:
{
  "Contents": " 133:\tstatic struct bpf_local_storage_elem *\n 134:\tbpf_sk_storage_clone_elem(struct sock *newsk,\n 135:\t\t\t\t  struct bpf_local_storage_map *smap,\n 136:\t\t\t\t  struct bpf_local_storage_elem *selem)\n 137:\t{\n 138:\t\tstruct bpf_local_storage_elem *copy_selem;\n 139:\t\n 140:\t\tcopy_selem = bpf_selem_alloc(smap, newsk, NULL, false);\n 141:\t\tif (!copy_selem)\n 142:\t\t\treturn NULL;\n 143:\t\n 144:\t\tif (btf_record_has_field(smap-\u003emap.record, BPF_SPIN_LOCK))\n 145:\t\t\tcopy_map_value_locked(\u0026smap-\u003emap, SDATA(copy_selem)-\u003edata,\n 146:\t\t\t\t\t      SDATA(selem)-\u003edata, true);\n 147:\t\telse\n 148:\t\t\tcopy_map_value(\u0026smap-\u003emap, SDATA(copy_selem)-\u003edata,\n 149:\t\t\t\t       SDATA(selem)-\u003edata);\n 150:\t\n 151:\t\treturn copy_selem;\n 152:\t}\n 153:\t\n 154:\tint bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)\n 155:\t{\n 156:\t\tstruct bpf_local_storage *new_sk_storage = NULL;\n 157:\t\tstruct bpf_local_storage *sk_storage;\n 158:\t\tstruct bpf_local_storage_elem *selem;\n 159:\t\tint ret = 0;\n 160:\t\n 161:\t\trcu_read_lock_dont_migrate();\n 162:\t\tsk_storage = rcu_dereference(sk-\u003esk_bpf_storage);\n 163:\t\n 164:\t\tif (!sk_storage || hlist_empty(\u0026sk_storage-\u003elist))\n 165:\t\t\tgoto out;\n 166:\t\n 167:\t\t/*\n"
}

67/3 2026/10/17 07:06 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 44665
							output: 40
							thoughts: 32
						

Thoughts:
Okay, let's dive into this `bpf_sk_storage_clone` function and see what's happening from lines 168 to 220. Let me mentally map out the flow here, starting from where we left off.

**Delving into `bpf_sk_storage_clone` - Line 168 Onward**

Alright, so the function call is happening, and now we're at the critical part where the "cloning" logic kicks in. Specifically, I need to see how a new `sk_storage` object is initiated from an existing one, and what steps occur to make it a distinct copy and how it's connected with its `sock`. We'll also see if there's any allocation happening, or if some things are just getting linked, so I can see its memory footprint. I need to understand if the clone is an exact replica, or if this new storage starts with a clean slate to avoid any race conditions.

I'm also looking for any potential data structure changes or operations that might need synchronization in the clone operation. I'm keen to find out about whether the clone preserves original states or it sets some variables differently, such as the `refcount` or `state` fields. I'm looking for clues of how the original storage and the cloned one might diverge. I'm expecting some kind of check or condition to determine which data need to be copied, and which will be initialized.



68/3 2026/10/17 07:06 tool read-file
0m Args:
{
  "File": "net/core/bpf_sk_storage.c",
  "FirstLine": 168,
  "LineCount": 45
}

Results:
{
  "Contents": " 168:\t\t * The maps lead to newsk as soon as an element is linked, but\n 169:\t\t * sk_clone() sets sk_refcnt only later.  Until then it holds whatever\n 170:\t\t * the slab object held before: no reference can be had yet.\n 171:\t\t */\n 172:\t\trefcount_set(\u0026newsk-\u003esk_refcnt, 0);\n 173:\t\n 174:\t\thlist_for_each_entry_rcu(selem, \u0026sk_storage-\u003elist, snode) {\n 175:\t\t\tstruct bpf_local_storage_elem *copy_selem;\n 176:\t\t\tstruct bpf_local_storage_map *smap;\n 177:\t\t\tstruct bpf_map *map;\n 178:\t\n 179:\t\t\tsmap = rcu_dereference(SDATA(selem)-\u003esmap);\n 180:\t\t\tif (!smap || !(smap-\u003emap.map_flags \u0026 BPF_F_CLONE))\n 181:\t\t\t\tcontinue;\n 182:\t\n 183:\t\t\t/* Note that for lockless listeners adding new element\n 184:\t\t\t * here can race with cleanup in bpf_local_storage_map_free.\n 185:\t\t\t * Try to grab map refcnt to make sure that it's still\n 186:\t\t\t * alive and prevent concurrent removal.\n 187:\t\t\t */\n 188:\t\t\tmap = bpf_map_inc_not_zero(\u0026smap-\u003emap);\n 189:\t\t\tif (IS_ERR(map))\n 190:\t\t\t\tcontinue;\n 191:\t\n 192:\t\t\tcopy_selem = bpf_sk_storage_clone_elem(newsk, smap, selem);\n 193:\t\t\tif (!copy_selem) {\n 194:\t\t\t\tret = -ENOMEM;\n 195:\t\t\t\tbpf_map_put(map);\n 196:\t\t\t\tgoto out;\n 197:\t\t\t}\n 198:\t\n 199:\t\t\tif (new_sk_storage) {\n 200:\t\t\t\tret = bpf_selem_link_map(smap, new_sk_storage, copy_selem);\n 201:\t\t\t\tif (ret) {\n 202:\t\t\t\t\tbpf_selem_free(copy_selem, true);\n 203:\t\t\t\t\tatomic_sub(smap-\u003eelem_size,\n 204:\t\t\t\t\t\t   \u0026newsk-\u003esk_omem_alloc);\n 205:\t\t\t\t\tbpf_map_put(map);\n 206:\t\t\t\t\tgoto out;\n 207:\t\t\t\t}\n 208:\t\t\t\tbpf_selem_link_storage_nolock(new_sk_storage, copy_selem);\n 209:\t\t\t} else {\n 210:\t\t\t\tret = bpf_local_storage_alloc(newsk, smap, copy_selem);\n 211:\t\t\t\tif (ret) {\n 212:\t\t\t\t\tbpf_selem_free(copy_selem, true);\n"
}

69/3 2026/10/17 07:06 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 45836
							output: 45
							thoughts: 1814
						

Thoughts:
**Analyzing the `bpf_sk_storage_clone` Patch for Potential KMSAN Implications**

Okay, let's break this down. My initial observation is focused on `bpf_sk_storage_clone()` and the implications of linking a `copy_selem` to the map. The core concern revolves around the lifecycle of the newly cloned socket, `newsk`.  I'm immediately struck by the risk of `newsk` becoming reachable via map iteration or lookup, and the potential for a race condition or UAF.

Specifically, I see a clear potential for an uninitialized `sk_refcnt`. Prior to this patch, the code used `ctx.sk = sk_storage->owner;` directly, without any refcounting. Then I saw how `newsk` was allocated and recognized that it was using `sk_prot_alloc` *without* `__GFP_ZERO`.  This means that the initial value of `newsk->sk_refcnt` was whatever garbage happened to be in that slab memory. This meant that calling `refcount_inc_not_zero(&newsk->sk_refcnt)` could read uninitialized memory, leading to a crash or other unpredictable behavior.

The patch appears to have been applied, and I see `refcount_set(&newsk->sk_refcnt, 0);` added to initialize it. This is a fix, of course, but it leads to the questions of whether the patch resolves *all* potential uninitialized memory issues and if there are *new* concerns.

This brings me to the KMSAN criteria. My expert intuition is that I should go through the conditions that would necessitate KMSAN: kernel structures sent to userspace, conditional logic on potentially uninitialized data, allocation of complex structures, and alterations in bounds checks/lengths.  

So, let's step through the specific parts. First the KMSAN rules say that there is no sense in running KMSAN if KASAN, LOCKDEP or other standard bug detectors are already effective, so only specifically uninitialized memory or info-leak cases are of concern.

So let's drill down in the patch, beyond `sk_refcnt` initialization. I check the other parts of the patch, specifically `bpf_sk_storage_map_seq_put_sk`. Here, I'm analyzing the `refcount_dec_and_test(&sk->sk_refcnt)` code, as that would seem like an obvious area to be concerned about.

Then I see:
```c
+	if (refcount_dec_and_test(&sk->sk_refcnt)) {
+		sk->sk_rcu.next = info->dead_sks;
+		info->dead_sks = &sk->sk_rcu;
+	}
+```
I note the use of `sk->sk_rcu.next`. So what is `sk_rcu`? It is an `rcu_head`. Is `sk_rcu` properly initialized? From prior experience, an embedded `rcu_head` *should* be fine if the structure it is embedded in is initialized, as I expect it is, but I *must* check the allocation and initialization of `info` to verify.

To complete the analysis I need to check how `info` is allocated and initialized by checking `bpf_iter_init_sk_storage_map` to see what `info->dead_sks` is set to. This will complete the picture and determine if the patch might necessitate KMSAN.



70/3 2026/10/17 07:06 tool grepper
0m Args:
{
  "Expression": "bpf_iter_init_sk_storage_map",
  "PathPrefixes": [
    "net/core/bpf_sk_storage.c"
  ]
}

Results:
{
  "Output": "net/core/bpf_sk_storage.c=895=static void bpf_sk_storage_map_seq_stop(struct seq_file *seq, void *v)\n--\nnet/core/bpf_sk_storage.c-904-\nnet/core/bpf_sk_storage.c:905:static int bpf_iter_init_sk_storage_map(void *priv_data,\nnet/core/bpf_sk_storage.c-906-\t\t\t\t\tstruct bpf_iter_aux_info *aux)\n--\nnet/core/bpf_sk_storage.c=972=static const struct bpf_iter_seq_info iter_seq_info = {\nnet/core/bpf_sk_storage.c-973-\t.seq_ops\t\t= \u0026bpf_sk_storage_map_seq_ops,\nnet/core/bpf_sk_storage.c:974:\t.init_seq_private\t= bpf_iter_init_sk_storage_map,\nnet/core/bpf_sk_storage.c-975-\t.fini_seq_private\t= bpf_iter_fini_sk_storage_map,\n"
}

71/3 2026/10/17 07:06 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 48755
							output: 40
							thoughts: 18
						

Thoughts:
Okay, let's dive into this `bpf_iter_init_sk_storage_map` function. My initial thought is, based on the name alone, that this likely concerns the initialization process for a storage map specifically related to socket (sk) data structures, when dealing with BPF iterations. Given my expertise, I'm already anticipating considerations around efficiency, concurrency, and how the map interacts with the kernel's network stack. I'll need to pay close attention to any locking mechanisms implemented. The "iter" prefix strongly suggests this map is designed to facilitate iteration through a collection, quite possibly a dynamic set of socket-related metadata. I expect to see data structures or BPF helpers optimized to handle the potential high volume or frequency that BPF iterations are typically involved in. I anticipate how this initialization stage sets the groundwork for how these BPF programs can effectively monitor, analyze, or potentially modify socket behavior. The focus on "sk_storage" implies the map isn't just a simple key-value store, but likely holds more complex, per-socket state. I need to be prepared to assess the memory layout, data structures used for keys and values, and the overall design for potential bottlenecks. Understanding how the initialization manages concurrency, particularly in a multi-threaded network environment, will be key to my understanding.



72/3 2026/10/17 07:06 tool read-file
0m Args:
{
  "File": "net/core/bpf_sk_storage.c",
  "FirstLine": 905,
  "LineCount": 25
}

Results:
{
  "Contents": " 905:\tstatic int bpf_iter_init_sk_storage_map(void *priv_data,\n 906:\t\t\t\t\t\tstruct bpf_iter_aux_info *aux)\n 907:\t{\n 908:\t\tstruct bpf_iter_seq_sk_storage_map_info *seq_info = priv_data;\n 909:\t\n 910:\t\tbpf_map_inc_with_uref(aux-\u003emap);\n 911:\t\tseq_info-\u003emap = aux-\u003emap;\n 912:\t\treturn 0;\n 913:\t}\n 914:\t\n 915:\tstatic void bpf_iter_fini_sk_storage_map(void *priv_data)\n 916:\t{\n 917:\t\tstruct bpf_iter_seq_sk_storage_map_info *seq_info = priv_data;\n 918:\t\n 919:\t\tbpf_map_put_with_uref(seq_info-\u003emap);\n 920:\t}\n 921:\t\n 922:\tstatic int bpf_iter_map_check_prog(const struct bpf_prog *prog,\n 923:\t\t\t\t\t   const struct bpf_iter_aux_info *aux)\n 924:\t{\n 925:\t\tif (prog-\u003eaux-\u003emax_rdwr_access \u003e aux-\u003emap-\u003evalue_size)\n 926:\t\t\treturn -EACCES;\n 927:\t\n 928:\t\treturn bpf_iter_map_check_value_write(prog, aux-\u003emap);\n 929:\t}\n"
}

73/3 2026/10/17 07:06 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 49513
							output: 37
							thoughts: 51
						

Thoughts:
Here's my thought process, as if I were analyzing this code:

**Debugging the `priv_data` Allocation**

Okay, so I need to track down where this `priv_data` field is actually getting allocated. That's the core question here. My initial thought is that it's going to be somewhere within the BPF iterator framework, likely in the data structures that manage the iteration state. Let's see... the `struct bpf_iter_seq_info` structure is a prime candidate, it seems to hold sequence-specific information, so I need to check its definition and how it's used. Alternatively, it could be tied to the `seq_ops` structure; the operations defining the sequence could be managing this. I should also investigate `bpf_iter_link_attach` and `bpf_seq_read`, as these are the points where BPF iterators are set up and data is read, respectively, and could have a hand in it. I'll need to dig into the function calls and structure definitions in each to pinpoint the precise location. I'm going to start with `bpf_iter_seq_info` and work from there.



74/3 2026/10/17 07:06 tool grepper
0m Args:
{
  "Expression": "init_seq_private",
  "PathPrefixes": [
    "kernel/bpf/bpf_iter.c"
  ]
}

Results:
{
  "Output": "kernel/bpf/bpf_iter.c=614=static int prepare_seq_file(struct file *file, struct bpf_iter_link *link)\n--\nkernel/bpf/bpf_iter.c-638-\nkernel/bpf/bpf_iter.c:639:\tif (seq_info-\u003einit_seq_private) {\nkernel/bpf/bpf_iter.c:640:\t\terr = seq_info-\u003einit_seq_private(priv_data-\u003etarget_private, \u0026link-\u003eaux);\nkernel/bpf/bpf_iter.c-641-\t\tif (err)\n"
}

75/3 2026/10/17 07:06 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 50020
							output: 39
							thoughts: 25
						

Thoughts:
Okay, let's dive into this. Here's my thought process on this:

**Examining `prepare_seq_file` in `kernel/bpf/bpf_iter.c`**

Alright, I'm thinking we should start by focusing on `prepare_seq_file` within `kernel/bpf/bpf_iter.c`. This suggests that something related to BPF iterators might be where the issue lies. This function's name implies it's involved in setting up or initializing a sequence file, which is often used for displaying data in a structured, readable format, like in `/proc` or `/sys`. Given my understanding of BPF and iterators, I'm expecting this function to be critical in connecting the BPF program's output to the user space via a sequence file. I need to understand how the data gets populated. Are there potential buffer overflows? Memory leaks? Incorrect synchronization? The possibilities are numerous, but this function feels like a good starting point to trace the control flow and data.



76/3 2026/10/17 07:06 tool read-file
0m Args:
{
  "File": "kernel/bpf/bpf_iter.c",
  "FirstLine": 614,
  "LineCount": 35
}

Results:
{
  "Contents": " 614:\tstatic int prepare_seq_file(struct file *file, struct bpf_iter_link *link)\n 615:\t{\n 616:\t\tconst struct bpf_iter_seq_info *seq_info = __get_seq_info(link);\n 617:\t\tstruct bpf_iter_priv_data *priv_data;\n 618:\t\tstruct bpf_iter_target_info *tinfo;\n 619:\t\tstruct bpf_prog *prog;\n 620:\t\tu32 total_priv_dsize;\n 621:\t\tstruct seq_file *seq;\n 622:\t\tint err = 0;\n 623:\t\n 624:\t\tmutex_lock(\u0026link_mutex);\n 625:\t\tprog = link-\u003elink.prog;\n 626:\t\tbpf_prog_inc(prog);\n 627:\t\tmutex_unlock(\u0026link_mutex);\n 628:\t\n 629:\t\ttinfo = link-\u003etinfo;\n 630:\t\ttotal_priv_dsize = offsetof(struct bpf_iter_priv_data, target_private) +\n 631:\t\t\t\t   seq_info-\u003eseq_priv_size;\n 632:\t\tpriv_data = __seq_open_private(file, seq_info-\u003eseq_ops,\n 633:\t\t\t\t\t       total_priv_dsize);\n 634:\t\tif (!priv_data) {\n 635:\t\t\terr = -ENOMEM;\n 636:\t\t\tgoto release_prog;\n 637:\t\t}\n 638:\t\n 639:\t\tif (seq_info-\u003einit_seq_private) {\n 640:\t\t\terr = seq_info-\u003einit_seq_private(priv_data-\u003etarget_private, \u0026link-\u003eaux);\n 641:\t\t\tif (err)\n 642:\t\t\t\tgoto release_seq_file;\n 643:\t\t}\n 644:\t\n 645:\t\tinit_seq_meta(priv_data, tinfo, seq_info, prog);\n 646:\t\tseq = file-\u003eprivate_data;\n 647:\t\tseq-\u003eprivate = priv_data-\u003etarget_private;\n 648:\t\n"
}

77/3 2026/10/17 07:06 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 50882
							output: 38
							thoughts: 1411
						

Thoughts:
**Analyzing Recent BPF Changes**

Okay, so I'm digging into these recent BPF changes. The `__seq_open_private` function uses `kzalloc`, which means `target_private` and the `struct bpf_iter_seq_sk_storage_map_info` struct are zero-initialized. Therefore, `info->dead_sks` starts as `NULL`, which is important for understanding the initial state.

Now, I'm looking at `net/core/filter.c`. I see a significant change in `bpf_skb_store_bytes`. The key here is handling dynamic pointer (`dynptr`) slices. If a BPF program uses `bpf_skb_store_bytes` or `__bpf_skb_meta_store_bytes` with `from` pointing to a slice of the SKB's head, the code now accounts for potential reallocation. The `bpf_try_make_writable_from` function seems to be the fix. Before, if `bpf_try_make_writable` (e.g., via `pskb_expand_head`) moved the SKB's head, the `from` pointer would be left dangling, pointing to freed memory, leading to a Use-After-Free condition, which KASAN would thankfully catch. Additionally, if `ptr` and `from` overlapped, `memcpy` was undefined behavior; now it uses `memmove` which is correct.

Next, I'm checking out `bpf_skb_net_grow`. I notice the addition of a check for `gso_size <= len_diff`. This is a defensive measure to prevent underflow of `gso_size`, which is good to see. It ensures that the MSS (Maximum Segment Size) isn't reduced to an invalid value.

Finally, I'm examining `bpf_update_srh_state` and `bpf_lwt_seg6_action`. This code updates the SRH (Source Routing Header) state within an SKB. It retrieves the SRH using `seg6_get_srh`. I need to figure out how `srh_state` is initialized. I see it uses `this_cpu_ptr(&seg6_bpf_srh_states)`, so I need to grep for that to understand the initialization and lifetime of this state. The check for `seg6_get_srh` means that it's now more robust in dealing with decapsulation scenarios where the header might not have been previously accessed. Also, `bpf_compute_data_pointers(skb)` is called, so if the header was pulled into the skb head, all pointers are recomputed. This likely handles the case where data has moved as a result of the previous operations.



78/3 2026/10/17 07:07 tool grepper
0m Args:
{
  "Expression": "seg6_bpf_srh_states",
  "PathPrefixes": [
    "net/core/filter.c"
  ]
}

Results:
{
  "Output": "net/core/filter.c=7002=BPF_CALL_4(bpf_lwt_seg6_store_bytes, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c-7005-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7006:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7007-\tstruct ipv6_sr_hdr *srh = srh_state-\u003esrh;\n--\nnet/core/filter.c=7045=static void bpf_update_srh_state(struct sk_buff *skb)\n--\nnet/core/filter.c-7047-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7048:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7049-\n--\nnet/core/filter.c=7060=BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\n--\nnet/core/filter.c-7063-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7064:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7065-\tint hdroff = 0;\n--\nnet/core/filter.c=7139=BPF_CALL_3(bpf_lwt_seg6_adjust_srh, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c-7142-\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c:7143:\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\nnet/core/filter.c-7144-\tstruct ipv6_sr_hdr *srh = srh_state-\u003esrh;\n"
}

79/3 2026/10/17 07:07 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 53489
							output: 36
							thoughts: 25
						

Thoughts:
Okay, let's dive into this. Here's my take on those lines of code:

**Analyzing `net/core/filter.c` - Lines 7040-7065**

Alright, I'm pulling up `net/core/filter.c` and zeroing in on lines 7040-7065. Based on my existing understanding of the filtering subsystem, this likely touches upon a specific aspect of packet filtering, most probably related to a particular rule evaluation, action, or perhaps even an optimization within the filter chain. Given the numbering, it's probably relatively deep within a larger function or macro. I'm guessing it's not a fundamental data structure definition or initialization; those are typically earlier in the file.

I anticipate seeing code that handles either:

*   **A specific match criteria:** Maybe a comparison against a header field, a bit mask check, or perhaps even a complex multi-part condition. I'll be looking for comparisons and logical operators.
*   **An associated action:** If a condition is met, what happens? This could range from dropping the packet, accepting it, modifying some header data, queuing it, or passing it on to another filter. I'll be looking for function calls like `skb_drop`, `NF_ACCEPT`, `netif_rx`, etc.
*   **Performance optimization:** Perhaps there's an early-exit check to avoid unnecessary computation, or some kind of caching or pre-calculation to speed up the filtering process. I'll be on the lookout for branches with short-circuiting logic.

My initial hypothesis is that these lines might be dealing with a nuanced filter rule, possibly a more involved match condition or a sophisticated action associated with a specific Netfilter hook. Let's see what's actually there. I'm eager to understand the fine-grained control it provides and how it interacts with the broader filtering framework. Let's get to the code and get into it.



80/3 2026/10/17 07:07 tool read-file
0m Args:
{
  "File": "net/core/filter.c",
  "FirstLine": 7035,
  "LineCount": 40
}

Results:
{
  "Contents": "7035:\tstatic const struct bpf_func_proto bpf_lwt_seg6_store_bytes_proto = {\n7036:\t\t.func\t\t= bpf_lwt_seg6_store_bytes,\n7037:\t\t.gpl_only\t= false,\n7038:\t\t.ret_type\t= RET_INTEGER,\n7039:\t\t.arg1_type\t= ARG_PTR_TO_CTX,\n7040:\t\t.arg2_type\t= ARG_ANYTHING,\n7041:\t\t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n7042:\t\t.arg4_type\t= ARG_MEM_SIZE\n7043:\t};\n7044:\t\n7045:\tstatic void bpf_update_srh_state(struct sk_buff *skb)\n7046:\t{\n7047:\t\tstruct seg6_bpf_srh_state *srh_state =\n7048:\t\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n7049:\t\n7050:\t\t/* Behind a decapsulation this is a header that nobody has looked at */\n7051:\t\tsrh_state-\u003esrh = seg6_get_srh(skb, 0);\n7052:\t\tif (srh_state-\u003esrh) {\n7053:\t\t\tsrh_state-\u003ehdrlen = srh_state-\u003esrh-\u003ehdrlen \u003c\u003c 3;\n7054:\t\t\tsrh_state-\u003evalid = true;\n7055:\t\t}\n7056:\t\t/* it may have been pulled into the head */\n7057:\t\tbpf_compute_data_pointers(skb);\n7058:\t}\n7059:\t\n7060:\tBPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\n7061:\t\t   u32, action, void *, param, u32, param_len)\n7062:\t{\n7063:\t\tstruct seg6_bpf_srh_state *srh_state =\n7064:\t\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n7065:\t\tint hdroff = 0;\n7066:\t\tint err;\n7067:\t\n7068:\t\tlockdep_assert_held(\u0026srh_state-\u003ebh_lock);\n7069:\t\tswitch (action) {\n7070:\t\tcase SEG6_LOCAL_ACTION_END_X:\n7071:\t\t\tif (!seg6_bpf_has_valid_srh(skb))\n7072:\t\t\t\treturn -EBADMSG;\n7073:\t\t\tif (param_len != sizeof(struct in6_addr))\n7074:\t\t\t\treturn -EINVAL;\n"
}

81/3 2026/10/17 07:07 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 54710
							output: 39
							thoughts: 258
						

Thoughts:
**Analyzing the Potential for NULL SRH Pointers in BPF Code**

Okay, I'm digging into this `bpf_update_srh_state` function. My immediate concern is this: what happens if `seg6_get_srh(skb, 0)` returns NULL? That's a critical point to consider. The original code's logic is a bit different, and that's making me pause. Let me see...

Ah, right, the original approach used `ipv6_find_hdr`. If that fails, the `srh` pointer is explicitly set to NULL. But what about the `seg6_get_srh` function? Does it *also* properly handle and reset the `srh_state->valid` flag when it returns NULL? That's the crux of my concern.

I need to confirm whether a NULL `srh` from `seg6_get_srh` correctly invalidates the state. The critical thing here is how `srh_state` is used later on and *where* `valid` is checked. That's what I have to understand. Time to grep the codebase for uses of `seg6_bpf_srh_state` and ensure there aren't any potential null pointer dereferences or incorrect assumptions about the validity of the SRH. Let's get to work!



82/3 2026/10/17 07:07 tool grepper
0m Args:
{
  "Expression": "struct seg6_bpf_srh_state",
  "PathPrefixes": [
    "net/",
    "include/"
  ]
}

Results:
{
  "Output": "include/net/seg6_local.h=19=extern bool seg6_bpf_has_valid_srh(struct sk_buff *skb);\ninclude/net/seg6_local.h-20-\ninclude/net/seg6_local.h:21:struct seg6_bpf_srh_state {\ninclude/net/seg6_local.h-22-\tlocal_lock_t bh_lock;\n--\ninclude/net/seg6_local.h-27-\ninclude/net/seg6_local.h:28:DECLARE_PER_CPU(struct seg6_bpf_srh_state, seg6_bpf_srh_states);\ninclude/net/seg6_local.h-29-\n--\nnet/core/filter.c=7002=BPF_CALL_4(bpf_lwt_seg6_store_bytes, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c-7004-{\nnet/core/filter.c:7005:\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c-7006-\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n--\nnet/core/filter.c=7045=static void bpf_update_srh_state(struct sk_buff *skb)\nnet/core/filter.c-7046-{\nnet/core/filter.c:7047:\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c-7048-\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n--\nnet/core/filter.c=7060=BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,\n--\nnet/core/filter.c-7062-{\nnet/core/filter.c:7063:\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c-7064-\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n--\nnet/core/filter.c=7139=BPF_CALL_3(bpf_lwt_seg6_adjust_srh, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c-7141-{\nnet/core/filter.c:7142:\tstruct seg6_bpf_srh_state *srh_state =\nnet/core/filter.c-7143-\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n--\nnet/ipv6/seg6_local.c=1459=static int input_action_end_b6_encap(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-1493-\nnet/ipv6/seg6_local.c:1494:DEFINE_PER_CPU(struct seg6_bpf_srh_state, seg6_bpf_srh_states) = {\nnet/ipv6/seg6_local.c-1495-\t.bh_lock\t= INIT_LOCAL_LOCK(bh_lock),\n--\nnet/ipv6/seg6_local.c=1498=bool seg6_bpf_has_valid_srh(struct sk_buff *skb)\nnet/ipv6/seg6_local.c-1499-{\nnet/ipv6/seg6_local.c:1500:\tstruct seg6_bpf_srh_state *srh_state =\nnet/ipv6/seg6_local.c-1501-\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n--\nnet/ipv6/seg6_local.c=1522=static int input_action_end_bpf(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-1524-{\nnet/ipv6/seg6_local.c:1525:\tstruct seg6_bpf_srh_state *srh_state;\nnet/ipv6/seg6_local.c-1526-\tenum skb_drop_reason reason;\n"
}

83/3 2026/10/17 07:07 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 56389
							output: 40
							thoughts: 29
						

Thoughts:
Okay, here's my interpretation of that section of `net/ipv6/seg6_local.c`, from lines 1494 to 1540:

**Analyzing the SEG6 Local Processing Logic**

Alright, let's dive into this specific section of the SEG6 local code. I'm looking at lines 1494-1540 and focusing on how it handles, presumably, the processing of locally originated traffic that needs to be steered through an IPv6 Segment Routing header (SRH). From the context, I'm expecting to find the key decision points and the core actions taken when a packet hits the `seg6_local` module.

I'm betting this code is responsible for checking if the destination matches a locally configured SEG6 policy, and if so, taking the necessary steps to apply the policy. This probably includes modifying the packet header to add or update the SRH with the segment list. I'm keen to see how it handles things like the SRH option's next header, the segment left pointer, and how it deals with potential errors or policy mismatches. It's crucial this code ensures the packet is properly prepared for the next hop based on the segment list. I'm really looking to see the flow of the code. Is the packet being routed to another interface? Is it being modified within the same interface? Is this done using xfrm? Are any checks performed before actually sending?

I'll be looking specifically for any calls to functions that handle SRH manipulation, policy lookup, or packet forwarding. The error handling is of particular interest as well – how does it deal with invalid policies, exhausted segment lists, or other unexpected conditions? I'm hoping to see a solid, efficient, and secure implementation here, as this is fundamental to the correct operation of the system. Let's see how it's done!



84/3 2026/10/17 07:07 tool read-file
0m Args:
{
  "File": "net/ipv6/seg6_local.c",
  "FirstLine": 1494,
  "LineCount": 45
}

Results:
{
  "Contents": "1494:\tDEFINE_PER_CPU(struct seg6_bpf_srh_state, seg6_bpf_srh_states) = {\n1495:\t\t.bh_lock\t= INIT_LOCAL_LOCK(bh_lock),\n1496:\t};\n1497:\t\n1498:\tbool seg6_bpf_has_valid_srh(struct sk_buff *skb)\n1499:\t{\n1500:\t\tstruct seg6_bpf_srh_state *srh_state =\n1501:\t\t\tthis_cpu_ptr(\u0026seg6_bpf_srh_states);\n1502:\t\tstruct ipv6_sr_hdr *srh = srh_state-\u003esrh;\n1503:\t\n1504:\t\tlockdep_assert_held(\u0026srh_state-\u003ebh_lock);\n1505:\t\tif (unlikely(srh == NULL))\n1506:\t\t\treturn false;\n1507:\t\n1508:\t\tif (unlikely(!srh_state-\u003evalid)) {\n1509:\t\t\tif ((srh_state-\u003ehdrlen \u0026 7) != 0)\n1510:\t\t\t\treturn false;\n1511:\t\n1512:\t\t\tsrh-\u003ehdrlen = (u8)(srh_state-\u003ehdrlen \u003e\u003e 3);\n1513:\t\t\tif (!seg6_validate_srh(srh, (srh-\u003ehdrlen + 1) \u003c\u003c 3, true))\n1514:\t\t\t\treturn false;\n1515:\t\n1516:\t\t\tsrh_state-\u003evalid = true;\n1517:\t\t}\n1518:\t\n1519:\t\treturn true;\n1520:\t}\n1521:\t\n1522:\tstatic int input_action_end_bpf(struct sk_buff *skb,\n1523:\t\t\t\t\tstruct seg6_local_lwt *slwt)\n1524:\t{\n1525:\t\tstruct seg6_bpf_srh_state *srh_state;\n1526:\t\tenum skb_drop_reason reason;\n1527:\t\tstruct ipv6_sr_hdr *srh;\n1528:\t\tint ret;\n1529:\t\n1530:\t\tsrh = get_and_validate_srh(skb);\n1531:\t\tif (!srh) {\n1532:\t\t\tkfree_skb(skb);\n1533:\t\t\treturn -EINVAL;\n1534:\t\t}\n1535:\t\tsrh = advance_nextseg(skb, srh, \u0026reason);\n1536:\t\tif (!srh) {\n1537:\t\t\tkfree_skb_reason(skb, reason);\n1538:\t\t\treturn -ENOMEM;\n"
}

85/3 2026/10/17 07:07 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 57584
							output: 40
							thoughts: 23
						

Thoughts:
Okay, let's break this down. Here's how I'd approach understanding the code, thinking like a seasoned professional:

**Analyzing the `input_action_end_bpf` Function**

Alright, I'm diving into this function, `input_action_end_bpf`. The central question is, what happens to `srh_state` inside of it? That's the core focus here. I need to understand how `input_action_end_bpf` interacts with and potentially modifies this state variable, `srh_state`. Knowing that interaction is key to grasping the function's overall purpose and its role within the larger system. Is it updating it? Reading it? Using it as a key for something else? Determining its fate in this particular section of code is my primary objective. I'm looking for clues in any associated operations, how its value may be manipulated, or where it's subsequently used. Let's see...



86/3 2026/10/17 07:07 tool read-file
0m Args:
{
  "File": "net/ipv6/seg6_local.c",
  "FirstLine": 1540,
  "LineCount": 45
}

Results:
{
  "Contents": "1540:\t\n1541:\t\t/* The access to the per-CPU buffer srh_state is protected by running\n1542:\t\t * always in softirq context (with disabled BH). On PREEMPT_RT the\n1543:\t\t * required locking is provided by the following local_lock_nested_bh()\n1544:\t\t * statement. It is also accessed by the bpf_lwt_seg6_* helpers via\n1545:\t\t * bpf_prog_run_save_cb().\n1546:\t\t */\n1547:\t\tlocal_lock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\n1548:\t\tsrh_state = this_cpu_ptr(\u0026seg6_bpf_srh_states);\n1549:\t\tsrh_state-\u003esrh = srh;\n1550:\t\tsrh_state-\u003ehdrlen = srh-\u003ehdrlen \u003c\u003c 3;\n1551:\t\tsrh_state-\u003evalid = true;\n1552:\t\n1553:\t\trcu_read_lock();\n1554:\t\tbpf_compute_data_pointers(skb);\n1555:\t\tret = bpf_prog_run_save_cb(slwt-\u003ebpf.prog, skb);\n1556:\t\trcu_read_unlock();\n1557:\t\n1558:\t\tswitch (ret) {\n1559:\t\tcase BPF_OK:\n1560:\t\tcase BPF_REDIRECT:\n1561:\t\t\tbreak;\n1562:\t\tcase BPF_DROP:\n1563:\t\t\tgoto drop;\n1564:\t\tdefault:\n1565:\t\t\tpr_warn_once(\"bpf-seg6local: Illegal return value %u\\n\", ret);\n1566:\t\t\tgoto drop;\n1567:\t\t}\n1568:\t\n1569:\t\tif (srh_state-\u003esrh \u0026\u0026 !seg6_bpf_has_valid_srh(skb))\n1570:\t\t\tgoto drop;\n1571:\t\tlocal_unlock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\n1572:\t\n1573:\t\tif (ret != BPF_REDIRECT)\n1574:\t\t\tseg6_lookup_nexthop(skb, NULL, 0);\n1575:\t\n1576:\t\treturn dst_input(skb);\n1577:\t\n1578:\tdrop:\n1579:\t\tlocal_unlock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\n1580:\t\tkfree_skb(skb);\n1581:\t\treturn -EINVAL;\n1582:\t}\n1583:\t\n1584:\tstatic struct seg6_action_desc seg6_action_table[] = {\n"
}

87/3 2026/10/17 07:07 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 58596
							output: 37
							thoughts: 184
						

Thoughts:
Here's my thought process, as requested:

**Deconstructing BPF CPU Map Entry Allocation**

Alright, let's break this down. I've got a handle on how `srh_state` in per-CPU memory starts – its `valid` flag is initialized at both definition and function entry. The next step is figuring out the allocation and usage of `struct bpf_cpu_map_entry`. The comment in `kernel/bpf/cpumap.c` hints at holding references to devices within the queue, which is interesting. It looks like it's tracking references to network devices (`struct net_device *held[]`) and the number of held devices (`u32 nr_held`).

My immediate question is: where is this `struct bpf_cpu_map_entry` actually instantiated? It's time to follow the trail. I'll need to go to `cpu_map_entry_alloc` in `kernel/bpf/cpumap.c`. That should provide the answer, and expose the allocation method. From there, I can begin tracing the lifecycle of these entries and how the held device references are managed. I'm especially interested in the synchronization, and the details surrounding that `CPU_MAP_HELD_DEVS` array size.



88/3 2026/10/17 07:07 tool grepper
0m Args:
{
  "Expression": "cpu_map_entry_alloc",
  "PathPrefixes": [
    "kernel/bpf/cpumap.c"
  ]
}

Results:
{
  "Output": "kernel/bpf/cpumap.c=449=static struct bpf_cpu_map_entry *\nkernel/bpf/cpumap.c:450:__cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,\nkernel/bpf/cpumap.c-451-\t\t      u32 cpu)\n--\nkernel/bpf/cpumap.c=596=static long cpu_map_update_elem(struct bpf_map *map, void *key, void *value,\n--\nkernel/bpf/cpumap.c-623-\t\t/* Updating qsize cause re-allocation of bpf_cpu_map_entry */\nkernel/bpf/cpumap.c:624:\t\trcpu = __cpu_map_entry_alloc(map, \u0026cpumap_value, key_cpu);\nkernel/bpf/cpumap.c-625-\t\tif (IS_ERR(rcpu))\n"
}

89/3 2026/10/17 07:07 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 59336
							output: 37
							thoughts: 26
						

Thoughts:
Okay, let's dive into this. I'm going to pull up `__cpu_map_entry_alloc` in `kernel/bpf/cpumap.c`. I know what it's *supposed* to do, but I want to refresh my memory and see if there are any subtle details I might have overlooked in the past. It's always a good idea to revisit these core functions, especially when dealing with something as performance-critical as CPU affinity. I'm going to pay close attention to the memory allocation strategies and any potential synchronization primitives. This is the bedrock of the BPF CPU map implementation, so getting this right is paramount. I'm expecting to see how this function handles the allocation and initialization of a new entry within the CPU map itself, as well as the underlying data structures. Let's see how they handle NUMA awareness, as well... I'll need to think about potential contention points too.



90/3 2026/10/17 07:08 tool read-file
0m Args:
{
  "File": "kernel/bpf/cpumap.c",
  "FirstLine": 449,
  "LineCount": 40
}

Results:
{
  "Contents": " 449:\tstatic struct bpf_cpu_map_entry *\n 450:\t__cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,\n 451:\t\t\t      u32 cpu)\n 452:\t{\n 453:\t\tint numa, err = -ENOMEM, i, fd = value-\u003ebpf_prog.fd;\n 454:\t\tgfp_t gfp = GFP_KERNEL | __GFP_NOWARN;\n 455:\t\tstruct bpf_cpu_map_entry *rcpu;\n 456:\t\tstruct xdp_bulk_queue *bq;\n 457:\t\n 458:\t\t/* Have map-\u003enuma_node, but choose node of redirect target CPU */\n 459:\t\tnuma = cpu_to_node(cpu);\n 460:\t\n 461:\t\trcpu = bpf_map_kmalloc_node(map, sizeof(*rcpu), gfp | __GFP_ZERO, numa);\n 462:\t\tif (!rcpu)\n 463:\t\t\treturn ERR_PTR(err);\n 464:\t\n 465:\t\t/* Alloc percpu bulkq */\n 466:\t\trcpu-\u003ebulkq = bpf_map_alloc_percpu(map, sizeof(*rcpu-\u003ebulkq),\n 467:\t\t\t\t\t\t   sizeof(void *), gfp);\n 468:\t\tif (!rcpu-\u003ebulkq)\n 469:\t\t\tgoto free_rcu;\n 470:\t\n 471:\t\tfor_each_possible_cpu(i) {\n 472:\t\t\tbq = per_cpu_ptr(rcpu-\u003ebulkq, i);\n 473:\t\t\tbq-\u003eobj = rcpu;\n 474:\t\t\tlocal_lock_init(\u0026bq-\u003ebq_lock);\n 475:\t\t}\n 476:\t\n 477:\t\t/* Alloc queue */\n 478:\t\trcpu-\u003equeue = bpf_map_kmalloc_node(map, sizeof(*rcpu-\u003equeue), gfp,\n 479:\t\t\t\t\t\t   numa);\n 480:\t\tif (!rcpu-\u003equeue)\n 481:\t\t\tgoto free_bulkq;\n 482:\t\n 483:\t\terr = ptr_ring_init(rcpu-\u003equeue, value-\u003eqsize, gfp);\n 484:\t\tif (err)\n 485:\t\t\tgoto free_queue;\n 486:\t\n 487:\t\trcpu-\u003ecpu    = cpu;\n 488:\t\trcpu-\u003emap_id = map-\u003eid;\n"
}

91/3 2026/10/17 07:08 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 60268
							output: 38
							thoughts: 332
						

Thoughts:
**My Current Analysis of BPF Map Initialization and Fixups**

Okay, so I'm initializing this `rcpu` using `bpf_map_kmalloc_node`.  I see `__GFP_ZERO` is being passed, which is important because that means `held` and `nr_held` are 0-initialized right off the bat.  Good. That's clean. And, I understand that `nr_held` is going to be incremented whenever a device pointer gets stuffed into `held`, and decremented when it's released.

Now, my attention has shifted. I'm taking a look at `kernel/bpf/fixups.c`. Specifically, I'm checking around line 2151 because something caught my eye. What's this? I see that `bpf_do_misc_fixups` is being called here.  I need to understand *why* this is happening in this context. It seems odd. What exactly is the purpose of this call at this point in the control flow? I need to read the code around that line in `kernel/bpf/fixups.c` to fully understand what's going on.



92/3 2026/10/17 07:08 tool read-file
0m Args:
{
  "File": "kernel/bpf/fixups.c",
  "FirstLine": 2140,
  "LineCount": 35
}

Results:
{
  "Contents": "2140:\t\t\tif (insn-\u003eimm == BPF_FUNC_get_prandom_u32)\n2141:\t\t\t\tbpf_user_rnd_init_once();\n2142:\t\t\tif (insn-\u003eimm == BPF_FUNC_override_return)\n2143:\t\t\t\tprog-\u003ekprobe_override = 1;\n2144:\t\t\tif (insn-\u003eimm == BPF_FUNC_tail_call) {\n2145:\t\t\t\t/* If we tail call into other programs, we\n2146:\t\t\t\t * cannot make any assumptions since they can\n2147:\t\t\t\t * be replaced dynamically during runtime in\n2148:\t\t\t\t * the program array.\n2149:\t\t\t\t */\n2150:\t\t\t\tprog-\u003ecb_access = 1;\n2151:\t\t\t\tif (!bpf_allow_tail_call_in_subprogs(env))\n2152:\t\t\t\t\tprog-\u003eaux-\u003estack_depth = MAX_BPF_STACK;\n2153:\t\t\t\tprog-\u003eaux-\u003emax_pkt_offset = MAX_PACKET_OFF;\n2154:\t\t\t\tprog-\u003eaux-\u003emax_rdonly_access = U32_MAX;\n2155:\t\t\t\tprog-\u003eaux-\u003emax_rdwr_access = U32_MAX;\n2156:\t\t\t\tif (prog-\u003etype == BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE)\n2157:\t\t\t\t\tprog-\u003eaux-\u003emax_tp_access = U32_MAX;\n2158:\t\n2159:\t\t\t\t/* mark bpf_tail_call as different opcode to avoid\n2160:\t\t\t\t * conditional branch in the interpreter for every normal\n2161:\t\t\t\t * call and to prevent accidental JITing by JIT compiler\n2162:\t\t\t\t * that doesn't support bpf_tail_call yet\n2163:\t\t\t\t */\n2164:\t\t\t\tinsn-\u003eimm = 0;\n2165:\t\t\t\tinsn-\u003ecode = BPF_JMP | BPF_TAIL_CALL;\n2166:\t\n2167:\t\t\t\taux = \u0026env-\u003einsn_aux_data[i + delta];\n2168:\t\t\t\tif (env-\u003ebpf_capable \u0026\u0026 !prog-\u003eblinding_requested \u0026\u0026\n2169:\t\t\t\t    prog-\u003ejit_requested \u0026\u0026\n2170:\t\t\t\t    !bpf_map_key_poisoned(aux) \u0026\u0026\n2171:\t\t\t\t    !bpf_map_ptr_poisoned(aux) \u0026\u0026\n2172:\t\t\t\t    !bpf_map_ptr_unpriv(aux)) {\n2173:\t\t\t\t\tstruct bpf_jit_poke_descriptor desc = {\n2174:\t\t\t\t\t\t.reason = BPF_POKE_REASON_TAIL_CALL,\n"
}

93/3 2026/10/17 07:08 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 61578
							output: 38
							thoughts: 1317
						

Thoughts:
**BPF Verifier and Runtime Improvements: A Deep Dive**

Okay, let's break down these BPF changes. That initial comment really got my attention: the interplay between tail calls and dynamic program replacement is crucial for safety. The update to `max_rdonly_access` and `max_rdwr_access` effectively tightens bounds checking when tail calls are involved. Essentially, we are now disallowing iterator map attach checks in cases when tail calls are used because the tail called program might access a larger range of memory, which is a significant improvement in preventing out-of-bounds access. This is a very targeted hardening, a good defensive mechanism.

Next, looking at `btf.c`, I see a critical recursion depth limit implemented for the BTF show functionality. This prevents potential kernel stack overflows during complex type resolution. This is a solid, albeit simple, defense. A very practical addition, as I've seen issues in the past with deeply nested BTF structures.

Now, that inode reference leak fix in `bpf_token_create` (in `kernel/bpf/token.c`) is a straightforward memory management improvement. Preventing an inode leak when `FD_PREPARE` fails is a classic issue and this fix seems correct. Preventing any object from being leaked, that's what I want to see!

The `netdev` registration state check in `bpf_prog_dev_bound_init` (in `kernel/bpf/offload.c`) is interesting. Preventing BPF program attachment to an unregistered netdev is a good move, safeguarding against Use-After-Free (UAF) issues. Another very pragmatic and sensible hardening approach.

The concurrency fix in `alloc_htab_elem` (in `kernel/bpf/hashtab.c`) for the hash table update is elegant. This addresses a concurrency race between NMI/kprobe interrupts and regular code. Using per-cpu extra elements and careful atomic operations is a solid way to handle this scenario. The use of `try_cmpxchg_local` is the right strategy.

Finally, let's dive into the verifier changes.
1.  The `dynptr_write_changes_pkt_data` function now invalidates SKB dynptr slices when a helper or kfunc modifies packet data. This is crucial for preventing UAF bugs if the SKB head gets reallocated. This sounds like an important and correct addition to the verifier, particularly important in network-facing BPF programs.
2.  Also within the verifier, `check_func_arg` disallows passing a packet slice to a helper that modifies packet data. Another UAF prevention technique. This is directly related to the previous point, reinforcing the safety net around packet manipulation.
3.  The introduction of `in_rcu_callback` and `map_needs_no_rcu` shows attention to sleepable context and RCU interactions. That's good defensive programming!
4.  But now, the `regs_refine_cond_op` change using `hweight64(val) != 1` instead of `!is_power_of_2(val)` warrants closer inspection. The fact that the previous comparison considered `!is_power_of_2(0)` as true is a major concern. The updated implementation ensures more accurate detection of non-power-of-2 values, which makes the code more robust. The difference between `hweight64(0)` and `!is_power_of_2(0)` is important to be aware of! This is a subtle but important change. Let me go back and double check the context around line 18117 in `kernel/bpf/verifier.c` to see the exact implication.



94/3 2026/10/17 07:08 tool read-file
0m Args:
{
  "File": "kernel/bpf/verifier.c",
  "FirstLine": 18250,
  "LineCount": 35
}

Results:
{
  "Contents": "18250:\t\t\tbreak;\n18251:\t\tcase BPF_JSET:\n18252:\t\t\tif (!is_reg_const(reg2, is_jmp32))\n18253:\t\t\t\tswap(reg1, reg2);\n18254:\t\t\tif (!is_reg_const(reg2, is_jmp32))\n18255:\t\t\t\tbreak;\n18256:\t\t\tval = reg_const_value(reg2, is_jmp32);\n18257:\t\t\t/* BPF_JSET (i.e., TRUE branch, *not* BPF_JSET | BPF_X)\n18258:\t\t\t * requires single bit to learn something useful. E.g., if we\n18259:\t\t\t * know that `r1 \u0026 0x3` is true, then which bits (0, 1, or both)\n18260:\t\t\t * are actually set? We can learn something definite only if\n18261:\t\t\t * it's a single-bit value to begin with.\n18262:\t\t\t *\n18263:\t\t\t * BPF_JSET | BPF_X (i.e., negation of BPF_JSET) doesn't have\n18264:\t\t\t * this restriction. I.e., !(r1 \u0026 0x3) means neither bit 0 nor\n18265:\t\t\t * bit 1 is set, which we can readily use in adjustments.\n18266:\t\t\t */\n18267:\t\t\tif (hweight64(val) != 1)\n18268:\t\t\t\tbreak;\n18269:\t\t\tif (is_jmp32) {\n18270:\t\t\t\tt = tnum_or(tnum_subreg(reg1-\u003evar_off), tnum_const(val));\n18271:\t\t\t\treg1-\u003evar_off = tnum_with_subreg(reg1-\u003evar_off, t);\n18272:\t\t\t} else {\n18273:\t\t\t\treg1-\u003evar_off = tnum_or(reg1-\u003evar_off, tnum_const(val));\n18274:\t\t\t}\n18275:\t\t\tbreak;\n18276:\t\tcase BPF_JSET | BPF_X: /* reverse of BPF_JSET, see bpf_rev_opcode() */\n18277:\t\t\tif (!is_reg_const(reg2, is_jmp32))\n18278:\t\t\t\tswap(reg1, reg2);\n18279:\t\t\tif (!is_reg_const(reg2, is_jmp32))\n18280:\t\t\t\tbreak;\n18281:\t\t\tval = reg_const_value(reg2, is_jmp32);\n18282:\t\t\t/* Forget the ranges before narrowing tnums, to avoid invariant\n18283:\t\t\t * violations if we're on a dead branch.\n18284:\t\t\t */\n"
}

95/3 2026/10/17 07:08 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 64482
							output: 582
							thoughts: 2680
						

Thoughts:
**KMSAN Assessment: A Deep Dive**

Okay, so I've meticulously reviewed this patch series, and my expert intuition is telling me that `NeedsKMSAN` should be set to `false`. Let me walk you through my reasoning, which I've taken the time to thoroughly and methodically assess, given my deep understanding of the kernel's memory management and BPF subsystem.

First, I had a quick look at the bit operations, confirming the expected behavior. Now, diving into the core changes, I saw a multitude of fixes focused on preventing use-after-free conditions, memory leaks, and concurrency issues within the BPF framework, including: `bpf_prog_realloc` updates that correct dangling pointer issues; `bpf_prog_free_images` updates that ensure proper freeing of JIT images within RCU grace periods; and various `bpf_local_storage` updates that handle issues with accessing local storage elements by sleepable BPF programs.

Next, I cross-referenced each change against the four conditions for needing KMSAN: Kernel structures sent to userspace, conditional logic on potentially uninitialized variables, data structure allocation with uninitialized fields, and bounds checks that expose uninitialized bytes. My detailed analysis involved a meticulous examination of each function and variable introduced or modified. In detail:

*   **User Space Exposure**: The `bpf_perf_link_fill_common`, `bpf_task_fd_query`, `bpf_prog_test_run_sk_lookup`, and `bpf_perf_link_fdinfo_kprobe/uprobe/tracepoint_link_show_fdinfo` changes are all centered on data being passed to user space. I made sure that the data copied to user space is properly initialized or zeroed. I noticed that the `bpf_perf_link_fill_common` and `bpf_task_fd_query` changes now includes `kfree_const`, which explicitly fixes a memory leak, but doesn't introduce any uninitialized memory concerns.

*   **Conditional Logic**: The crucial thing in `bpf_sk_storage_clone` is the initialization of `newsk->sk_refcnt`, which, quite impressively, *fixes* a potential read of uninitialized memory. In the other scenarios, new variables such as `sleepable_users`, `full`, `is_arg`, `ksyms`, `last`, `is_percpu`, and `value_size` are all carefully initialized before use, thereby negating any KMSAN concern.

*   **Data Structure Allocation**: I meticulously reviewed structures like `bpf_prog_aux`, `bpf_func_state`, `bpf_call_arg_meta`, `bpf_iter_seq_sk_storage_map_info`, and `bpf_cpu_map_entry` to check allocation, and how the values are written to prevent uninitialized reads. Each member in those structs is allocated with either `kzalloc` or `__GFP_ZERO`, ensuring all fields are zero-initialized.

*   **Bounds Checks**: Enhancements to bounds checking in functions like `bpf_skb_net_grow`, `bpf_skb_store_bytes`, `check_buffer_access`, `bpf_do_misc_fixups`, and `btf_show_start_aggr_type` focus on tightening the constraints to prevent out-of-bounds access and overflow issues.

I've carefully categorized all the bugs the patch series addresses, which includes concurrency and race conditions (handled by LOCKDEP / thread sanitizers), memory leaks (handled by KMEMLEAK), reference counting issues (handled by KASAN), and use-after-free / lifetime bugs (handled by KASAN), out-of-bounds access/overflow bugs. These are all memory safety and concurrency concerns that are already well-covered by existing tools, with no evidence of uninitialized memory usage risks or information leaks.

Therefore, since there are no new kernel structures sent to user space with uninitialized fields, no conditional logic depending on uninitialized variables, and no allocations or initialization of structures with uninitialized fields, I've concluded `NeedsKMSAN` is `false`.

To further solidify my evaluation, I made sure to compare the scope of the bugs covered by this series against what KASAN and LOCKDEP cover. The patch deals with memory safety aspects like UAF, OOB, double free, and leaks, as well as concurrency issues, all of which are thoroughly addressed by those existing detectors. Thus, invoking KMSAN would add significant overhead without providing any additional benefit for these changes.



96/3 2026/10/17 07:08 tool set-results
0m Args:
{
  "KMSANReasoning": "The patch series addresses several issues across the BPF subsystem, including:\n1. Use-after-free and lifetime bugs: invalidating dynptr packet slices on skb writes, tracking moved packet headers in bpf_skb_store_bytes/bpf_skb_meta_store_bytes, deferring BPF JIT image freeing through RCU work, keeping net_device references in cpumap, and tracking socket references in bpf_sk_storage iterator.\n2. Memory leaks and reference counting: adding missing iput() on token creation error, adding kfree_const() for strings duplicated with kstrdup_const() in perf event info queries and fdinfo dumps.\n3. Concurrency and locking: using try_cmpxchg_local for per-cpu extra elems in hashtab, enforcing RCU critical sections for sleepable programs and iterator callbacks, and adding NOSLEEP restrictions on task_vma iterator.\n4. Verifier bounds checking: adding tracking for rdwr buffer writes (min_rdwr_write / max_rdwr_write) to prevent BPF programs from corrupting special BTF record fields (bpf_spin_lock, bpf_timer, etc.) in map values.\n\nKMSAN vs. KASAN analysis:\n- All new struct fields (such as min_rdwr_write, max_rdwr_write, sleepable_async_cb, rwork, in_rcu_callback_fn, dynptr_write_type, dead_sks, held, nr_held) reside within objects allocated with __GFP_ZERO or kzalloc (e.g., bpf_prog_aux, bpf_func_state, bpf_cpu_map_entry, seq_file private data).\n- The patch explicitly eliminates a potential uninitialized slab read in bpf_sk_storage_clone() by setting refcount_set(\u0026newsk-\u003esk_refcnt, 0) before linking elements.\n- No uninitialized data or struct padding is exposed or copied to user space. The changes touching user copy routines (bpf_perf_link_fill_common, bpf_task_fd_query) only ensure allocated buffers are properly freed with kfree_const().\n- The modified bounds checks and verifier logic tighten constraints rather than opening up uninitialized buffer reads.\n- The bugs targeted by these changes (UAF, memory leaks, concurrency races, refcount underflows) are comprehensively covered by KASAN, KMEMLEAK, and LOCKDEP in standard fuzzing builds.\n\nTherefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

Results:
{
  "KMSANReasoning": "The patch series addresses several issues across the BPF subsystem, including:\n1. Use-after-free and lifetime bugs: invalidating dynptr packet slices on skb writes, tracking moved packet headers in bpf_skb_store_bytes/bpf_skb_meta_store_bytes, deferring BPF JIT image freeing through RCU work, keeping net_device references in cpumap, and tracking socket references in bpf_sk_storage iterator.\n2. Memory leaks and reference counting: adding missing iput() on token creation error, adding kfree_const() for strings duplicated with kstrdup_const() in perf event info queries and fdinfo dumps.\n3. Concurrency and locking: using try_cmpxchg_local for per-cpu extra elems in hashtab, enforcing RCU critical sections for sleepable programs and iterator callbacks, and adding NOSLEEP restrictions on task_vma iterator.\n4. Verifier bounds checking: adding tracking for rdwr buffer writes (min_rdwr_write / max_rdwr_write) to prevent BPF programs from corrupting special BTF record fields (bpf_spin_lock, bpf_timer, etc.) in map values.\n\nKMSAN vs. KASAN analysis:\n- All new struct fields (such as min_rdwr_write, max_rdwr_write, sleepable_async_cb, rwork, in_rcu_callback_fn, dynptr_write_type, dead_sks, held, nr_held) reside within objects allocated with __GFP_ZERO or kzalloc (e.g., bpf_prog_aux, bpf_func_state, bpf_cpu_map_entry, seq_file private data).\n- The patch explicitly eliminates a potential uninitialized slab read in bpf_sk_storage_clone() by setting refcount_set(\u0026newsk-\u003esk_refcnt, 0) before linking elements.\n- No uninitialized data or struct padding is exposed or copied to user space. The changes touching user copy routines (bpf_perf_link_fill_common, bpf_task_fd_query) only ensure allocated buffers are properly freed with kfree_const().\n- The modified bounds checks and verifier logic tighten constraints rather than opening up uninitialized buffer reads.\n- The bugs targeted by these changes (UAF, memory leaks, concurrency races, refcount underflows) are comprehensively covered by KASAN, KMEMLEAK, and LOCKDEP in standard fuzzing builds.\n\nTherefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)