AI Trajectory


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

Results:
{
  "EnableConfigs": [
    "BPF_SYSCALL",
    "DEBUG_INFO_BTF"
  ],
  "FocusSymbols": [
    "gen_kfunc_arg_proto",
    "get_kfunc_arg_type",
    "process_map_ptr_arg",
    "check_kfunc_args",
    "check_func_arg",
    "check_mem_size_reg",
    "check_mem_reg",
    "process_const_arg"
  ],
  "Reasoning": "The patch significantly refactors how the eBPF verifier handles arguments for kfuncs and helper functions, introducing new argument types (ARG_MEM_SIZE, ARG_MEM_SIZE_OR_ZERO) and a new way to generate kfunc prototypes (gen_kfunc_arg_proto). This is core verifier logic that is highly complex and prone to security vulnerabilities, making it a prime target for fuzzing.",
  "WorthFuzzing": true
}

1/1 2026/07/24 09:17 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit a49c57a3e69e2f3aac56ba2231f49f2aad1156a5\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Fri Jul 24 09:17:05 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst\nindex c801a330aece08..cbde86d082ccea 100644\n--- a/Documentation/bpf/kfuncs.rst\n+++ b/Documentation/bpf/kfuncs.rst\n@@ -250,6 +250,34 @@ Or::\n                 ...\n         }\n \n+2.3.7 __const_map and __map Annotations\n+---------------------------------------\n+\n+These annotations are used for ``struct bpf_map *`` arguments and distinguish a\n+verifier-known map from an opaque one.\n+\n+``__const_map`` indicates a map must be known at the verification time, i.e. a\n+concrete map fd the BPF program references directly.\n+\n+An example is given below::\n+\n+        __bpf_kfunc int bpf_wq_init(struct bpf_wq *wq, void *p__const_map,\n+                                    unsigned int flags)\n+        {\n+                ...\n+        }\n+\n+``__map`` indicates an opaque ``struct bpf_map *`` that may be resolved\n+at run time. The argument may take either a map fd or a ``PTR_TO_BTF_ID``\n+``struct bpf_map`` pointer.\n+\n+An example is given below::\n+\n+        __bpf_kfunc void *bpf_arena_alloc_pages(void *p__map, ...)\n+        {\n+                ...\n+        }\n+\n .. _BPF_kfunc_nodef:\n \n 2.4 Using an existing kernel function\n@@ -411,7 +439,7 @@ Example declaration:\n .. code-block:: c\n \n \t__bpf_kfunc int bpf_task_work_schedule_signal(struct task_struct *task, struct bpf_task_work *tw,\n-\t\t\t\t\t\t      void *map__map, bpf_task_work_callback_t callback,\n+\t\t\t\t\t\t      void *map__const_map, bpf_task_work_callback_t callback,\n \t\t\t\t\t\t      struct bpf_prog_aux *aux) { ... }\n \n Example usage in BPF program:\ndiff --git a/include/linux/bpf.h b/include/linux/bpf.h\nindex d9542127dfdfc0..2ea5ce30f729bb 100644\n--- a/include/linux/bpf.h\n+++ b/include/linux/bpf.h\n@@ -748,6 +748,7 @@ extern const struct bpf_map_ops bpf_map_offload_ops;\n enum bpf_type_flag {\n \t/* PTR may be NULL. */\n \tPTR_MAYBE_NULL\t\t= BIT(0 + BPF_BASE_TYPE_BITS),\n+\tSCALAR_MAYBE_ZERO\t= PTR_MAYBE_NULL,\n \n \t/* MEM is read-only. When applied on bpf_arg, it indicates the arg is\n \t * compatible with both mutable and immutable memory.\n@@ -888,8 +889,7 @@ enum bpf_arg_type {\n \tARG_PTR_TO_MEM,\t\t/* pointer to valid memory (stack, packet, map value) */\n \tARG_PTR_TO_ARENA,\n \n-\tARG_CONST_SIZE,\t\t/* number of bytes accessed from memory */\n-\tARG_CONST_SIZE_OR_ZERO,\t/* number of bytes accessed from memory or 0 */\n+\tARG_MEM_SIZE,\t\t/* number of bytes accessed from memory */\n \n \tARG_PTR_TO_CTX,\t\t/* pointer to context */\n \tARG_ANYTHING,\t\t/* any (initialized) argument is ok */\n@@ -922,6 +922,8 @@ enum bpf_arg_type {\n \tARG_PTR_TO_UNINIT_MEM\t\t= MEM_UNINIT | MEM_WRITE | ARG_PTR_TO_MEM,\n \t/* Pointer to valid memory of size known at compile time. */\n \tARG_PTR_TO_FIXED_SIZE_MEM\t= MEM_FIXED_SIZE | ARG_PTR_TO_MEM,\n+\t/* Number of bytes accessed from memory, or 0. */\n+\tARG_MEM_SIZE_OR_ZERO\t\t= SCALAR_MAYBE_ZERO | ARG_MEM_SIZE,\n \n \t/* This must be the last entry. Its purpose is to ensure the enum is\n \t * wide enough to hold the higher bits reserved for bpf_type_flag.\n@@ -960,6 +962,21 @@ enum bpf_return_type {\n };\n static_assert(__BPF_RET_TYPE_MAX \u003c= BPF_BASE_TYPE_LIMIT);\n \n+/* The longest tracepoint has 12 args.\n+ * See include/trace/bpf_probe.h\n+ *\n+ * Also reuse this macro for maximum number of arguments a BPF function\n+ * or a kfunc can have. Args 1-5 are passed in registers, args 6-12 via\n+ * stack arg slots. The JIT may map some stack arg slots to registers based\n+ * on the native calling convention (e.g., arg 6 to R9 on x86-64).\n+ */\n+#define MAX_BPF_FUNC_ARGS 12\n+\n+/* The maximum number of arguments passed through registers\n+ * a single function may have.\n+ */\n+#define MAX_BPF_FUNC_REG_ARGS 5\n+\n /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs\n  * to in-kernel helper functions and for adjusting imm32 field in BPF_CALL\n  * instructions after verifying\n@@ -984,7 +1001,7 @@ struct bpf_func_proto {\n \t\t\tenum bpf_arg_type arg4_type;\n \t\t\tenum bpf_arg_type arg5_type;\n \t\t};\n-\t\tenum bpf_arg_type arg_type[5];\n+\t\tenum bpf_arg_type arg_type[MAX_BPF_FUNC_ARGS];\n \t};\n \tunion {\n \t\tstruct {\n@@ -994,7 +1011,7 @@ struct bpf_func_proto {\n \t\t\tu32 *arg4_btf_id;\n \t\t\tu32 *arg5_btf_id;\n \t\t};\n-\t\tu32 *arg_btf_id[5];\n+\t\tu32 *arg_btf_id[MAX_BPF_FUNC_ARGS];\n \t\tstruct {\n \t\t\tsize_t arg1_size;\n \t\t\tsize_t arg2_size;\n@@ -1002,7 +1019,7 @@ struct bpf_func_proto {\n \t\t\tsize_t arg4_size;\n \t\t\tsize_t arg5_size;\n \t\t};\n-\t\tsize_t arg_size[5];\n+\t\tsize_t arg_size[MAX_BPF_FUNC_ARGS];\n \t};\n \tint *ret_btf_id; /* return value btf_id */\n \tbool (*allowed)(const struct bpf_prog *prog);\n@@ -1192,21 +1209,6 @@ struct bpf_prog_offload {\n \tu32\t\t\tjited_len;\n };\n \n-/* The longest tracepoint has 12 args.\n- * See include/trace/bpf_probe.h\n- *\n- * Also reuse this macro for maximum number of arguments a BPF function\n- * or a kfunc can have. Args 1-5 are passed in registers, args 6-12 via\n- * stack arg slots. The JIT may map some stack arg slots to registers based\n- * on the native calling convention (e.g., arg 6 to R9 on x86-64).\n- */\n-#define MAX_BPF_FUNC_ARGS 12\n-\n-/* The maximum number of arguments passed through registers\n- * a single function may have.\n- */\n-#define MAX_BPF_FUNC_REG_ARGS 5\n-\n /* The argument is a structure or a union. */\n #define BTF_FMODEL_STRUCT_ARG\t\tBIT(0)\n \ndiff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h\nindex 682c2cd3b84430..0655164e6af2eb 100644\n--- a/include/linux/bpf_verifier.h\n+++ b/include/linux/bpf_verifier.h\n@@ -15,7 +15,7 @@\n  * ensures that umax_value + (int)off + (int)size cannot overflow a u64.\n  */\n #define BPF_MAX_VAR_OFF\t(1 \u003c\u003c 29)\n-/* Maximum variable size permitted for ARG_CONST_SIZE[_OR_ZERO].  This ensures\n+/* Maximum variable size permitted for ARG_MEM_SIZE[_OR_ZERO].  This ensures\n  * that converting umax_value to int cannot overflow.\n  */\n #define BPF_MAX_VAR_SIZ\t(1 \u003c\u003c 29)\n@@ -1188,6 +1188,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,\n \t\t\t    u32 btf_id,\n \t\t\t    struct bpf_attach_target_info *tgt_info);\n void bpf_free_kfunc_btf_tab(struct bpf_kfunc_btf_tab *tab);\n+void bpf_free_kfunc_desc_tab(struct bpf_kfunc_desc_tab *tab);\n \n int mark_chain_precision(struct bpf_verifier_env *env, int regno);\n \n@@ -1305,8 +1306,19 @@ static inline u32 type_flag(u32 type)\n /* only use after check_attach_btf_id() */\n static inline enum bpf_prog_type resolve_prog_type(const struct bpf_prog *prog)\n {\n-\treturn (prog-\u003etype == BPF_PROG_TYPE_EXT \u0026\u0026 prog-\u003eaux-\u003esaved_dst_prog_type) ?\n-\t\tprog-\u003eaux-\u003esaved_dst_prog_type : prog-\u003etype;\n+\tif (prog-\u003etype == BPF_PROG_TYPE_EXT) {\n+\t\t/*\n+\t\t * saved_dst_prog_type is only set once check_attach_btf_id()\n+\t\t * runs. Before that -- e.g. when generating kfunc prototypes at\n+\t\t * add-call time -- fall back to the attach target's type, which\n+\t\t * is available from load time and holds the same value.\n+\t\t */\n+\t\tif (prog-\u003eaux-\u003esaved_dst_prog_type)\n+\t\t\treturn prog-\u003eaux-\u003esaved_dst_prog_type;\n+\t\tif (prog-\u003eaux-\u003edst_prog)\n+\t\t\treturn prog-\u003eaux-\u003edst_prog-\u003etype;\n+\t}\n+\treturn prog-\u003etype;\n }\n \n static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)\n@@ -1479,10 +1491,17 @@ struct ret_mem_desc {\n \tbool found;\n };\n \n+/* A constant scalar argument; Populated by process_const_arg() */\n+struct arg_constant_desc {\n+\tu64 value;\n+\tbool found;\n+};\n+\n struct bpf_call_arg_meta {\n \t/* Common */\n \tstruct btf *btf;\n \tu32 func_id;\n+\tconst struct bpf_func_proto *fn;\n \tu8 release_regno;\n \tu32 ret_btf_id;\n \tu32 subprogno;\n@@ -1496,10 +1515,7 @@ struct bpf_call_arg_meta {\n \tu32 kfunc_flags;\n \tconst struct btf_type *func_proto;\n \tconst char *func_name;\n-\tstruct {\n-\t\tu64 value;\n-\t\tbool found;\n-\t} arg_constant;\n+\tstruct arg_constant_desc arg_constant;\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\n@@ -1614,6 +1630,7 @@ enum bpf_reg_arg_type {\n \n struct bpf_kfunc_desc {\n \tstruct btf_func_model func_model;\n+\tstruct bpf_func_proto *proto;\n \tu32 func_id;\n \ts32 imm;\n \tu16 offset;\ndiff --git a/kernel/bpf/backtrack.c b/kernel/bpf/backtrack.c\nindex 2e4ae0ef08609d..2f473ad4fd7c1c 100644\n--- a/kernel/bpf/backtrack.c\n+++ b/kernel/bpf/backtrack.c\n@@ -636,7 +636,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,\n  * r5 += 1\n  * ...\n  * call bpf_perf_event_output#25\n- *   where .arg5_type = ARG_CONST_SIZE_OR_ZERO\n+ *   where .arg5_type = ARG_MEM_SIZE_OR_ZERO\n  *\n  * and this case:\n  * r6 = 1\ndiff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c\nindex 3983b4ce73c811..82c5988417a0cf 100644\n--- a/kernel/bpf/bpf_lsm.c\n+++ b/kernel/bpf/bpf_lsm.c\n@@ -186,7 +186,7 @@ static const struct bpf_func_proto bpf_ima_inode_hash_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026bpf_ima_inode_hash_btf_ids[0],\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.allowed\t= bpf_ima_inode_hash_allowed,\n };\n \n@@ -205,7 +205,7 @@ static const struct bpf_func_proto bpf_ima_file_hash_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026bpf_ima_file_hash_btf_ids[0],\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.allowed\t= bpf_ima_inode_hash_allowed,\n };\n \ndiff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c\nindex cbb1e49b9bcbf5..a23a42cbe3b135 100644\n--- a/kernel/bpf/btf.c\n+++ b/kernel/bpf/btf.c\n@@ -8707,7 +8707,7 @@ const struct bpf_func_proto bpf_btf_find_by_name_kind_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg2_type\t= ARG_CONST_SIZE,\n+\t.arg2_type\t= ARG_MEM_SIZE,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_ANYTHING,\n };\ndiff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c\nindex 4355ccb78a9c67..fb9357b64cadbc 100644\n--- a/kernel/bpf/cgroup.c\n+++ b/kernel/bpf/cgroup.c\n@@ -2305,7 +2305,7 @@ static const struct bpf_func_proto bpf_sysctl_get_name_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_WRITE,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -2347,7 +2347,7 @@ static const struct bpf_func_proto bpf_sysctl_get_current_value_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_3(bpf_sysctl_get_new_value, struct bpf_sysctl_kern *, ctx, char *, buf,\n@@ -2367,7 +2367,7 @@ static const struct bpf_func_proto bpf_sysctl_get_new_value_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_3(bpf_sysctl_set_new_value, struct bpf_sysctl_kern *, ctx,\n@@ -2393,7 +2393,7 @@ static const struct bpf_func_proto bpf_sysctl_set_new_value_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n };\n \n static const struct bpf_func_proto *\ndiff --git a/kernel/bpf/core.c b/kernel/bpf/core.c\nindex 47fe047ad30b88..a30e7471e9d81e 100644\n--- a/kernel/bpf/core.c\n+++ b/kernel/bpf/core.c\n@@ -198,7 +198,9 @@ void bpf_prog_jit_attempt_done(struct bpf_prog *prog)\n \t\tprog-\u003eaux-\u003ejited_linfo = NULL;\n \t}\n \n-\tkfree(prog-\u003eaux-\u003ekfunc_tab);\n+#ifdef CONFIG_BPF_SYSCALL\n+\tbpf_free_kfunc_desc_tab(prog-\u003eaux-\u003ekfunc_tab);\n+#endif\n \tprog-\u003eaux-\u003ekfunc_tab = NULL;\n }\n \ndiff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c\nindex c18f1e16edee4c..18be5d6e4f9c29 100644\n--- a/kernel/bpf/helpers.c\n+++ b/kernel/bpf/helpers.c\n@@ -278,7 +278,7 @@ const struct bpf_func_proto bpf_get_current_comm_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE,\n+\t.arg2_type\t= ARG_MEM_SIZE,\n };\n \n #if defined(CONFIG_QUEUED_SPINLOCKS) || defined(CONFIG_BPF_ARCH_SPINLOCK)\n@@ -539,7 +539,7 @@ const struct bpf_func_proto bpf_strtol_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg2_type\t= ARG_CONST_SIZE,\n+\t.arg2_type\t= ARG_MEM_SIZE,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,\n \t.arg4_size\t= sizeof(s64),\n@@ -567,7 +567,7 @@ const struct bpf_func_proto bpf_strtoul_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg2_type\t= ARG_CONST_SIZE,\n+\t.arg2_type\t= ARG_MEM_SIZE,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,\n \t.arg4_size\t= sizeof(u64),\n@@ -583,7 +583,7 @@ static const struct bpf_func_proto bpf_strncmp_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg2_type\t= ARG_CONST_SIZE,\n+\t.arg2_type\t= ARG_MEM_SIZE,\n \t.arg3_type\t= ARG_PTR_TO_CONST_STR,\n };\n \n@@ -627,7 +627,7 @@ const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto = {\n \t.arg1_type\t= ARG_ANYTHING,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type      = ARG_PTR_TO_UNINIT_MEM,\n-\t.arg4_type      = ARG_CONST_SIZE,\n+\t.arg4_type      = ARG_MEM_SIZE,\n };\n \n static const struct bpf_func_proto bpf_get_raw_smp_processor_id_proto = {\n@@ -653,7 +653,7 @@ const struct bpf_func_proto bpf_event_output_data_proto =  {\n \t.arg2_type      = ARG_CONST_MAP_PTR,\n \t.arg3_type      = ARG_ANYTHING,\n \t.arg4_type      = ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type      = ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type      = ARG_MEM_SIZE_OR_ZERO,\n };\n \n BPF_CALL_3(bpf_copy_from_user, void *, dst, u32, size,\n@@ -675,7 +675,7 @@ const struct bpf_func_proto bpf_copy_from_user_proto = {\n \t.might_sleep\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n };\n \n@@ -706,7 +706,7 @@ const struct bpf_func_proto bpf_copy_from_user_task_proto = {\n \t.might_sleep\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg4_btf_id\t= \u0026btf_tracing_ids[BTF_TRACING_TYPE_TASK],\n@@ -1093,10 +1093,10 @@ const struct bpf_func_proto bpf_snprintf_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_PTR_TO_CONST_STR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n static void *map_key_from_value(struct bpf_map *map, void *value, u32 *arr_idx)\n@@ -1888,7 +1888,7 @@ static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT | MEM_WRITE,\n };\n@@ -1943,7 +1943,7 @@ static const struct bpf_func_proto bpf_dynptr_read_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_PTR_TO_DYNPTR,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n@@ -2004,7 +2004,7 @@ static const struct bpf_func_proto bpf_dynptr_write_proto = {\n \t.arg1_type\t= ARG_PTR_TO_DYNPTR,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg4_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n \n@@ -3404,10 +3404,10 @@ __bpf_kfunc void bpf_throw(u64 cookie)\n \tWARN(1, \"A call to BPF exception callback should never return\\n\");\n }\n \n-__bpf_kfunc int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags)\n+__bpf_kfunc int bpf_wq_init(struct bpf_wq *wq, void *p__const_map, unsigned int flags)\n {\n \tstruct bpf_async_kern *async = (struct bpf_async_kern *)wq;\n-\tstruct bpf_map *map = p__map;\n+\tstruct bpf_map *map = p__const_map;\n \n \tBUILD_BUG_ON(sizeof(struct bpf_async_kern) \u003e sizeof(struct bpf_wq));\n \tBUILD_BUG_ON(__alignof__(struct bpf_async_kern) != __alignof__(struct bpf_wq));\n@@ -4642,17 +4642,17 @@ static int bpf_task_work_schedule(struct task_struct *task, struct bpf_task_work\n  * mode\n  * @task: Task struct for which callback should be scheduled\n  * @tw: Pointer to struct bpf_task_work in BPF map value for internal bookkeeping\n- * @map__map: bpf_map that embeds struct bpf_task_work in the values\n+ * @map__const_map: bpf_map that embeds struct bpf_task_work in the values\n  * @callback: pointer to BPF subprogram to call\n  * @aux: pointer to bpf_prog_aux of the caller BPF program, implicitly set by the verifier\n  *\n  * Return: 0 if task work has been scheduled successfully, negative error code otherwise\n  */\n __bpf_kfunc int bpf_task_work_schedule_signal(struct task_struct *task, struct bpf_task_work *tw,\n-\t\t\t\t\t      void *map__map, bpf_task_work_callback_t callback,\n+\t\t\t\t\t      void *map__const_map, bpf_task_work_callback_t callback,\n \t\t\t\t\t      struct bpf_prog_aux *aux)\n {\n-\treturn bpf_task_work_schedule(task, tw, map__map, callback, aux, TWA_SIGNAL);\n+\treturn bpf_task_work_schedule(task, tw, map__const_map, callback, aux, TWA_SIGNAL);\n }\n \n /**\n@@ -4660,17 +4660,17 @@ __bpf_kfunc int bpf_task_work_schedule_signal(struct task_struct *task, struct b\n  * mode\n  * @task: Task struct for which callback should be scheduled\n  * @tw: Pointer to struct bpf_task_work in BPF map value for internal bookkeeping\n- * @map__map: bpf_map that embeds struct bpf_task_work in the values\n+ * @map__const_map: bpf_map that embeds struct bpf_task_work in the values\n  * @callback: pointer to BPF subprogram to call\n  * @aux: pointer to bpf_prog_aux of the caller BPF program, implicitly set by the verifier\n  *\n  * Return: 0 if task work has been scheduled successfully, negative error code otherwise\n  */\n __bpf_kfunc int bpf_task_work_schedule_resume(struct task_struct *task, struct bpf_task_work *tw,\n-\t\t\t\t\t      void *map__map, bpf_task_work_callback_t callback,\n+\t\t\t\t\t      void *map__const_map, bpf_task_work_callback_t callback,\n \t\t\t\t\t      struct bpf_prog_aux *aux)\n {\n-\treturn bpf_task_work_schedule(task, tw, map__map, callback, aux, TWA_RESUME);\n+\treturn bpf_task_work_schedule(task, tw, map__const_map, callback, aux, TWA_RESUME);\n }\n \n static int make_file_dynptr(struct file *file, u32 flags, bool may_sleep,\ndiff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c\nindex 35ae64ade36b83..c1bf7a197a96f3 100644\n--- a/kernel/bpf/ringbuf.c\n+++ b/kernel/bpf/ringbuf.c\n@@ -634,7 +634,7 @@ const struct bpf_func_proto bpf_ringbuf_output_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \ndiff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c\nindex 41fe87d7302f22..463f94ba1cc478 100644\n--- a/kernel/bpf/stackmap.c\n+++ b/kernel/bpf/stackmap.c\n@@ -781,7 +781,7 @@ const struct bpf_func_proto bpf_get_stack_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -797,7 +797,7 @@ const struct bpf_func_proto bpf_get_stack_sleepable_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -831,7 +831,7 @@ const struct bpf_func_proto bpf_get_task_stack_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026btf_tracing_ids[BTF_TRACING_TYPE_TASK],\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -848,7 +848,7 @@ const struct bpf_func_proto bpf_get_task_stack_sleepable_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026btf_tracing_ids[BTF_TRACING_TYPE_TASK],\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -911,7 +911,7 @@ const struct bpf_func_proto bpf_get_stack_proto_pe = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \ndiff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c\nindex 0ff9e3aa293d57..0b5dc6788ba27f 100644\n--- a/kernel/bpf/syscall.c\n+++ b/kernel/bpf/syscall.c\n@@ -2444,7 +2444,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)\n \tmodule_put(prog-\u003eaux-\u003emod);\n \tkvfree(prog-\u003eaux-\u003ejited_linfo);\n \tkvfree(prog-\u003eaux-\u003elinfo);\n-\tkfree(prog-\u003eaux-\u003ekfunc_tab);\n+\tbpf_free_kfunc_desc_tab(prog-\u003eaux-\u003ekfunc_tab);\n \tkfree(prog-\u003eaux-\u003ectx_arg_info);\n \tif (prog-\u003eaux-\u003eattach_btf)\n \t\tbtf_put(prog-\u003eaux-\u003eattach_btf);\n@@ -6544,7 +6544,7 @@ static const struct bpf_func_proto bpf_sys_bpf_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_ANYTHING,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n };\n \n const struct bpf_func_proto * __weak\n@@ -6591,7 +6591,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,\n \t.arg4_size\t= sizeof(u64),\ndiff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c\nindex 52be0a118cce07..aca37a7bf2cbc7 100644\n--- a/kernel/bpf/verifier.c\n+++ b/kernel/bpf/verifier.c\n@@ -2719,8 +2719,25 @@ static int fetch_kfunc_meta(struct bpf_verifier_env *env,\n \treturn 0;\n }\n \n+static int gen_kfunc_arg_proto(struct bpf_verifier_env *env,\n+\t\t\t       struct bpf_call_arg_meta *meta,\n+\t\t\t       struct bpf_func_proto *proto);\n+\n+void bpf_free_kfunc_desc_tab(struct bpf_kfunc_desc_tab *tab)\n+{\n+\tu32 i;\n+\n+\tif (!tab)\n+\t\treturn;\n+\tfor (i = 0; i \u003c tab-\u003enr_descs; i++)\n+\t\tkfree(tab-\u003edescs[i].proto);\n+\tkfree(tab);\n+}\n+\n int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset)\n {\n+\tstruct bpf_call_arg_meta meta;\n+\tstruct bpf_func_proto *proto;\n \tstruct bpf_kfunc_btf_tab *btf_tab;\n \tstruct btf_func_model func_model;\n \tstruct bpf_kfunc_desc_tab *tab;\n@@ -2806,11 +2823,29 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset)\n \tif (err)\n \t\treturn err;\n \n+\tproto = kzalloc_obj(*proto, GFP_KERNEL_ACCOUNT);\n+\tif (!proto)\n+\t\treturn -ENOMEM;\n+\n+\tmemset(\u0026meta, 0, sizeof(meta));\n+\tmeta.btf = kfunc.btf;\n+\tmeta.func_id = kfunc.id;\n+\tmeta.func_proto = kfunc.proto;\n+\tmeta.func_name = kfunc.name;\n+\tmeta.kfunc_flags = kfunc.flags ? *kfunc.flags : 0;\n+\n+\terr = gen_kfunc_arg_proto(env, \u0026meta, proto);\n+\tif (err) {\n+\t\tkfree(proto);\n+\t\treturn err;\n+\t}\n+\n \tdesc = \u0026tab-\u003edescs[tab-\u003enr_descs++];\n \tdesc-\u003efunc_id = func_id;\n \tdesc-\u003eoffset = offset;\n \tdesc-\u003eaddr = addr;\n \tdesc-\u003efunc_model = func_model;\n+\tdesc-\u003eproto = proto;\n \tsort(tab-\u003edescs, tab-\u003enr_descs, sizeof(tab-\u003edescs[0]),\n \t     kfunc_desc_cmp_by_id_off, NULL);\n \treturn 0;\n@@ -4924,6 +4959,19 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = {\n \t[CONST_PTR_TO_MAP] = btf_bpf_map_id,\n };\n \n+static enum bpf_reg_type lookup_reg2btf_ids(const struct btf_type *ref_t)\n+{\n+\tenum bpf_reg_type type;\n+\n+\tfor (type = 0; type \u003c __BPF_REG_TYPE_MAX; type++) {\n+\t\tif (reg2btf_ids[type] \u0026\u0026\n+\t\t    btf_type_by_id(btf_vmlinux, *reg2btf_ids[type]) == ref_t)\n+\t\t\treturn type;\n+\t}\n+\n+\treturn NOT_INIT;\n+}\n+\n static bool is_trusted_reg(struct bpf_verifier_env *env, const struct bpf_reg_state *reg)\n {\n \t/* A referenced register is always trusted. */\n@@ -6873,7 +6921,14 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,\n \t\t\t      bool zero_size_allowed,\n \t\t\t      struct bpf_call_arg_meta *meta)\n {\n-\tint err;\n+\tbool may_be_null = type_may_be_null(mem_reg-\u003etype);\n+\tstruct bpf_reg_state saved_reg;\n+\tint err = 0;\n+\n+\tif (may_be_null) {\n+\t\tsaved_reg = *mem_reg;\n+\t\tmark_ptr_not_null_reg(mem_reg);\n+\t}\n \n \t/* This is used to refine r0 return value bounds for helpers\n \t * that enforce this value as an upper bound on return values.\n@@ -6910,8 +6965,14 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,\n \t\t\treg_arg_name(env, size_argno));\n \t\treturn -EACCES;\n \t}\n-\terr = check_helper_mem_access(env, mem_reg, mem_argno, reg_umax(size_reg),\n-\t\t\t\t      access_type, zero_size_allowed, meta);\n+\n+\tif (access_type \u0026 BPF_READ)\n+\t\terr = check_helper_mem_access(env, mem_reg, mem_argno, reg_umax(size_reg),\n+\t\t\t\t\t      BPF_READ, zero_size_allowed, meta);\n+\tif (!err \u0026\u0026 access_type \u0026 BPF_WRITE)\n+\t\terr = check_helper_mem_access(env, mem_reg, mem_argno, reg_umax(size_reg),\n+\t\t\t\t\t      BPF_WRITE, zero_size_allowed, meta);\n+\n \tif (!err) {\n \t\tint regno = reg_from_argno(size_argno);\n \n@@ -6920,15 +6981,22 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,\n \t\telse\n \t\t\terr = mark_stack_arg_precision(env, arg_idx_from_argno(size_argno));\n \t}\n+\n+\tif (may_be_null)\n+\t\t*mem_reg = saved_reg;\n+\n \treturn err;\n }\n \n static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n-\t\t\t argno_t argno, u32 mem_size)\n+\t\t\t argno_t argno, u32 mem_size, enum bpf_access_type access_type,\n+\t\t\t struct bpf_call_arg_meta *meta)\n {\n+\t/* meta-\u003ebtf is set only for kfuncs; a NULL meta means a global subprog. */\n+\tbool helper = meta \u0026\u0026 !meta-\u003ebtf;\n \tbool may_be_null = type_may_be_null(reg-\u003etype);\n \tstruct bpf_reg_state saved_reg;\n-\tint err;\n+\tint size, err = 0;\n \n \tif (bpf_register_is_null(reg))\n \t\treturn 0;\n@@ -6948,10 +7016,12 @@ static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg\n \t\tmark_ptr_not_null_reg(reg);\n \t}\n \n-\tint size = base_type(reg-\u003etype) == PTR_TO_STACK ? -(int)mem_size : mem_size;\n+\tsize = (!helper \u0026\u0026 base_type(reg-\u003etype) == PTR_TO_STACK) ? -(int)mem_size : mem_size;\n \n-\terr = check_helper_mem_access(env, reg, argno, size, BPF_READ, true, NULL);\n-\terr = err ?: check_helper_mem_access(env, reg, argno, size, BPF_WRITE, true, NULL);\n+\tif (access_type \u0026 BPF_READ)\n+\t\terr = check_helper_mem_access(env, reg, argno, size, BPF_READ, true, meta);\n+\tif (!err \u0026\u0026 (access_type \u0026 BPF_WRITE))\n+\t\terr = check_helper_mem_access(env, reg, argno, size, BPF_WRITE, true, meta);\n \n \tif (may_be_null)\n \t\t*reg = saved_reg;\n@@ -6993,28 +7063,33 @@ static int process_const_alloc_mem_size(struct bpf_verifier_env *env, struct bpf\n \treturn 0;\n }\n \n-static int check_kfunc_mem_size_reg(struct bpf_verifier_env *env, struct bpf_reg_state *mem_reg,\n-\t\t\t\t    struct bpf_reg_state *size_reg, argno_t mem_argno, argno_t size_argno)\n+static int process_const_arg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n+\t\t\t     argno_t argno, struct bpf_call_arg_meta *meta)\n {\n-\tbool may_be_null = type_may_be_null(mem_reg-\u003etype);\n-\tstruct bpf_reg_state saved_reg;\n-\tstruct bpf_call_arg_meta meta;\n+\tint regno = reg_from_argno(argno);\n \tint err;\n \n-\tmemset(\u0026meta, 0, sizeof(meta));\n+\tif (meta-\u003earg_constant.found) {\n+\t\tverifier_bug(env, \"only one constant argument permitted\");\n+\t\treturn -EFAULT;\n+\t}\n \n-\tif (may_be_null) {\n-\t\tsaved_reg = *mem_reg;\n-\t\tmark_ptr_not_null_reg(mem_reg);\n+\tif (!tnum_is_const(reg-\u003evar_off)) {\n+\t\tverbose(env, \"%s must be a known constant\\n\", reg_arg_name(env, argno));\n+\t\treturn -EINVAL;\n \t}\n \n-\terr = check_mem_size_reg(env, mem_reg, size_reg, mem_argno, size_argno, BPF_READ, true, \u0026meta);\n-\terr = err ?: check_mem_size_reg(env, mem_reg, size_reg, mem_argno, size_argno, BPF_WRITE, true, \u0026meta);\n+\tif (regno \u003e= 0)\n+\t\terr = mark_chain_precision(env, regno);\n+\telse\n+\t\terr = mark_stack_arg_precision(env, arg_idx_from_argno(argno));\n+\tif (err \u003c 0)\n+\t\treturn err;\n \n-\tif (may_be_null)\n-\t\t*mem_reg = saved_reg;\n+\tmeta-\u003earg_constant.found = true;\n+\tmeta-\u003earg_constant.value = reg-\u003evar_off.value;\n \n-\treturn err;\n+\treturn 0;\n }\n \n enum {\n@@ -7224,18 +7299,6 @@ static int process_timer_func(struct bpf_verifier_env *env, struct bpf_reg_state\n \treturn check_map_field_pointer(env, reg, argno, BPF_TIMER, map);\n }\n \n-static int process_timer_helper(struct bpf_verifier_env *env, struct bpf_reg_state *reg, argno_t argno,\n-\t\t\t\tstruct bpf_call_arg_meta *meta)\n-{\n-\treturn process_timer_func(env, reg, argno, \u0026meta-\u003emap);\n-}\n-\n-static int process_timer_kfunc(struct bpf_verifier_env *env, struct bpf_reg_state *reg, argno_t argno,\n-\t\t\t       struct bpf_call_arg_meta *meta)\n-{\n-\treturn process_timer_func(env, reg, argno, \u0026meta-\u003emap);\n-}\n-\n static int process_kptr_func(struct bpf_verifier_env *env, int regno,\n \t\t\t     struct bpf_call_arg_meta *meta)\n {\n@@ -7738,8 +7801,7 @@ static int process_iter_next_call(struct bpf_verifier_env *env, int insn_idx,\n \n static bool arg_type_is_mem_size(enum bpf_arg_type type)\n {\n-\treturn type == ARG_CONST_SIZE ||\n-\t       type == ARG_CONST_SIZE_OR_ZERO;\n+\treturn base_type(type) == ARG_MEM_SIZE;\n }\n \n static bool arg_type_is_raw_mem(enum bpf_arg_type type)\n@@ -7885,8 +7947,7 @@ static const struct bpf_reg_types dynptr_types = {\n static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {\n \t[ARG_PTR_TO_MAP_KEY]\t\t= \u0026mem_types,\n \t[ARG_PTR_TO_MAP_VALUE]\t\t= \u0026mem_types,\n-\t[ARG_CONST_SIZE]\t\t= \u0026scalar_types,\n-\t[ARG_CONST_SIZE_OR_ZERO]\t= \u0026scalar_types,\n+\t[ARG_MEM_SIZE]\t\t\t= \u0026scalar_types,\n \t[ARG_CONST_ALLOC_SIZE_OR_ZERO]\t= \u0026scalar_types,\n \t[ARG_CONST_MAP_PTR]\t\t= \u0026const_map_ptr_types,\n \t[ARG_PTR_TO_CTX]\t\t= \u0026context_types,\n@@ -8286,11 +8347,55 @@ static int get_constant_map_key(struct bpf_verifier_env *env,\n \n static bool can_elide_value_nullness(const struct bpf_map *map);\n \n+/* Record the bpf_map argument of a helper or kfunc call in meta-\u003emap.\n+ *\n+ * When meta-\u003emap is already set from an earlier argument (a timer, workqueue or\n+ * task_work object that is bound to a map), reject a map pointer that does not\n+ * match it. That object sits in the register right before the map argument, and\n+ * its type is taken from the bound map's record for the diagnostic.\n+ */\n+static int process_map_ptr_arg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n+\t\t\t       argno_t argno, struct bpf_call_arg_meta *meta)\n+{\n+\tint map_regno = reg_from_argno(argno);\n+\n+\t/* Use map_uid (which is unique id of inner map) to reject:\n+\t * inner_map1 = bpf_map_lookup_elem(outer_map, key1)\n+\t * inner_map2 = bpf_map_lookup_elem(outer_map, key2)\n+\t * if (inner_map1 \u0026\u0026 inner_map2) {\n+\t *     timer = bpf_map_lookup_elem(inner_map1);\n+\t *     if (timer)\n+\t *         // mismatch would have been allowed\n+\t *         bpf_timer_init(timer, inner_map2);\n+\t * }\n+\t *\n+\t * Comparing map_ptr is enough to distinguish normal and outer maps.\n+\t */\n+\tif (meta-\u003emap.ptr \u0026\u0026\n+\t    (meta-\u003emap.ptr != reg-\u003emap_ptr || meta-\u003emap.uid != reg-\u003emap_uid)) {\n+\t\tstruct btf_record *rec = meta-\u003emap.ptr-\u003erecord;\n+\t\tconst char *obj_name = \"workqueue\";\n+\n+\t\tif (rec-\u003etimer_off \u003e= 0)\n+\t\t\tobj_name = \"timer\";\n+\t\telse if (rec-\u003etask_work_off \u003e= 0)\n+\t\t\tobj_name = \"bpf_task_work\";\n+\n+\t\tverbose(env, \"%s pointer in R%d map_uid=%d doesn't match map pointer in R%d map_uid=%d\\n\",\n+\t\t\tobj_name, map_regno - 1, meta-\u003emap.uid, map_regno, reg-\u003emap_uid);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmeta-\u003emap.ptr = reg-\u003emap_ptr;\n+\tmeta-\u003emap.uid = reg-\u003emap_uid;\n+\treturn 0;\n+}\n+\n static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \t\t\t  struct bpf_call_arg_meta *meta,\n-\t\t\t  const struct bpf_func_proto *fn,\n \t\t\t  int insn_idx)\n {\n+\tconst struct bpf_func_proto *fn = meta-\u003efn;\n \tu32 regno = BPF_REG_1 + arg;\n \tstruct bpf_reg_state *reg = reg_state(env, regno);\n \tenum bpf_arg_type arg_type = fn-\u003earg_type[arg];\n@@ -8361,29 +8466,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \tswitch (base_type(arg_type)) {\n \tcase ARG_CONST_MAP_PTR:\n \t\t/* bpf_map_xxx(map_ptr) call: remember that map_ptr */\n-\t\tif (meta-\u003emap.ptr) {\n-\t\t\t/* Use map_uid (which is unique id of inner map) to reject:\n-\t\t\t * inner_map1 = bpf_map_lookup_elem(outer_map, key1)\n-\t\t\t * inner_map2 = bpf_map_lookup_elem(outer_map, key2)\n-\t\t\t * if (inner_map1 \u0026\u0026 inner_map2) {\n-\t\t\t *     timer = bpf_map_lookup_elem(inner_map1);\n-\t\t\t *     if (timer)\n-\t\t\t *         // mismatch would have been allowed\n-\t\t\t *         bpf_timer_init(timer, inner_map2);\n-\t\t\t * }\n-\t\t\t *\n-\t\t\t * Comparing map_ptr is enough to distinguish normal and outer maps.\n-\t\t\t */\n-\t\t\tif (meta-\u003emap.ptr != reg-\u003emap_ptr ||\n-\t\t\t    meta-\u003emap.uid != reg-\u003emap_uid) {\n-\t\t\t\tverbose(env,\n-\t\t\t\t\t\"timer pointer in R1 map_uid=%d doesn't match map pointer in R2 map_uid=%d\\n\",\n-\t\t\t\t\tmeta-\u003emap.uid, reg-\u003emap_uid);\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t}\n-\t\tmeta-\u003emap.ptr = reg-\u003emap_ptr;\n-\t\tmeta-\u003emap.uid = reg-\u003emap_uid;\n+\t\terr = process_map_ptr_arg(env, reg, argno, meta);\n+\t\tif (err)\n+\t\t\treturn err;\n \t\tbreak;\n \tcase ARG_PTR_TO_MAP_KEY:\n \t\t/* bpf_map_xxx(..., map_ptr, ..., key) call:\n@@ -8466,7 +8551,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \t\t}\n \t\tbreak;\n \tcase ARG_PTR_TO_TIMER:\n-\t\terr = process_timer_helper(env, reg, argno, meta);\n+\t\terr = process_timer_func(env, reg, argno, \u0026meta-\u003emap);\n \t\tif (err)\n \t\t\treturn err;\n \t\tbreak;\n@@ -8474,31 +8559,22 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \t\tmeta-\u003esubprogno = reg-\u003esubprogno;\n \t\tbreak;\n \tcase ARG_PTR_TO_MEM:\n-\t\t/* The access to this pointer is only checked when we hit the\n-\t\t * next is_mem_size argument below.\n-\t\t */\n \t\tif (arg_type \u0026 MEM_FIXED_SIZE) {\n-\t\t\terr = check_helper_mem_access(env, reg, argno, fn-\u003earg_size[arg],\n-\t\t\t\t\t\t      arg_type \u0026 MEM_WRITE ? BPF_WRITE : BPF_READ,\n-\t\t\t\t\t\t      false, meta);\n+\t\t\terr = check_mem_reg(env, reg, argno_from_reg(regno), fn-\u003earg_size[arg],\n+\t\t\t\t\t    arg_type \u0026 MEM_WRITE ? BPF_WRITE : BPF_READ, meta);\n \t\t\tif (err)\n \t\t\t\treturn err;\n \t\t\tif (arg_type \u0026 MEM_ALIGNED)\n \t\t\t\terr = check_ptr_alignment(env, reg, 0, fn-\u003earg_size[arg], true);\n+\t\t} else {\n+\t\t\tstruct bpf_reg_state *size_reg = reg_state(env, regno + 1);\n+\n+\t\t\terr = check_mem_size_reg(env, reg, size_reg, argno,\n+\t\t\t\t\t\t argno_from_reg(regno + 1),\n+\t\t\t\t\t\t arg_type \u0026 MEM_WRITE ? BPF_WRITE : BPF_READ,\n+\t\t\t\t\t\t fn-\u003earg_type[arg + 1] \u0026 SCALAR_MAYBE_ZERO, meta);\n \t\t}\n \t\tbreak;\n-\tcase ARG_CONST_SIZE:\n-\t\terr = check_mem_size_reg(env, reg_state(env, regno - 1), reg,\n-\t\t\t\t\t argno_from_reg(regno - 1), argno,\n-\t\t\t\t\t fn-\u003earg_type[arg - 1] \u0026 MEM_WRITE ? BPF_WRITE : BPF_READ,\n-\t\t\t\t\t false, meta);\n-\t\tbreak;\n-\tcase ARG_CONST_SIZE_OR_ZERO:\n-\t\terr = check_mem_size_reg(env, reg_state(env, regno - 1), reg,\n-\t\t\t\t\t argno_from_reg(regno - 1), argno,\n-\t\t\t\t\t fn-\u003earg_type[arg - 1] \u0026 MEM_WRITE ? BPF_WRITE : BPF_READ,\n-\t\t\t\t\t true, meta);\n-\t\tbreak;\n \tcase ARG_PTR_TO_DYNPTR:\n \t\terr = process_dynptr_func(env, reg, argno, insn_idx, arg_type, \u0026meta-\u003eref_obj,\n \t\t\t\t\t  \u0026meta-\u003edynptr);\n@@ -8823,7 +8899,7 @@ static bool check_raw_mode_ok(const struct bpf_func_proto *fn, struct bpf_call_a\n {\n \tint i;\n \n-\tfor (i = 0; i \u003c ARRAY_SIZE(fn-\u003earg_type); i++) {\n+\tfor (i = 0; i \u003c MAX_BPF_FUNC_REG_ARGS; i++) {\n \t\tif (!arg_type_is_raw_mem(fn-\u003earg_type[i]))\n \t\t\tcontinue;\n \t\tif (meta-\u003earg_raw_mem.regno)\n@@ -8840,7 +8916,7 @@ static bool check_args_pair_invalid(const struct bpf_func_proto *fn, int arg)\n \tbool has_size = fn-\u003earg_size[arg] != 0;\n \tbool is_next_size = false;\n \n-\tif (arg + 1 \u003c ARRAY_SIZE(fn-\u003earg_type))\n+\tif (arg + 1 \u003c MAX_BPF_FUNC_REG_ARGS)\n \t\tis_next_size = arg_type_is_mem_size(fn-\u003earg_type[arg + 1]);\n \n \tif (base_type(fn-\u003earg_type[arg]) != ARG_PTR_TO_MEM)\n@@ -8871,7 +8947,7 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn)\n {\n \tint i;\n \n-\tfor (i = 0; i \u003c ARRAY_SIZE(fn-\u003earg_type); i++) {\n+\tfor (i = 0; i \u003c MAX_BPF_FUNC_REG_ARGS; i++) {\n \t\tif (base_type(fn-\u003earg_type[i]) == ARG_PTR_TO_BTF_ID)\n \t\t\treturn !!fn-\u003earg_btf_id[i];\n \t\tif (base_type(fn-\u003earg_type[i]) == ARG_PTR_TO_SPIN_LOCK)\n@@ -8890,7 +8966,7 @@ static bool check_mem_arg_rw_flag_ok(const struct bpf_func_proto *fn)\n {\n \tint i;\n \n-\tfor (i = 0; i \u003c ARRAY_SIZE(fn-\u003earg_type); i++) {\n+\tfor (i = 0; i \u003c MAX_BPF_FUNC_REG_ARGS; i++) {\n \t\tenum bpf_arg_type arg_type = fn-\u003earg_type[i];\n \n \t\tif (base_type(arg_type) != ARG_PTR_TO_MEM)\n@@ -8906,7 +8982,7 @@ static bool check_proto_release_reg(const struct bpf_func_proto *fn, struct bpf_\n {\n \tint i;\n \n-\tfor (i = 0; i \u003c ARRAY_SIZE(fn-\u003earg_type); i++) {\n+\tfor (i = 0; i \u003c MAX_BPF_FUNC_REG_ARGS; i++) {\n \t\tenum bpf_arg_type arg_type = fn-\u003earg_type[i];\n \n \t\tif (arg_type_is_release(arg_type)) {\n@@ -9252,7 +9328,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,\n \t\t\tret = check_func_arg_reg_off(env, reg, argno, ARG_DONTCARE);\n \t\t\tif (ret \u003c 0)\n \t\t\t\treturn ret;\n-\t\t\tif (check_mem_reg(env, reg, argno, arg-\u003emem_size))\n+\t\t\tif (check_mem_reg(env, reg, argno, arg-\u003emem_size, BPF_READ | BPF_WRITE, NULL))\n \t\t\t\treturn -EINVAL;\n \t\t\tif (!(arg-\u003earg_type \u0026 PTR_MAYBE_NULL) \u0026\u0026 (reg-\u003etype \u0026 PTR_MAYBE_NULL)) {\n \t\t\t\tbpf_log(log, \"%s is expected to be non-NULL\\n\",\n@@ -10297,9 +10373,10 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn\n \t\tenv-\u003einsn_aux_data[insn_idx].non_sleepable = true;\n \n \tmeta.func_id = func_id;\n+\tmeta.fn = fn;\n \t/* check args */\n \tfor (i = 0; i \u003c MAX_BPF_FUNC_REG_ARGS; i++) {\n-\t\terr = check_func_arg(env, i, \u0026meta, fn, insn_idx);\n+\t\terr = check_func_arg(env, i, \u0026meta, insn_idx);\n \t\tif (err)\n \t\t\treturn err;\n \t}\n@@ -10771,26 +10848,24 @@ static bool is_kfunc_rcu_protected(struct bpf_call_arg_meta *meta)\n }\n \n static bool is_kfunc_arg_mem_size(const struct btf *btf,\n-\t\t\t\t  const struct btf_param *arg,\n-\t\t\t\t  const struct bpf_reg_state *reg)\n+\t\t\t\t  const struct btf_param *arg)\n {\n \tconst struct btf_type *t;\n \n \tt = btf_type_skip_modifiers(btf, arg-\u003etype, NULL);\n-\tif (!btf_type_is_scalar(t) || reg-\u003etype != SCALAR_VALUE)\n+\tif (!btf_type_is_scalar(t))\n \t\treturn false;\n \n \treturn btf_param_match_suffix(btf, arg, \"__sz\");\n }\n \n static bool is_kfunc_arg_const_mem_size(const struct btf *btf,\n-\t\t\t\t\tconst struct btf_param *arg,\n-\t\t\t\t\tconst struct bpf_reg_state *reg)\n+\t\t\t\t\tconst struct btf_param *arg)\n {\n \tconst struct btf_type *t;\n \n \tt = btf_type_skip_modifiers(btf, arg-\u003etype, NULL);\n-\tif (!btf_type_is_scalar(t) || reg-\u003etype != SCALAR_VALUE)\n+\tif (!btf_type_is_scalar(t))\n \t\treturn false;\n \n \treturn btf_param_match_suffix(btf, arg, \"__szk\");\n@@ -10811,6 +10886,11 @@ static bool is_kfunc_arg_map(const struct btf *btf, const struct btf_param *arg)\n \treturn btf_param_match_suffix(btf, arg, \"__map\");\n }\n \n+static bool is_kfunc_arg_const_map(const struct btf *btf, const struct btf_param *arg)\n+{\n+\treturn btf_param_match_suffix(btf, arg, \"__const_map\");\n+}\n+\n static bool is_kfunc_arg_alloc_obj(const struct btf *btf, const struct btf_param *arg)\n {\n \treturn btf_param_match_suffix(btf, arg, \"__alloc\");\n@@ -11051,18 +11131,21 @@ enum kfunc_ptr_arg_type {\n \tKF_ARG_PTR_TO_LIST_NODE,\n \tKF_ARG_PTR_TO_BTF_ID,\t       /* Also covers reg2btf_ids conversions */\n \tKF_ARG_PTR_TO_MEM,\n-\tKF_ARG_PTR_TO_MEM_SIZE,\t       /* Size derived from next argument, skip it */\n \tKF_ARG_PTR_TO_CALLBACK,\n \tKF_ARG_PTR_TO_RB_ROOT,\n \tKF_ARG_PTR_TO_RB_NODE,\n-\tKF_ARG_PTR_TO_NULL,\n \tKF_ARG_PTR_TO_CONST_STR,\n-\tKF_ARG_PTR_TO_MAP,\n+\tKF_ARG_CONST_MAP_PTR,\n \tKF_ARG_PTR_TO_TIMER,\n \tKF_ARG_PTR_TO_WORKQUEUE,\n \tKF_ARG_PTR_TO_IRQ_FLAG,\n \tKF_ARG_PTR_TO_RES_SPIN_LOCK,\n \tKF_ARG_PTR_TO_TASK_WORK,\n+\tKF_ARG_CONST_BTF_ID,\t       /* const scalar carrying a BTF type id */\n+\tKF_ARG_CONST_MEM_SIZE,\t       /* const scalar sizing a preceding memory arg */\n+\tKF_ARG_CONST_ALLOC_SIZE_OR_ZERO, /* const scalar sizing a returned buffer */\n+\tKF_ARG_MEM_SIZE,\t       /* scalar sizing a preceding memory arg */\n+\tKF_ARG_ANYTHING,\t       /* unconstrained scalar */\n };\n \n enum special_kfunc_type {\n@@ -11318,108 +11401,156 @@ bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta)\n \treturn meta-\u003efunc_id == special_kfunc_list[KF_bpf_xdp_pull_data];\n }\n \n-static enum kfunc_ptr_arg_type\n-get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, struct bpf_func_state *caller,\n-\t\t       struct bpf_reg_state *regs, struct bpf_call_arg_meta *meta,\n-\t\t       const struct btf_type *t, const struct btf_type *ref_t,\n-\t\t       const char *ref_tname, const struct btf_param *args,\n-\t\t       int arg, int nargs, argno_t argno, struct bpf_reg_state *reg)\n+static int\n+get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,\n+\t\t   const struct btf_param *args, int arg, int nargs, argno_t argno)\n {\n+\tconst struct btf_type *t, *ref_t = NULL;\n+\tconst char *ref_tname = NULL;\n \tbool arg_mem_size = false;\n+\tint arg_type;\n \n-\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||\n-\t    meta-\u003efunc_id == special_kfunc_list[KF_bpf_session_is_return] ||\n-\t    meta-\u003efunc_id == special_kfunc_list[KF_bpf_session_cookie])\n-\t\treturn KF_ARG_PTR_TO_CTX;\n+\tt = btf_type_skip_modifiers(meta-\u003ebtf, args[arg].type, NULL);\n \n-\tif (arg + 1 \u003c nargs \u0026\u0026\n-\t    (is_kfunc_arg_mem_size(meta-\u003ebtf, \u0026args[arg + 1], get_func_arg_reg(caller, regs, arg + 1)) ||\n-\t     is_kfunc_arg_const_mem_size(meta-\u003ebtf, \u0026args[arg + 1], get_func_arg_reg(caller, regs, arg + 1))))\n-\t\targ_mem_size = true;\n+\t/* Scalar arguments are classified from their BTF suffix/name alone. */\n+\tif (btf_type_is_scalar(t)) {\n+\t\tif (is_kfunc_arg_constant(meta-\u003ebtf, \u0026args[arg]))\n+\t\t\treturn KF_ARG_CONST_BTF_ID;\n+\t\tif (is_kfunc_arg_const_mem_size(meta-\u003ebtf, \u0026args[arg]))\n+\t\t\treturn KF_ARG_CONST_MEM_SIZE;\n+\t\tif (is_kfunc_arg_mem_size(meta-\u003ebtf, \u0026args[arg]))\n+\t\t\treturn KF_ARG_MEM_SIZE;\n+\t\tif (is_kfunc_arg_scalar_with_name(meta-\u003ebtf, \u0026args[arg], \"rdonly_buf_size\") ||\n+\t\t    is_kfunc_arg_scalar_with_name(meta-\u003ebtf, \u0026args[arg], \"rdwr_buf_size\"))\n+\t\t\treturn KF_ARG_CONST_ALLOC_SIZE_OR_ZERO;\n+\t\treturn KF_ARG_ANYTHING;\n+\t}\n+\n+\tif (!btf_type_is_ptr(t)) {\n+\t\tverbose(env, \"Unrecognized %s type %s\\n\",\n+\t\t\treg_arg_name(env, argno), btf_type_str(t));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tref_t = btf_type_skip_modifiers(meta-\u003ebtf, t-\u003etype, NULL);\n+\tref_tname = btf_name_by_offset(meta-\u003ebtf, ref_t-\u003ename_off);\n \n \t/* In this function, we verify the kfunc's BTF as per the argument type,\n \t * leaving the rest of the verification with respect to the register\n \t * type to our caller. When a set of conditions hold in the BTF type of\n \t * arguments, we resolve it to a known kfunc_ptr_arg_type.\n \t */\n-\tif (btf_is_prog_ctx_type(\u0026env-\u003elog, meta-\u003ebtf, t, resolve_prog_type(env-\u003eprog), arg))\n-\t\treturn KF_ARG_PTR_TO_CTX;\n-\n-\tif (is_kfunc_arg_nullable(meta-\u003ebtf, \u0026args[arg]) \u0026\u0026 bpf_register_is_null(reg) \u0026\u0026\n-\t    !arg_mem_size)\n-\t\treturn KF_ARG_PTR_TO_NULL;\n-\n-\tif (is_kfunc_arg_alloc_obj(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_ALLOC_BTF_ID;\n-\n-\tif (is_kfunc_arg_refcounted_kptr(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_REFCOUNTED_KPTR;\n-\n-\tif (is_kfunc_arg_dynptr(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_DYNPTR;\n-\n-\tif (is_kfunc_arg_iter(meta, arg, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_ITER;\n-\n-\tif (is_kfunc_arg_list_head(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_LIST_HEAD;\n-\n-\tif (is_kfunc_arg_list_node(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_LIST_NODE;\n-\n-\tif (is_kfunc_arg_rbtree_root(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_RB_ROOT;\n-\n-\tif (is_kfunc_arg_rbtree_node(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_RB_NODE;\n+\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||\n+\t    meta-\u003efunc_id == special_kfunc_list[KF_bpf_session_is_return] ||\n+\t    meta-\u003efunc_id == special_kfunc_list[KF_bpf_session_cookie])\n+\t\targ_type = KF_ARG_PTR_TO_CTX;\n+\telse if (btf_is_prog_ctx_type(\u0026env-\u003elog, meta-\u003ebtf, t, resolve_prog_type(env-\u003eprog), arg))\n+\t\targ_type = KF_ARG_PTR_TO_CTX;\n+\telse if (is_kfunc_arg_alloc_obj(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_ALLOC_BTF_ID;\n+\telse if (is_kfunc_arg_refcounted_kptr(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_REFCOUNTED_KPTR;\n+\telse if (is_kfunc_arg_dynptr(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_DYNPTR;\n+\telse if (is_kfunc_arg_iter(meta, arg, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_ITER;\n+\telse if (is_kfunc_arg_list_head(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_LIST_HEAD;\n+\telse if (is_kfunc_arg_list_node(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_LIST_NODE;\n+\telse if (is_kfunc_arg_rbtree_root(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_RB_ROOT;\n+\telse if (is_kfunc_arg_rbtree_node(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_RB_NODE;\n+\telse if (is_kfunc_arg_const_str(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_CONST_STR;\n+\telse if (is_kfunc_arg_const_map(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_CONST_MAP_PTR;\n+\telse if (is_kfunc_arg_map(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_BTF_ID;\n+\telse if (is_kfunc_arg_wq(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_WORKQUEUE;\n+\telse if (is_kfunc_arg_timer(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_TIMER;\n+\telse if (is_kfunc_arg_task_work(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_TASK_WORK;\n+\telse if (is_kfunc_arg_irq_flag(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_IRQ_FLAG;\n+\telse if (is_kfunc_arg_res_spin_lock(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_RES_SPIN_LOCK;\n+\telse if (is_kfunc_arg_callback(env, meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type = KF_ARG_PTR_TO_CALLBACK;\n+\telse {\n+\t\tif (arg + 1 \u003c nargs \u0026\u0026\n+\t\t    (is_kfunc_arg_mem_size(meta-\u003ebtf, \u0026args[arg + 1]) ||\n+\t\t     is_kfunc_arg_const_mem_size(meta-\u003ebtf, \u0026args[arg + 1])))\n+\t\t\targ_mem_size = true;\n+\n+\t\tif (btf_type_is_struct(ref_t) \u0026\u0026 !arg_mem_size) {\n+\t\t\t/* A pointer to a struct without a size argument is classified\n+\t\t\t * as KF_ARG_PTR_TO_BTF_ID.\n+\t\t\t */\n+\t\t\targ_type = KF_ARG_PTR_TO_BTF_ID;\n+\t\t} else if (!btf_type_is_scalar(ref_t) \u0026\u0026\n+\t\t\t   !__btf_type_is_scalar_struct(env, meta-\u003ebtf, ref_t, 0) \u0026\u0026\n+\t\t\t   (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {\n+\t\t\tverbose(env, \"%s pointer type %s %s must point to %sscalar, or struct with scalar\\n\",\n+\t\t\t\treg_arg_name(env, argno),\n+\t\t\t\tbtf_type_str(ref_t), ref_tname, arg_mem_size ? \"void, \" : \"\");\n+\t\t\treturn -EINVAL;\n+\t\t} else {\n+\t\t\t/* Otherwise this is a memory buffer supported by\n+\t\t\t * check_helper_mem_access(): a pointer to a scalar, or to void\n+\t\t\t * when paired with a size argument. The access size is derived\n+\t\t\t * from the pointed-to BTF type unless a size argument follows.\n+\t\t\t */\n+\t\t\targ_type = arg_mem_size ? KF_ARG_PTR_TO_MEM : KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;\n+\t\t}\n+\t}\n \n-\tif (is_kfunc_arg_const_str(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_CONST_STR;\n+\tif (is_kfunc_arg_nullable(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type |= PTR_MAYBE_NULL;\n \n-\tif (is_kfunc_arg_map(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_MAP;\n+\treturn arg_type;\n+}\n \n-\tif (is_kfunc_arg_wq(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_WORKQUEUE;\n+static int gen_kfunc_arg_proto(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,\n+\t\t\t       struct bpf_func_proto *proto)\n+{\n+\tconst struct btf *btf = meta-\u003ebtf;\n+\tconst struct btf_param *args;\n+\tu32 i, nargs;\n+\tint arg_type;\n \n-\tif (is_kfunc_arg_timer(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_TIMER;\n+\targs = (const struct btf_param *)(meta-\u003efunc_proto + 1);\n+\tnargs = btf_type_vlen(meta-\u003efunc_proto);\n+\tif (nargs \u003e MAX_BPF_FUNC_ARGS) {\n+\t\tverbose(env, \"Function %s has %d \u003e %d args\\n\", meta-\u003efunc_name,\n+\t\t\tnargs, MAX_BPF_FUNC_ARGS);\n+\t\treturn -EINVAL;\n+\t}\n+\tif (nargs \u003e MAX_BPF_FUNC_REG_ARGS \u0026\u0026 !bpf_jit_supports_stack_args()) {\n+\t\tverbose(env, \"JIT does not support kfunc %s() with %d args\\n\",\n+\t\t\tmeta-\u003efunc_name, nargs);\n+\t\treturn -ENOTSUPP;\n+\t}\n \n-\tif (is_kfunc_arg_task_work(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_TASK_WORK;\n+\tfor (i = 0; i \u003c nargs; i++) {\n+\t\targno_t argno = argno_from_arg(i + 1);\n \n-\tif (is_kfunc_arg_irq_flag(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_IRQ_FLAG;\n+\t\tif (is_kfunc_arg_prog_aux(btf, \u0026args[i]) ||\n+\t\t    is_kfunc_arg_ignore(btf, \u0026args[i]) ||\n+\t\t    is_kfunc_arg_implicit(meta, i))\n+\t\t\tcontinue;\n \n-\tif (is_kfunc_arg_res_spin_lock(meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_RES_SPIN_LOCK;\n+\t\targ_type = get_kfunc_arg_type(env, meta, args, i, nargs, argno);\n+\t\tif (arg_type \u003c 0)\n+\t\t\treturn arg_type;\n \n-\tif ((base_type(reg-\u003etype) == PTR_TO_BTF_ID || reg2btf_ids[base_type(reg-\u003etype)])) {\n-\t\tif (!btf_type_is_struct(ref_t)) {\n-\t\t\tverbose(env, \"kernel function %s %s pointer type %s %s is not supported\\n\",\n-\t\t\t\tmeta-\u003efunc_name, reg_arg_name(env, argno),\n-\t\t\t\tbtf_type_str(ref_t), ref_tname);\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\t\treturn KF_ARG_PTR_TO_BTF_ID;\n+\t\tproto-\u003earg_type[i] = arg_type;\n \t}\n \n-\tif (is_kfunc_arg_callback(env, meta-\u003ebtf, \u0026args[arg]))\n-\t\treturn KF_ARG_PTR_TO_CALLBACK;\n-\n-\t/* This is the catch all argument type of register types supported by\n-\t * check_helper_mem_access. However, we only allow when argument type is\n-\t * pointer to scalar, or struct composed (recursively) of scalars. When\n-\t * arg_mem_size is true, the pointer can be void *.\n-\t */\n-\tif (!btf_type_is_scalar(ref_t) \u0026\u0026 !__btf_type_is_scalar_struct(env, meta-\u003ebtf, ref_t, 0) \u0026\u0026\n-\t    (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {\n-\t\tverbose(env, \"%s pointer type %s %s must point to %sscalar, or struct with scalar\\n\",\n-\t\t\treg_arg_name(env, argno),\n-\t\t\tbtf_type_str(ref_t), ref_tname, arg_mem_size ? \"void, \" : \"\");\n-\t\treturn -EINVAL;\n-\t}\n-\treturn arg_mem_size ? KF_ARG_PTR_TO_MEM_SIZE : KF_ARG_PTR_TO_MEM;\n+\treturn 0;\n }\n \n static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,\n@@ -12005,16 +12136,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me\n \n \targs = (const struct btf_param *)(meta-\u003efunc_proto + 1);\n \tnargs = btf_type_vlen(meta-\u003efunc_proto);\n-\tif (nargs \u003e MAX_BPF_FUNC_ARGS) {\n-\t\tverbose(env, \"Function %s has %d \u003e %d args\\n\", func_name, nargs,\n-\t\t\tMAX_BPF_FUNC_ARGS);\n-\t\treturn -EINVAL;\n-\t}\n-\tif (nargs \u003e MAX_BPF_FUNC_REG_ARGS \u0026\u0026 !bpf_jit_supports_stack_args()) {\n-\t\tverbose(env, \"JIT does not support kfunc %s() with %d args\\n\",\n-\t\t\tfunc_name, nargs);\n-\t\treturn -ENOTSUPP;\n-\t}\n \n \tret = check_outgoing_stack_args(env, caller, nargs);\n \tif (ret)\n@@ -12031,8 +12152,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me\n \t\tint regno = reg_from_argno(argno);\n \t\tbool btf_id_fixed_off_ok = true;\n \t\tu32 ref_id, type_size;\n-\t\tbool is_ret_buf_sz = false;\n-\t\tint kf_arg_type;\n+\t\tint kf_arg_type = meta-\u003efn-\u003earg_type[i];\n \n \t\tif (is_kfunc_arg_prog_aux(btf, \u0026args[i])) {\n \t\t\t/* Reject repeated use bpf_prog_aux */\n@@ -12055,52 +12175,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me\n \n \t\tt = btf_type_skip_modifiers(btf, args[i].type, NULL);\n \n-\t\tif (btf_type_is_scalar(t)) {\n-\t\t\tif (reg-\u003etype != SCALAR_VALUE) {\n-\t\t\t\tverbose(env, \"%s is not a scalar\\n\", reg_arg_name(env, argno));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\n-\t\t\tif (is_kfunc_arg_constant(meta-\u003ebtf, \u0026args[i])) {\n-\t\t\t\tif (meta-\u003earg_constant.found) {\n-\t\t\t\t\tverifier_bug(env, \"only one constant argument permitted\");\n-\t\t\t\t\treturn -EFAULT;\n-\t\t\t\t}\n-\t\t\t\tif (!tnum_is_const(reg-\u003evar_off)) {\n-\t\t\t\t\tverbose(env, \"%s must be a known constant\\n\",\n-\t\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t}\n-\t\t\t\tif (regno \u003e= 0)\n-\t\t\t\t\tret = mark_chain_precision(env, regno);\n-\t\t\t\telse\n-\t\t\t\t\tret = mark_stack_arg_precision(env, i);\n-\t\t\t\tif (ret \u003c 0)\n-\t\t\t\t\treturn ret;\n-\t\t\t\tmeta-\u003earg_constant.found = true;\n-\t\t\t\tmeta-\u003earg_constant.value = reg-\u003evar_off.value;\n-\t\t\t} else if (is_kfunc_arg_scalar_with_name(btf, \u0026args[i], \"rdonly_buf_size\")) {\n-\t\t\t\tmeta-\u003er0_rdonly = true;\n-\t\t\t\tis_ret_buf_sz = true;\n-\t\t\t} else if (is_kfunc_arg_scalar_with_name(btf, \u0026args[i], \"rdwr_buf_size\")) {\n-\t\t\t\tis_ret_buf_sz = true;\n-\t\t\t}\n-\n-\t\t\tif (is_ret_buf_sz) {\n-\t\t\t\tret = process_const_alloc_mem_size(env, reg, argno, \u0026meta-\u003eret_mem);\n-\t\t\t\tif (ret \u003c 0)\n-\t\t\t\t\treturn ret;\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (!btf_type_is_ptr(t)) {\n-\t\t\tverbose(env, \"Unrecognized %s type %s\\n\",\n-\t\t\t\treg_arg_name(env, argno), btf_type_str(t));\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\n-\t\tif ((bpf_register_is_null(reg) || type_may_be_null(reg-\u003etype)) \u0026\u0026\n+\t\tif (btf_type_is_ptr(t) \u0026\u0026 (bpf_register_is_null(reg) || type_may_be_null(reg-\u003etype)) \u0026\u0026\n \t\t    !is_kfunc_arg_nullable(meta-\u003ebtf, \u0026args[i])) {\n \t\t\tverbose(env, \"Possibly NULL pointer passed to trusted %s\\n\",\n \t\t\t\treg_arg_name(env, argno));\n@@ -12117,76 +12192,35 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me\n \t\tif (reg_is_referenced(env, reg))\n \t\t\tupdate_ref_obj(\u0026meta-\u003eref_obj, reg);\n \n-\t\tref_t = btf_type_skip_modifiers(btf, t-\u003etype, \u0026ref_id);\n-\t\tref_tname = btf_name_by_offset(btf, ref_t-\u003ename_off);\n-\n-\t\tkf_arg_type = get_kfunc_ptr_arg_type(env, caller, regs, meta, t, ref_t, ref_tname,\n-\t\t\t\t\t\t     args, i, nargs, argno, reg);\n-\t\tif (kf_arg_type \u003c 0)\n-\t\t\treturn kf_arg_type;\n+\t\tif (btf_type_is_ptr(t)) {\n+\t\t\tref_t = btf_type_skip_modifiers(btf, t-\u003etype, \u0026ref_id);\n+\t\t\tref_tname = btf_name_by_offset(btf, ref_t-\u003ename_off);\n+\t\t}\n \n-\t\tswitch (kf_arg_type) {\n-\t\tcase KF_ARG_PTR_TO_NULL:\n+\t\tif (bpf_register_is_null(reg) \u0026\u0026 type_may_be_null(kf_arg_type))\n \t\t\tcontinue;\n-\t\tcase KF_ARG_PTR_TO_MAP:\n-\t\t\tif (!reg-\u003emap_ptr) {\n-\t\t\t\tverbose(env, \"pointer in %s isn't map pointer\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tif (meta-\u003emap.ptr \u0026\u0026 (reg-\u003emap_ptr-\u003erecord-\u003ewq_off \u003e= 0 ||\n-\t\t\t\t\t      reg-\u003emap_ptr-\u003erecord-\u003etask_work_off \u003e= 0)) {\n-\t\t\t\t/* Use map_uid (which is unique id of inner map) to reject:\n-\t\t\t\t * inner_map1 = bpf_map_lookup_elem(outer_map, key1)\n-\t\t\t\t * inner_map2 = bpf_map_lookup_elem(outer_map, key2)\n-\t\t\t\t * if (inner_map1 \u0026\u0026 inner_map2) {\n-\t\t\t\t *     wq = bpf_map_lookup_elem(inner_map1);\n-\t\t\t\t *     if (wq)\n-\t\t\t\t *         // mismatch would have been allowed\n-\t\t\t\t *         bpf_wq_init(wq, inner_map2);\n-\t\t\t\t * }\n-\t\t\t\t *\n-\t\t\t\t * Comparing map_ptr is enough to distinguish normal and outer maps.\n-\t\t\t\t */\n-\t\t\t\tif (meta-\u003emap.ptr != reg-\u003emap_ptr ||\n-\t\t\t\t    meta-\u003emap.uid != reg-\u003emap_uid) {\n-\t\t\t\t\tif (reg-\u003emap_ptr-\u003erecord-\u003etask_work_off \u003e= 0) {\n-\t\t\t\t\t\tverbose(env,\n-\t\t\t\t\t\t\t\"bpf_task_work pointer in R2 map_uid=%d doesn't match map pointer in R3 map_uid=%d\\n\",\n-\t\t\t\t\t\t\tmeta-\u003emap.uid, reg-\u003emap_uid);\n-\t\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t\t}\n-\t\t\t\t\tverbose(env,\n-\t\t\t\t\t\t\"workqueue pointer in R1 map_uid=%d doesn't match map pointer in R2 map_uid=%d\\n\",\n-\t\t\t\t\t\tmeta-\u003emap.uid, reg-\u003emap_uid);\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tmeta-\u003emap.ptr = reg-\u003emap_ptr;\n-\t\t\tmeta-\u003emap.uid = reg-\u003emap_uid;\n-\t\t\tfallthrough;\n+\n+\t\tif (is_kfunc_arg_map(btf, \u0026args[i])) {\n+\t\t\tref_id = *reg2btf_ids[CONST_PTR_TO_MAP];\n+\t\t\tref_t = btf_type_by_id(btf_vmlinux, ref_id);\n+\t\t\tref_tname = btf_name_by_offset(btf, ref_t-\u003ename_off);\n+\t\t}\n+\n+\t\tswitch (base_type(kf_arg_type)) {\n+\t\tcase KF_ARG_CONST_BTF_ID:\n+\t\tcase KF_ARG_CONST_ALLOC_SIZE_OR_ZERO:\n+\t\tcase KF_ARG_ANYTHING:\n \t\tcase KF_ARG_PTR_TO_ALLOC_BTF_ID:\n \t\tcase KF_ARG_PTR_TO_BTF_ID:\n-\t\t\tif (!is_trusted_reg(env, reg)) {\n-\t\t\t\tif (!is_kfunc_rcu(meta)) {\n-\t\t\t\t\tverbose(env, \"%s must be referenced or trusted\\n\",\n-\t\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t}\n-\t\t\t\tif (!is_rcu_reg(reg)) {\n-\t\t\t\t\tverbose(env, \"%s must be a rcu pointer\\n\",\n-\t\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tfallthrough;\n+\t\tcase KF_ARG_CONST_MAP_PTR:\n \t\tcase KF_ARG_PTR_TO_ITER:\n \t\tcase KF_ARG_PTR_TO_LIST_HEAD:\n \t\tcase KF_ARG_PTR_TO_LIST_NODE:\n \t\tcase KF_ARG_PTR_TO_RB_ROOT:\n \t\tcase KF_ARG_PTR_TO_RB_NODE:\n \t\tcase KF_ARG_PTR_TO_MEM:\n-\t\tcase KF_ARG_PTR_TO_MEM_SIZE:\n+\t\tcase KF_ARG_CONST_MEM_SIZE:\n+\t\tcase KF_ARG_MEM_SIZE:\n \t\tcase KF_ARG_PTR_TO_CALLBACK:\n \t\tcase KF_ARG_PTR_TO_CONST_STR:\n \t\tcase KF_ARG_PTR_TO_WORKQUEUE:\n@@ -12217,7 +12251,35 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me\n \t\tif (ret \u003c 0)\n \t\t\treturn ret;\n \n-\t\tswitch (kf_arg_type) {\n+\t\tswitch (base_type(kf_arg_type)) {\n+\t\tcase KF_ARG_CONST_BTF_ID:\n+\t\t\tif (reg-\u003etype != SCALAR_VALUE) {\n+\t\t\t\tverbose(env, \"%s is not a scalar\\n\", reg_arg_name(env, argno));\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\n+\t\t\tret = process_const_arg(env, reg, argno, meta);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\treturn ret;\n+\t\t\tbreak;\n+\t\tcase KF_ARG_CONST_ALLOC_SIZE_OR_ZERO:\n+\t\t\tif (reg-\u003etype != SCALAR_VALUE) {\n+\t\t\t\tverbose(env, \"%s is not a scalar\\n\", reg_arg_name(env, argno));\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\n+\t\t\tif (is_kfunc_arg_scalar_with_name(btf, \u0026args[i], \"rdonly_buf_size\"))\n+\t\t\t\tmeta-\u003er0_rdonly = true;\n+\t\t\tret = process_const_alloc_mem_size(env, reg, argno, \u0026meta-\u003eret_mem);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\treturn ret;\n+\t\t\tbreak;\n+\t\tcase KF_ARG_ANYTHING:\n+\t\t\tif (reg-\u003etype != SCALAR_VALUE) {\n+\t\t\t\tverbose(env, \"%s is not a scalar\\n\", reg_arg_name(env, argno));\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\tbreak;\n \t\tcase KF_ARG_PTR_TO_CTX:\n \t\t\tif (reg-\u003etype != PTR_TO_CTX) {\n \t\t\t\tverbose(env, \"%s expected pointer to ctx, but got %s\\n\",\n@@ -12386,51 +12448,77 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me\n \t\t\tif (ret \u003c 0)\n \t\t\t\treturn ret;\n \t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_MAP:\n-\t\t\t/* If argument has '__map' suffix expect 'struct bpf_map *' */\n-\t\t\tref_id = *reg2btf_ids[CONST_PTR_TO_MAP];\n-\t\t\tref_t = btf_type_by_id(btf_vmlinux, ref_id);\n-\t\t\tref_tname = btf_name_by_offset(btf, ref_t-\u003ename_off);\n-\t\t\tfallthrough;\n-\t\tcase KF_ARG_PTR_TO_BTF_ID:\n-\t\t\t/* Only base_type is checked, further checks are done here */\n-\t\t\tif ((base_type(reg-\u003etype) != PTR_TO_BTF_ID ||\n-\t\t\t     (bpf_type_has_unsafe_modifiers(reg-\u003etype) \u0026\u0026 !is_rcu_reg(reg))) \u0026\u0026\n-\t\t\t    !reg2btf_ids[base_type(reg-\u003etype)]) {\n-\t\t\t\tverbose(env, \"%s is %s \", reg_arg_name(env, argno),\n-\t\t\t\t\treg_type_str(env, reg-\u003etype));\n-\t\t\t\tverbose(env, \"expected %s or socket\\n\",\n-\t\t\t\t\treg_type_str(env, base_type(reg-\u003etype) |\n-\t\t\t\t\t\t\t  (type_flag(reg-\u003etype) \u0026 BPF_REG_TRUSTED_MODIFIERS)));\n+\t\tcase KF_ARG_CONST_MAP_PTR:\n+\t\t\tif (!reg-\u003emap_ptr) {\n+\t\t\t\tverbose(env, \"pointer in %s isn't map pointer\\n\",\n+\t\t\t\t\treg_arg_name(env, argno));\n \t\t\t\treturn -EINVAL;\n \t\t\t}\n-\t\t\tret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i, argno);\n+\t\t\tret = process_map_ptr_arg(env, reg, argno, meta);\n \t\t\tif (ret \u003c 0)\n \t\t\t\treturn ret;\n \t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_MEM:\n-\t\t\tresolve_ret = btf_resolve_size(btf, ref_t, \u0026type_size);\n-\t\t\tif (IS_ERR(resolve_ret)) {\n-\t\t\t\tverbose(env, \"%s reference type('%s %s') size cannot be determined: %ld\\n\",\n-\t\t\t\t\treg_arg_name(env, argno), btf_type_str(ref_t),\n-\t\t\t\t\tref_tname, PTR_ERR(resolve_ret));\n+\t\tcase KF_ARG_PTR_TO_BTF_ID:\n+\t\t\t/* Only base_type is checked, further checks are done here */\n+\t\t\tif (base_type(reg-\u003etype) == PTR_TO_BTF_ID ||\n+\t\t\t    reg2btf_ids[base_type(reg-\u003etype)]) {\n+\n+\t\t\t\tif (!is_trusted_reg(env, reg)) {\n+\t\t\t\t\tif (!is_kfunc_rcu(meta)) {\n+\t\t\t\t\t\tverbose(env, \"%s must be referenced or trusted\\n\",\n+\t\t\t\t\t\t\treg_arg_name(env, argno));\n+\t\t\t\t\t\treturn -EINVAL;\n+\t\t\t\t\t}\n+\t\t\t\t\tif (!is_rcu_reg(reg)) {\n+\t\t\t\t\t\tverbose(env, \"%s must be a rcu pointer\\n\",\n+\t\t\t\t\t\t\treg_arg_name(env, argno));\n+\t\t\t\t\t\treturn -EINVAL;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\n+\t\t\t\tret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i, argno);\n+\t\t\t\tif (ret \u003c 0)\n+\t\t\t\t\treturn ret;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tif (!__btf_type_is_scalar_struct(env, meta-\u003ebtf, ref_t, 0)) {\n+\t\t\t\tenum bpf_reg_type reg2btf_type = lookup_reg2btf_ids(ref_t);\n+\n+\t\t\t\tverbose(env, \"%s is %s expected %s %s\",\n+\t\t\t\t\treg_arg_name(env, argno), reg_type_str(env, reg-\u003etype),\n+\t\t\t\t\tbtf_type_str(ref_t), ref_tname);\n+\t\t\t\tif (reg2btf_type != NOT_INIT)\n+\t\t\t\t\tverbose(env, \" or %s\", reg_type_str(env, reg2btf_type));\n+\t\t\t\tverbose(env, \"\\n\");\n \t\t\t\treturn -EINVAL;\n \t\t\t}\n-\t\t\tret = check_mem_reg(env, reg, argno, type_size);\n-\t\t\tif (ret \u003c 0)\n-\t\t\t\treturn ret;\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_MEM_SIZE:\n-\t\t{\n-\t\t\tstruct bpf_reg_state *buff_reg = reg;\n-\t\t\tconst struct btf_param *buff_arg = \u0026args[i];\n-\t\t\tstruct bpf_reg_state *size_reg = get_func_arg_reg(caller, regs, i + 1);\n-\t\t\tconst struct btf_param *size_arg = \u0026args[i + 1];\n-\t\t\targno_t next_argno = argno_from_arg(i + 2);\n-\n-\t\t\tif (!bpf_register_is_null(buff_reg) || !is_kfunc_arg_nullable(meta-\u003ebtf, buff_arg)) {\n-\t\t\t\tret = check_kfunc_mem_size_reg(env, buff_reg, size_reg,\n-\t\t\t\t\t\t\t       argno, next_argno);\n+\n+\t\t\t/*\n+\t\t\t * If the register does not contain btf id but the argument type is a pointer to\n+\t\t\t * scalar-only struct, allow verifying it as a fixed size memory.\n+\t\t\t */\n+\t\t\tkf_arg_type = KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;\n+\t\t\tfallthrough;\n+\t\tcase KF_ARG_PTR_TO_MEM:\n+\t\t\tif (kf_arg_type \u0026 MEM_FIXED_SIZE) {\n+\t\t\t\tresolve_ret = btf_resolve_size(btf, ref_t, \u0026type_size);\n+\t\t\t\tif (IS_ERR(resolve_ret)) {\n+\t\t\t\t\tverbose(env, \"%s reference type('%s %s') size cannot be determined: %ld\\n\",\n+\t\t\t\t\t\treg_arg_name(env, argno), btf_type_str(ref_t),\n+\t\t\t\t\t\tref_tname, PTR_ERR(resolve_ret));\n+\t\t\t\t\treturn -EINVAL;\n+\t\t\t\t}\n+\t\t\t\tret = check_mem_reg(env, reg, argno, type_size, BPF_READ | BPF_WRITE, meta);\n+\t\t\t\tif (ret \u003c 0)\n+\t\t\t\t\treturn ret;\n+\t\t\t} else {\n+\t\t\t\tstruct bpf_reg_state *buff_reg = reg;\n+\t\t\t\tstruct bpf_reg_state *size_reg = get_func_arg_reg(caller, regs, i + 1);\n+\t\t\t\targno_t next_argno = argno_from_arg(i + 2);\n+\n+\t\t\t\tret = check_mem_size_reg(env, buff_reg, size_reg, argno, next_argno,\n+\t\t\t\t\t\t\t BPF_READ | BPF_WRITE, true, meta);\n \t\t\t\tif (ret \u003c 0) {\n \t\t\t\t\tverbose(env, \"%s and \", reg_arg_name(env, argno));\n \t\t\t\t\tverbose(env, \"%s memory, len pair leads to invalid memory access\\n\",\n@@ -12438,25 +12526,20 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me\n \t\t\t\t\treturn ret;\n \t\t\t\t}\n \t\t\t}\n-\n-\t\t\tif (is_kfunc_arg_const_mem_size(meta-\u003ebtf, size_arg, size_reg)) {\n-\t\t\t\tif (meta-\u003earg_constant.found) {\n-\t\t\t\t\tverifier_bug(env, \"only one constant argument permitted\");\n-\t\t\t\t\treturn -EFAULT;\n-\t\t\t\t}\n-\t\t\t\tif (!tnum_is_const(size_reg-\u003evar_off)) {\n-\t\t\t\t\tverbose(env, \"%s must be a known constant\\n\",\n-\t\t\t\t\t\treg_arg_name(env, next_argno));\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t}\n-\t\t\t\tmeta-\u003earg_constant.found = true;\n-\t\t\t\tmeta-\u003earg_constant.value = size_reg-\u003evar_off.value;\n+\t\t\tbreak;\n+\t\tcase KF_ARG_CONST_MEM_SIZE:\n+\t\t\tif (reg-\u003etype != SCALAR_VALUE) {\n+\t\t\t\tverbose(env, \"%s is not a scalar\\n\", reg_arg_name(env, argno));\n+\t\t\t\treturn -EINVAL;\n \t\t\t}\n \n-\t\t\t/* Skip next '__sz' or '__szk' argument */\n-\t\t\ti++;\n+\t\t\tret = process_const_arg(env, reg, argno, meta);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\treturn ret;\n+\n+\t\t\tfallthrough;\n+\t\tcase KF_ARG_MEM_SIZE:\n \t\t\tbreak;\n-\t\t}\n \t\tcase KF_ARG_PTR_TO_CALLBACK:\n \t\t\tif (reg-\u003etype != PTR_TO_FUNC) {\n \t\t\t\tverbose(env, \"%s expected pointer to func\\n\", reg_arg_name(env, argno));\n@@ -12514,7 +12597,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me\n \t\t\t\t\treg_arg_name(env, argno));\n \t\t\t\treturn -EINVAL;\n \t\t\t}\n-\t\t\tret = process_timer_kfunc(env, reg, argno, meta);\n+\t\t\tret = process_timer_func(env, reg, argno, \u0026meta-\u003emap);\n \t\t\tif (ret \u003c 0)\n \t\t\t\treturn ret;\n \t\t\tbreak;\n@@ -12676,7 +12759,7 @@ s64 bpf_helper_stack_access_bytes(struct bpf_verifier_env *env, struct bpf_insn\n \t\t\tsize = fn-\u003earg_size[arg];\n \t\t\tgoto out;\n \t\t}\n-\t\tif (arg + 1 \u003c ARRAY_SIZE(fn-\u003earg_type) \u0026\u0026\n+\t\tif (arg + 1 \u003c MAX_BPF_FUNC_REG_ARGS \u0026\u0026\n \t\t    arg_type_is_mem_size(fn-\u003earg_type[arg + 1])) {\n \t\t\tint size_reg = BPF_REG_1 + arg + 1;\n \n@@ -12975,6 +13058,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\n \tint err, insn_idx = *insn_idx_p;\n \tconst struct btf_param *args;\n \tu32 i, nargs, ptr_type_id;\n+\tstruct bpf_kfunc_desc *desc;\n \tstruct btf *desc_btf;\n \tint id;\n \n@@ -12991,6 +13075,13 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\n \tfunc_name = meta.func_name;\n \tinsn_aux = \u0026env-\u003einsn_aux_data[insn_idx];\n \n+\tdesc = find_kfunc_desc(env-\u003eprog, insn-\u003eimm, insn-\u003eoff);\n+\tif (!desc) {\n+\t\tverifier_bug(env, \"kfunc descriptor not found for func_id %u\", insn-\u003eimm);\n+\t\treturn -EFAULT;\n+\t}\n+\tmeta.fn = desc-\u003eproto;\n+\n \tinsn_aux-\u003eis_iter_next = bpf_is_iter_next_kfunc(\u0026meta);\n \n \tif (!insn-\u003eoff \u0026\u0026\ndiff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c\nindex 76ab51deaa6b95..891897f8a1b357 100644\n--- a/kernel/trace/bpf_trace.c\n+++ b/kernel/trace/bpf_trace.c\n@@ -221,7 +221,7 @@ const struct bpf_func_proto bpf_probe_read_user_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n };\n \n@@ -258,7 +258,7 @@ const struct bpf_func_proto bpf_probe_read_user_str_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n };\n \n@@ -273,7 +273,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n };\n \n@@ -308,7 +308,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_str_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n };\n \n@@ -328,7 +328,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n };\n \n@@ -347,7 +347,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_str_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_ANYTHING,\n };\n #endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */\n@@ -383,7 +383,7 @@ static const struct bpf_func_proto bpf_probe_write_user_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_ANYTHING,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n };\n \n #define MAX_TRACE_PRINTK_VARARGS\t3\n@@ -418,7 +418,7 @@ static const struct bpf_func_proto bpf_trace_printk_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg2_type\t= ARG_CONST_SIZE,\n+\t.arg2_type\t= ARG_MEM_SIZE,\n };\n \n static void __set_printk_clr_event(struct work_struct *work)\n@@ -474,9 +474,9 @@ static const struct bpf_func_proto bpf_trace_vprintk_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg2_type\t= ARG_CONST_SIZE,\n+\t.arg2_type\t= ARG_MEM_SIZE,\n \t.arg3_type\t= ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg4_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n const struct bpf_func_proto *bpf_get_trace_vprintk_proto(void)\n@@ -518,9 +518,9 @@ static const struct bpf_func_proto bpf_seq_printf_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026btf_seq_file_ids[0],\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.arg4_type      = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,\n-\t.arg5_type      = ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type      = ARG_MEM_SIZE_OR_ZERO,\n };\n \n BPF_CALL_3(bpf_seq_write, struct seq_file *, m, const void *, data, u32, len)\n@@ -535,7 +535,7 @@ static const struct bpf_func_proto bpf_seq_write_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026btf_seq_file_ids[0],\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n BPF_CALL_4(bpf_seq_printf_btf, struct seq_file *, m, struct btf_ptr *, ptr,\n@@ -559,7 +559,7 @@ static const struct bpf_func_proto bpf_seq_printf_btf_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026btf_seq_file_ids[0],\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -633,7 +633,7 @@ static const struct bpf_func_proto bpf_perf_event_read_value_proto = {\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n };\n \n const struct bpf_func_proto *bpf_get_perf_event_read_value_proto(void)\n@@ -730,7 +730,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto = {\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n static DEFINE_PER_CPU(int, bpf_event_output_nest_level);\n@@ -996,7 +996,7 @@ static const struct bpf_func_proto bpf_d_path_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026bpf_d_path_btf_ids[0],\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_WRITE,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.allowed\t= bpf_d_path_allowed,\n };\n \n@@ -1053,9 +1053,9 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_WRITE,\n-\t.arg2_type\t= ARG_CONST_SIZE,\n+\t.arg2_type\t= ARG_MEM_SIZE,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n \n@@ -1218,7 +1218,7 @@ const struct bpf_func_proto bpf_get_branch_snapshot_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n BPF_CALL_3(get_func_arg, void *, ctx, u32, n, u64 *, value)\n@@ -1421,7 +1421,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_tp = {\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n BPF_CALL_3(bpf_get_stackid_tp, void *, tp_buff, struct bpf_map *, map,\n@@ -1462,7 +1462,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_tp = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -1524,12 +1524,12 @@ BPF_CALL_3(bpf_perf_prog_read_value, struct bpf_perf_event_data_kern *, ctx,\n }\n \n static const struct bpf_func_proto bpf_perf_prog_read_value_proto = {\n-         .func           = bpf_perf_prog_read_value,\n-         .gpl_only       = true,\n-         .ret_type       = RET_INTEGER,\n-         .arg1_type      = ARG_PTR_TO_CTX,\n-         .arg2_type      = ARG_PTR_TO_UNINIT_MEM,\n-         .arg3_type      = ARG_CONST_SIZE,\n+\t.func           = bpf_perf_prog_read_value,\n+\t.gpl_only       = true,\n+\t.ret_type       = RET_INTEGER,\n+\t.arg1_type      = ARG_PTR_TO_CTX,\n+\t.arg2_type      = ARG_PTR_TO_UNINIT_MEM,\n+\t.arg3_type      = ARG_MEM_SIZE,\n };\n \n BPF_CALL_4(bpf_read_branch_records, struct bpf_perf_event_data_kern *, ctx,\n@@ -1566,7 +1566,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = {\n \t.ret_type       = RET_INTEGER,\n \t.arg1_type      = ARG_PTR_TO_CTX,\n \t.arg2_type      = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE,\n-\t.arg3_type      = ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type      = ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type      = ARG_ANYTHING,\n };\n \n@@ -1646,7 +1646,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_raw_tp = {\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n extern const struct bpf_func_proto bpf_skb_output_proto;\n@@ -1701,7 +1701,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \ndiff --git a/net/core/filter.c b/net/core/filter.c\nindex 0b7afdd0ae4748..eb0b706af4b296 100644\n--- a/net/core/filter.c\n+++ b/net/core/filter.c\n@@ -1747,7 +1747,7 @@ static const struct bpf_func_proto bpf_skb_store_bytes_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n \n@@ -1784,7 +1784,7 @@ static const struct bpf_func_proto bpf_skb_load_bytes_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n };\n \n int __bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len)\n@@ -1823,7 +1823,7 @@ static const struct bpf_func_proto bpf_flow_dissector_load_bytes_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_skb_load_bytes_relative, const struct sk_buff *, skb,\n@@ -1867,7 +1867,7 @@ static const struct bpf_func_proto bpf_skb_load_bytes_relative_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n \n@@ -2063,9 +2063,9 @@ static const struct bpf_func_proto bpf_csum_diff_proto = {\n \t.pkt_access\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,\n-\t.arg2_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg3_type\t= ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg4_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n \n@@ -2621,7 +2621,7 @@ static const struct bpf_func_proto bpf_redirect_neigh_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_ANYTHING,\n \t.arg2_type      = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,\n-\t.arg3_type      = ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type      = ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -4194,7 +4194,7 @@ static const struct bpf_func_proto bpf_xdp_load_bytes_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n };\n \n int __bpf_xdp_load_bytes(struct xdp_buff *xdp, u32 offset, void *buf, u32 len)\n@@ -4226,7 +4226,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n };\n \n int __bpf_xdp_store_bytes(struct xdp_buff *xdp, u32 offset, void *buf, u32 len)\n@@ -4789,7 +4789,7 @@ static const struct bpf_func_proto bpf_skb_event_output_proto = {\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n BTF_ID_LIST_SINGLE(bpf_skb_output_btf_ids, struct, sk_buff)\n@@ -4803,7 +4803,7 @@ const struct bpf_func_proto bpf_skb_output_proto = {\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n static unsigned short bpf_tunnel_key_af(u64 flags)\n@@ -4886,7 +4886,7 @@ static const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -4921,7 +4921,7 @@ static const struct bpf_func_proto bpf_skb_get_tunnel_opt_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n };\n \n static struct metadata_dst __percpu *md_dst;\n@@ -5003,7 +5003,7 @@ static const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -5031,7 +5031,7 @@ static const struct bpf_func_proto bpf_skb_set_tunnel_opt_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n };\n \n static const struct bpf_func_proto *\n@@ -5203,7 +5203,7 @@ static const struct bpf_func_proto bpf_xdp_event_output_proto = {\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n BTF_ID_LIST_SINGLE(bpf_xdp_output_btf_ids, struct, xdp_buff)\n@@ -5217,7 +5217,7 @@ const struct bpf_func_proto bpf_xdp_output_proto = {\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n BPF_CALL_1(bpf_get_socket_cookie, struct sk_buff *, skb)\n@@ -5764,7 +5764,7 @@ const struct bpf_func_proto bpf_sk_setsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_sk_getsockopt, struct sock *, sk, int, level,\n@@ -5781,7 +5781,7 @@ const struct bpf_func_proto bpf_sk_getsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_sk_setsockopt_nodelay, struct sock *, sk, int, level,\n@@ -5805,7 +5805,7 @@ const struct bpf_func_proto bpf_sk_setsockopt_nodelay_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_unlocked_sk_setsockopt, struct sock *, sk, int, level,\n@@ -5822,7 +5822,7 @@ const struct bpf_func_proto bpf_unlocked_sk_setsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_unlocked_sk_getsockopt, struct sock *, sk, int, level,\n@@ -5839,7 +5839,7 @@ const struct bpf_func_proto bpf_unlocked_sk_getsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_sock_addr_setsockopt, struct bpf_sock_addr_kern *, ctx,\n@@ -5856,7 +5856,7 @@ static const struct bpf_func_proto bpf_sock_addr_setsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_sock_addr_getsockopt, struct bpf_sock_addr_kern *, ctx,\n@@ -5873,7 +5873,7 @@ static const struct bpf_func_proto bpf_sock_addr_getsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n static int sk_bpf_set_get_bypass_prot_mem(struct sock *sk,\n@@ -5918,7 +5918,7 @@ static const struct bpf_func_proto bpf_sock_create_setsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_sock_create_getsockopt, struct sock *, sk, int, level,\n@@ -5944,7 +5944,7 @@ static const struct bpf_func_proto bpf_sock_create_getsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_sock_ops_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,\n@@ -5970,7 +5970,7 @@ static const struct bpf_func_proto bpf_sock_ops_setsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n static int bpf_sock_ops_get_syn(struct bpf_sock_ops_kern *bpf_sock,\n@@ -6080,7 +6080,7 @@ static const struct bpf_func_proto bpf_sock_ops_getsockopt_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_ANYTHING,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_2(bpf_sock_ops_cb_flags_set, struct bpf_sock_ops_kern *, bpf_sock,\n@@ -6147,7 +6147,7 @@ static const struct bpf_func_proto bpf_bind_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n };\n \n #ifdef CONFIG_XFRM\n@@ -6200,7 +6200,7 @@ static const struct bpf_func_proto bpf_skb_get_xfrm_state_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n #endif\n@@ -6607,7 +6607,7 @@ static const struct bpf_func_proto bpf_xdp_fib_lookup_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type      = ARG_PTR_TO_CTX,\n \t.arg2_type      = ARG_PTR_TO_MEM | MEM_WRITE,\n-\t.arg3_type      = ARG_CONST_SIZE,\n+\t.arg3_type      = ARG_MEM_SIZE,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -6667,7 +6667,7 @@ static const struct bpf_func_proto bpf_skb_fib_lookup_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type      = ARG_PTR_TO_CTX,\n \t.arg2_type      = ARG_PTR_TO_MEM | MEM_WRITE,\n-\t.arg3_type      = ARG_CONST_SIZE,\n+\t.arg3_type      = ARG_MEM_SIZE,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -6865,7 +6865,7 @@ static const struct bpf_func_proto bpf_lwt_in_push_encap_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE\n+\t.arg4_type\t= ARG_MEM_SIZE\n };\n \n static const struct bpf_func_proto bpf_lwt_xmit_push_encap_proto = {\n@@ -6875,7 +6875,7 @@ static const struct bpf_func_proto bpf_lwt_xmit_push_encap_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE\n+\t.arg4_type\t= ARG_MEM_SIZE\n };\n \n #if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\n@@ -6919,7 +6919,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_store_bytes_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE\n+\t.arg4_type\t= ARG_MEM_SIZE\n };\n \n static void bpf_update_srh_state(struct sk_buff *skb)\n@@ -7008,7 +7008,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_action_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg4_type\t= ARG_CONST_SIZE\n+\t.arg4_type\t= ARG_MEM_SIZE\n };\n \n BPF_CALL_3(bpf_lwt_seg6_adjust_srh, struct sk_buff *, skb, u32, offset,\n@@ -7249,7 +7249,7 @@ static const struct bpf_func_proto bpf_skc_lookup_tcp_proto = {\n \t.ret_type\t= RET_PTR_TO_SOCK_COMMON_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n@@ -7268,7 +7268,7 @@ static const struct bpf_func_proto bpf_sk_lookup_tcp_proto = {\n \t.ret_type\t= RET_PTR_TO_SOCKET_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n@@ -7287,7 +7287,7 @@ static const struct bpf_func_proto bpf_sk_lookup_udp_proto = {\n \t.ret_type\t= RET_PTR_TO_SOCKET_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n@@ -7311,7 +7311,7 @@ static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = {\n \t.ret_type\t= RET_PTR_TO_SOCK_COMMON_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n@@ -7335,7 +7335,7 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = {\n \t.ret_type\t= RET_PTR_TO_SOCKET_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n@@ -7359,7 +7359,7 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_udp_proto = {\n \t.ret_type\t= RET_PTR_TO_SOCKET_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n@@ -7397,7 +7397,7 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_udp_proto = {\n \t.ret_type       = RET_PTR_TO_SOCKET_OR_NULL,\n \t.arg1_type      = ARG_PTR_TO_CTX,\n \t.arg2_type      = ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type      = ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type      = ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type      = ARG_ANYTHING,\n \t.arg5_type      = ARG_ANYTHING,\n };\n@@ -7421,7 +7421,7 @@ static const struct bpf_func_proto bpf_xdp_skc_lookup_tcp_proto = {\n \t.ret_type       = RET_PTR_TO_SOCK_COMMON_OR_NULL,\n \t.arg1_type      = ARG_PTR_TO_CTX,\n \t.arg2_type      = ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type      = ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type      = ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type      = ARG_ANYTHING,\n \t.arg5_type      = ARG_ANYTHING,\n };\n@@ -7445,7 +7445,7 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_tcp_proto = {\n \t.ret_type       = RET_PTR_TO_SOCKET_OR_NULL,\n \t.arg1_type      = ARG_PTR_TO_CTX,\n \t.arg2_type      = ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type      = ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type      = ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type      = ARG_ANYTHING,\n \t.arg5_type      = ARG_ANYTHING,\n };\n@@ -7465,7 +7465,7 @@ static const struct bpf_func_proto bpf_sock_addr_skc_lookup_tcp_proto = {\n \t.ret_type\t= RET_PTR_TO_SOCK_COMMON_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n@@ -7484,7 +7484,7 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_tcp_proto = {\n \t.ret_type\t= RET_PTR_TO_SOCKET_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n@@ -7503,7 +7503,7 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_udp_proto = {\n \t.ret_type\t= RET_PTR_TO_SOCKET_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n \t.arg4_type\t= ARG_ANYTHING,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n@@ -7823,9 +7823,9 @@ static const struct bpf_func_proto bpf_tcp_check_syncookie_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID_SOCK_COMMON,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,\n@@ -7892,9 +7892,9 @@ static const struct bpf_func_proto bpf_tcp_gen_syncookie_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID_SOCK_COMMON,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg5_type\t= ARG_CONST_SIZE,\n+\t.arg5_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_3(bpf_sk_assign, struct sk_buff *, skb, struct sock *, sk, u64, flags)\n@@ -8048,7 +8048,7 @@ static const struct bpf_func_proto bpf_sock_ops_load_hdr_opt_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_WRITE,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -8126,7 +8126,7 @@ static const struct bpf_func_proto bpf_sock_ops_store_hdr_opt_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE,\n+\t.arg3_type\t= ARG_MEM_SIZE,\n \t.arg4_type\t= ARG_ANYTHING,\n };\n \n@@ -8221,7 +8221,7 @@ static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv4_proto = {\n \t.arg1_type\t= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY,\n \t.arg1_size\t= sizeof(struct iphdr),\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv6, struct ipv6hdr *, iph,\n@@ -8253,7 +8253,7 @@ static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv6_proto = {\n \t.arg1_type\t= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY,\n \t.arg1_size\t= sizeof(struct ipv6hdr),\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n-\t.arg3_type\t= ARG_CONST_SIZE_OR_ZERO,\n+\t.arg3_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n \n BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv4, struct iphdr *, iph,\n@@ -11726,7 +11726,7 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n };\n \n BPF_CALL_5(sk_reuseport_load_bytes_relative,\n@@ -11744,7 +11744,7 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_relative_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_ANYTHING,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n-\t.arg4_type\t= ARG_CONST_SIZE,\n+\t.arg4_type\t= ARG_MEM_SIZE,\n \t.arg5_type\t= ARG_ANYTHING,\n };\n \ndiff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c\nindex be97f6887f0e7f..a81faa709dd5bb 100644\n--- a/tools/testing/selftests/bpf/prog_tests/verifier.c\n+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c\n@@ -67,6 +67,7 @@\n #include \"verifier_masking.skel.h\"\n #include \"verifier_may_goto_1.skel.h\"\n #include \"verifier_may_goto_2.skel.h\"\n+#include \"verifier_mem_size_reg.skel.h\"\n #include \"verifier_meta_access.skel.h\"\n #include \"verifier_movsx.skel.h\"\n #include \"verifier_mtu.skel.h\"\n@@ -221,6 +222,7 @@ void test_verifier_map_ret_val(void)          { RUN(verifier_map_ret_val); }\n void test_verifier_masking(void)              { RUN(verifier_masking); }\n void test_verifier_may_goto_1(void)           { RUN(verifier_may_goto_1); }\n void test_verifier_may_goto_2(void)           { RUN(verifier_may_goto_2); }\n+void test_verifier_mem_size_reg(void)         { RUN(verifier_mem_size_reg); }\n void test_verifier_meta_access(void)          { RUN(verifier_meta_access); }\n void test_verifier_movsx(void)                 { RUN(verifier_movsx); }\n void test_verifier_mul(void)                  { RUN(verifier_mul); }\ndiff --git a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c\nindex d0d65d6d450cf5..efe7bcae70f85a 100644\n--- a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c\n+++ b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c\n@@ -64,7 +64,7 @@ int BPF_PROG(cgrp_kfunc_acquire_no_null_check, struct cgroup *cgrp, const char *\n }\n \n SEC(\"tp_btf/cgroup_mkdir\")\n-__failure __msg(\"R1 pointer type STRUCT cgroup must point\")\n+__failure __msg(\"R1 is fp expected STRUCT cgroup\")\n int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path)\n {\n \tstruct cgroup *acquired, *stack_cgrp = (struct cgroup *)\u0026path;\ndiff --git a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c\nindex 5b4453747c2308..0952d1ebf0f17a 100644\n--- a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c\n+++ b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c\n@@ -137,7 +137,7 @@ int helper_param_not_ok(void *ctx)\n \n \tp = bpf_rdonly_cast(0, 0);\n \t/*\n-\t * Any helper with ARG_CONST_SIZE_OR_ZERO constraint will do,\n+\t * Any helper with ARG_MEM_SIZE_OR_ZERO constraint will do,\n \t * the most permissive constraint\n \t */\n \tbpf_copy_from_user(p, 0, (void *)42);\ndiff --git a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c\nindex 8942b547812917..5c99b1e6532bfd 100644\n--- a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c\n+++ b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c\n@@ -50,7 +50,7 @@ int BPF_PROG(task_kfunc_acquire_untrusted, struct task_struct *task, u64 clone_f\n }\n \n SEC(\"tp_btf/task_newtask\")\n-__failure __msg(\"R1 pointer type STRUCT task_struct must point\")\n+__failure __msg(\"R1 is fp expected STRUCT task_struct\")\n int BPF_PROG(task_kfunc_acquire_fp, struct task_struct *task, u64 clone_flags)\n {\n \tstruct task_struct *acquired, *stack_task = (struct task_struct *)\u0026clone_flags;\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c\nindex bc038ac2df98e2..1a273e416fedff 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_bounds.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c\n@@ -1195,7 +1195,7 @@ l0_%=:\tr1 = r6;\t\t\t\t\t\\\n \tr3 += -8;\t\t\t\t\t\\\n \tr5 = 0;\t\t\t\t\t\t\\\n \t/* The 4th argument of bpf_skb_store_bytes is defined as \\\n-\t * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \\\n+\t * ARG_MEM_SIZE, so 0 is not allowed. The 'r4 != 0' \\\n \t * is providing us this exclusion of zero from initial \\\n \t * [0, 7] range.\t\t\t\t\\\n \t */\t\t\t\t\t\t\\\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c b/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c\nindex f2c54e4d89ebef..343fc08d974798 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c\n@@ -85,7 +85,7 @@ __naked void stack_bitwise_and_zero_included(void)\n \tr2 += -64;\t\t\t\t\t\\\n \tr4 = 0;\t\t\t\t\t\t\\\n \t/* Call bpf_ringbuf_output(), it is one of a few helper functions with\\\n-\t * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\\\n+\t * ARG_MEM_SIZE_OR_ZERO parameter allowed in unpriv mode.\\\n \t * For unpriv this should signal an error, because memory at \u0026fp[-64] is\\\n \t * not initialized.\t\t\t\t\\\n \t */\t\t\t\t\t\t\\\n@@ -278,7 +278,7 @@ __naked void stack_jmp_no_min_check(void)\n \tr2 += -64;\t\t\t\t\t\\\n \tr4 = 0;\t\t\t\t\t\t\\\n \t/* Call bpf_ringbuf_output(), it is one of a few helper functions with\\\n-\t * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\\\n+\t * ARG_MEM_SIZE_OR_ZERO parameter allowed in unpriv mode.\\\n \t * For unpriv this should signal an error, because memory at \u0026fp[-64] is\\\n \t * not initialized.\t\t\t\t\\\n \t */\t\t\t\t\t\t\\\n@@ -778,7 +778,7 @@ __naked void variable_memory_8_bytes_leak(void)\n \tr3 += 1;\t\t\t\t\t\\\n \tr4 = 0;\t\t\t\t\t\t\\\n \t/* Call bpf_ringbuf_output(), it is one of a few helper functions with\\\n-\t * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\\\n+\t * ARG_MEM_SIZE_OR_ZERO parameter allowed in unpriv mode.\\\n \t * For unpriv this should signal an error, because memory region [1, 64]\\\n \t * at \u0026fp[-64] is not fully initialized.\t\\\n \t */\t\t\t\t\t\t\\\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c b/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c\nindex 6d2a38597c34f4..c6603a118fdc39 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c\n@@ -91,7 +91,7 @@ l0_%=:\texit;\t\t\t\t\t\t\\\n \n /* Call a function taking a pointer and a size which doesn't allow the size to\n  * be zero (i.e. bpf_trace_printk() declares the second argument to be\n- * ARG_CONST_SIZE, not ARG_CONST_SIZE_OR_ZERO). We attempt to pass zero for the\n+ * ARG_MEM_SIZE, not ARG_MEM_SIZE_OR_ZERO). We attempt to pass zero for the\n  * size and expect to fail.\n  */\n SEC(\"tracepoint\")\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c b/tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c\nnew file mode 100644\nindex 00000000000000..78a9ad22b10dfd\n--- /dev/null\n+++ b/tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c\n@@ -0,0 +1,60 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \u003cvmlinux.h\u003e\n+#include \u003cbpf/bpf_helpers.h\u003e\n+#include \"bpf_misc.h\"\n+#include \"bpf_kfuncs.h\"\n+\n+char _license[] SEC(\"license\") = \"GPL\";\n+\n+struct inner_map {\n+\t__uint(type, BPF_MAP_TYPE_ARRAY);\n+\t__uint(max_entries, 1);\n+\t__type(key, int);\n+\t__type(value, int);\n+} inner_map SEC(\".maps\");\n+\n+struct {\n+\t__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);\n+\t__uint(max_entries, 1);\n+\t__type(key, int);\n+\t__array(values, struct inner_map);\n+} outer_map SEC(\".maps\") = {\n+\t.values = { [0] = \u0026inner_map },\n+};\n+\n+/* An un-narrowed map-of-maps value must be rejected as a __nullable kfunc mem buffer */\n+SEC(\"?tc\")\n+__failure\n+int mapofmaps_value_as_kfunc_mem_buf(struct __sk_buff *skb)\n+{\n+\tstruct bpf_dynptr dptr;\n+\t__u32 key = 0;\n+\tvoid *inner;\n+\tchar *p;\n+\n+\tinner = bpf_map_lookup_elem(\u0026outer_map, \u0026key);\n+\t/* intentionally NOT NULL-checked: reg stays PTR_TO_MAP_VALUE_OR_NULL */\n+\n+\tbpf_dynptr_from_skb(skb, 0, \u0026dptr);\n+\t/* pass the un-narrowed map-of-maps value as the scratch buffer */\n+\tp = bpf_dynptr_slice(\u0026dptr, 0, inner, 8);\n+\tif (p)\n+\t\treturn p[0];\n+\treturn 0;\n+}\n+\n+/* An un-narrowed map-of-maps value must be rejected as a PTR_MAYBE_NULL helper mem buffer */\n+SEC(\"?tc\")\n+__failure\n+int mapofmaps_value_as_helper_mem_buf(struct __sk_buff *skb)\n+{\n+\t__u32 key = 0;\n+\tvoid *inner;\n+\n+\tinner = bpf_map_lookup_elem(\u0026outer_map, \u0026key);\n+\t/* intentionally NOT NULL-checked: reg stays PTR_TO_MAP_VALUE_OR_NULL */\n+\n+\t/* @from is a nullable read-only mem+size arg; outer value_size is 4 */\n+\treturn bpf_csum_diff(inner, 4, NULL, 0, 0) + skb-\u003elen;\n+}\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c\nindex 2870738d93f7ec..8f0c45421f8938 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c\n@@ -28,7 +28,7 @@ int BPF_PROG(get_task_exe_file_kfunc_null)\n }\n \n SEC(\"lsm.s/inode_getxattr\")\n-__failure __msg(\"R1 pointer type STRUCT task_struct must point to scalar, or struct with scalar\")\n+__failure __msg(\"R1 is fp expected STRUCT task_struct\")\n int BPF_PROG(get_task_exe_file_kfunc_fp)\n {\n \tu64 x;\n@@ -98,7 +98,7 @@ int BPF_PROG(path_d_path_kfunc_null)\n }\n \n SEC(\"lsm.s/task_alloc\")\n-__failure __msg(\"R1 must be referenced or trusted\")\n+__failure __msg(\"dereference of modified untrusted_ptr_\")\n int BPF_PROG(path_d_path_kfunc_untrusted_from_argument, struct task_struct *task)\n {\n \tstruct path *root;\n@@ -112,7 +112,7 @@ int BPF_PROG(path_d_path_kfunc_untrusted_from_argument, struct task_struct *task\n }\n \n SEC(\"lsm.s/file_open\")\n-__failure __msg(\"R1 must be referenced or trusted\")\n+__failure __msg(\"dereference of modified untrusted_ptr_\")\n int BPF_PROG(path_d_path_kfunc_untrusted_from_current)\n {\n \tstruct path *pwd;\ndiff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c\nindex 302d712e0d7ed2..8cd626e0455157 100644\n--- a/tools/testing/selftests/bpf/verifier/calls.c\n+++ b/tools/testing/selftests/bpf/verifier/calls.c\n@@ -31,7 +31,7 @@\n \t},\n \t.prog_type = BPF_PROG_TYPE_SCHED_CLS,\n \t.result = REJECT,\n-\t.errstr = \"R1 pointer type STRUCT prog_test_fail1 must point to scalar\",\n+\t.errstr = \"R1 is fp expected STRUCT prog_test_fail1\",\n \t.fixup_kfunc_btf_id = {\n \t\t{ \"bpf_kfunc_call_test_fail1\", 2 },\n \t},\n@@ -46,7 +46,7 @@\n \t},\n \t.prog_type = BPF_PROG_TYPE_SCHED_CLS,\n \t.result = REJECT,\n-\t.errstr = \"max struct nesting depth exceeded\\nR1 pointer type STRUCT prog_test_fail2\",\n+\t.errstr = \"max struct nesting depth exceeded\\nR1 is fp expected STRUCT prog_test_fail2\",\n \t.fixup_kfunc_btf_id = {\n \t\t{ \"bpf_kfunc_call_test_fail2\", 2 },\n \t},\n@@ -61,7 +61,7 @@\n \t},\n \t.prog_type = BPF_PROG_TYPE_SCHED_CLS,\n \t.result = REJECT,\n-\t.errstr = \"R1 pointer type STRUCT prog_test_fail3 must point to scalar\",\n+\t.errstr = \"R1 is fp expected STRUCT prog_test_fail3\",\n \t.fixup_kfunc_btf_id = {\n \t\t{ \"bpf_kfunc_call_test_fail3\", 2 },\n \t},\n"
}

2/1 2026/07/24 09:17 agent patch-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": [
    "BPF_SYSCALL",
    "DEBUG_INFO_BTF"
  ],
  "FocusSymbols": [
    "gen_kfunc_arg_proto",
    "get_kfunc_arg_type",
    "process_map_ptr_arg",
    "check_kfunc_args",
    "check_func_arg",
    "check_mem_size_reg",
    "check_mem_reg",
    "process_const_arg"
  ],
  "Reasoning": "The patch significantly refactors how the eBPF verifier handles arguments for kfuncs and helper functions, introducing new argument types (ARG_MEM_SIZE, ARG_MEM_SIZE_OR_ZERO) and a new way to generate kfunc prototypes (gen_kfunc_arg_proto). This is core verifier logic that is highly complex and prone to security vulnerabilities, making it a prime target for fuzzing.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a '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:
For your convenience, here is the diff of the changes:
commit a49c57a3e69e2f3aac56ba2231f49f2aad1156a5
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Jul 24 09:17:05 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst
index c801a330aece08..cbde86d082ccea 100644
--- a/Documentation/bpf/kfuncs.rst
+++ b/Documentation/bpf/kfuncs.rst
@@ -250,6 +250,34 @@ Or::
                 ...
         }
 
+2.3.7 __const_map and __map Annotations
+---------------------------------------
+
+These annotations are used for ``struct bpf_map *`` arguments and distinguish a
+verifier-known map from an opaque one.
+
+``__const_map`` indicates a map must be known at the verification time, i.e. a
+concrete map fd the BPF program references directly.
+
+An example is given below::
+
+        __bpf_kfunc int bpf_wq_init(struct bpf_wq *wq, void *p__const_map,
+                                    unsigned int flags)
+        {
+                ...
+        }
+
+``__map`` indicates an opaque ``struct bpf_map *`` that may be resolved
+at run time. The argument may take either a map fd or a ``PTR_TO_BTF_ID``
+``struct bpf_map`` pointer.
+
+An example is given below::
+
+        __bpf_kfunc void *bpf_arena_alloc_pages(void *p__map, ...)
+        {
+                ...
+        }
+
 .. _BPF_kfunc_nodef:
 
 2.4 Using an existing kernel function
@@ -411,7 +439,7 @@ Example declaration:
 .. code-block:: c
 
 	__bpf_kfunc int bpf_task_work_schedule_signal(struct task_struct *task, struct bpf_task_work *tw,
-						      void *map__map, bpf_task_work_callback_t callback,
+						      void *map__const_map, bpf_task_work_callback_t callback,
 						      struct bpf_prog_aux *aux) { ... }
 
 Example usage in BPF program:
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index d9542127dfdfc0..2ea5ce30f729bb 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -748,6 +748,7 @@ extern const struct bpf_map_ops bpf_map_offload_ops;
 enum bpf_type_flag {
 	/* PTR may be NULL. */
 	PTR_MAYBE_NULL		= BIT(0 + BPF_BASE_TYPE_BITS),
+	SCALAR_MAYBE_ZERO	= PTR_MAYBE_NULL,
 
 	/* MEM is read-only. When applied on bpf_arg, it indicates the arg is
 	 * compatible with both mutable and immutable memory.
@@ -888,8 +889,7 @@ enum bpf_arg_type {
 	ARG_PTR_TO_MEM,		/* pointer to valid memory (stack, packet, map value) */
 	ARG_PTR_TO_ARENA,
 
-	ARG_CONST_SIZE,		/* number of bytes accessed from memory */
-	ARG_CONST_SIZE_OR_ZERO,	/* number of bytes accessed from memory or 0 */
+	ARG_MEM_SIZE,		/* number of bytes accessed from memory */
 
 	ARG_PTR_TO_CTX,		/* pointer to context */
 	ARG_ANYTHING,		/* any (initialized) argument is ok */
@@ -922,6 +922,8 @@ enum bpf_arg_type {
 	ARG_PTR_TO_UNINIT_MEM		= MEM_UNINIT | MEM_WRITE | ARG_PTR_TO_MEM,
 	/* Pointer to valid memory of size known at compile time. */
 	ARG_PTR_TO_FIXED_SIZE_MEM	= MEM_FIXED_SIZE | ARG_PTR_TO_MEM,
+	/* Number of bytes accessed from memory, or 0. */
+	ARG_MEM_SIZE_OR_ZERO		= SCALAR_MAYBE_ZERO | ARG_MEM_SIZE,
 
 	/* This must be the last entry. Its purpose is to ensure the enum is
 	 * wide enough to hold the higher bits reserved for bpf_type_flag.
@@ -960,6 +962,21 @@ enum bpf_return_type {
 };
 static_assert(__BPF_RET_TYPE_MAX <= BPF_BASE_TYPE_LIMIT);
 
+/* The longest tracepoint has 12 args.
+ * See include/trace/bpf_probe.h
+ *
+ * Also reuse this macro for maximum number of arguments a BPF function
+ * or a kfunc can have. Args 1-5 are passed in registers, args 6-12 via
+ * stack arg slots. The JIT may map some stack arg slots to registers based
+ * on the native calling convention (e.g., arg 6 to R9 on x86-64).
+ */
+#define MAX_BPF_FUNC_ARGS 12
+
+/* The maximum number of arguments passed through registers
+ * a single function may have.
+ */
+#define MAX_BPF_FUNC_REG_ARGS 5
+
 /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs
  * to in-kernel helper functions and for adjusting imm32 field in BPF_CALL
  * instructions after verifying
@@ -984,7 +1001,7 @@ struct bpf_func_proto {
 			enum bpf_arg_type arg4_type;
 			enum bpf_arg_type arg5_type;
 		};
-		enum bpf_arg_type arg_type[5];
+		enum bpf_arg_type arg_type[MAX_BPF_FUNC_ARGS];
 	};
 	union {
 		struct {
@@ -994,7 +1011,7 @@ struct bpf_func_proto {
 			u32 *arg4_btf_id;
 			u32 *arg5_btf_id;
 		};
-		u32 *arg_btf_id[5];
+		u32 *arg_btf_id[MAX_BPF_FUNC_ARGS];
 		struct {
 			size_t arg1_size;
 			size_t arg2_size;
@@ -1002,7 +1019,7 @@ struct bpf_func_proto {
 			size_t arg4_size;
 			size_t arg5_size;
 		};
-		size_t arg_size[5];
+		size_t arg_size[MAX_BPF_FUNC_ARGS];
 	};
 	int *ret_btf_id; /* return value btf_id */
 	bool (*allowed)(const struct bpf_prog *prog);
@@ -1192,21 +1209,6 @@ struct bpf_prog_offload {
 	u32			jited_len;
 };
 
-/* The longest tracepoint has 12 args.
- * See include/trace/bpf_probe.h
- *
- * Also reuse this macro for maximum number of arguments a BPF function
- * or a kfunc can have. Args 1-5 are passed in registers, args 6-12 via
- * stack arg slots. The JIT may map some stack arg slots to registers based
- * on the native calling convention (e.g., arg 6 to R9 on x86-64).
- */
-#define MAX_BPF_FUNC_ARGS 12
-
-/* The maximum number of arguments passed through registers
- * a single function may have.
- */
-#define MAX_BPF_FUNC_REG_ARGS 5
-
 /* The argument is a structure or a union. */
 #define BTF_FMODEL_STRUCT_ARG		BIT(0)
 
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 682c2cd3b84430..0655164e6af2eb 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -15,7 +15,7 @@
  * ensures that umax_value + (int)off + (int)size cannot overflow a u64.
  */
 #define BPF_MAX_VAR_OFF	(1 << 29)
-/* Maximum variable size permitted for ARG_CONST_SIZE[_OR_ZERO].  This ensures
+/* Maximum variable size permitted for ARG_MEM_SIZE[_OR_ZERO].  This ensures
  * that converting umax_value to int cannot overflow.
  */
 #define BPF_MAX_VAR_SIZ	(1 << 29)
@@ -1188,6 +1188,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
 			    u32 btf_id,
 			    struct bpf_attach_target_info *tgt_info);
 void bpf_free_kfunc_btf_tab(struct bpf_kfunc_btf_tab *tab);
+void bpf_free_kfunc_desc_tab(struct bpf_kfunc_desc_tab *tab);
 
 int mark_chain_precision(struct bpf_verifier_env *env, int regno);
 
@@ -1305,8 +1306,19 @@ static inline u32 type_flag(u32 type)
 /* only use after check_attach_btf_id() */
 static inline enum bpf_prog_type resolve_prog_type(const struct bpf_prog *prog)
 {
-	return (prog->type == BPF_PROG_TYPE_EXT && prog->aux->saved_dst_prog_type) ?
-		prog->aux->saved_dst_prog_type : prog->type;
+	if (prog->type == BPF_PROG_TYPE_EXT) {
+		/*
+		 * saved_dst_prog_type is only set once check_attach_btf_id()
+		 * runs. Before that -- e.g. when generating kfunc prototypes at
+		 * add-call time -- fall back to the attach target's type, which
+		 * is available from load time and holds the same value.
+		 */
+		if (prog->aux->saved_dst_prog_type)
+			return prog->aux->saved_dst_prog_type;
+		if (prog->aux->dst_prog)
+			return prog->aux->dst_prog->type;
+	}
+	return prog->type;
 }
 
 static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
@@ -1479,10 +1491,17 @@ struct ret_mem_desc {
 	bool found;
 };
 
+/* A constant scalar argument; Populated by process_const_arg() */
+struct arg_constant_desc {
+	u64 value;
+	bool found;
+};
+
 struct bpf_call_arg_meta {
 	/* Common */
 	struct btf *btf;
 	u32 func_id;
+	const struct bpf_func_proto *fn;
 	u8 release_regno;
 	u32 ret_btf_id;
 	u32 subprogno;
@@ -1496,10 +1515,7 @@ struct bpf_call_arg_meta {
 	u32 kfunc_flags;
 	const struct btf_type *func_proto;
 	const char *func_name;
-	struct {
-		u64 value;
-		bool found;
-	} arg_constant;
+	struct arg_constant_desc arg_constant;
 
 	/* arg_{btf,btf_id,owning_ref} are used by kfunc-specific handling,
 	 * generally to pass info about user-defined local kptr types to later
@@ -1614,6 +1630,7 @@ enum bpf_reg_arg_type {
 
 struct bpf_kfunc_desc {
 	struct btf_func_model func_model;
+	struct bpf_func_proto *proto;
 	u32 func_id;
 	s32 imm;
 	u16 offset;
diff --git a/kernel/bpf/backtrack.c b/kernel/bpf/backtrack.c
index 2e4ae0ef08609d..2f473ad4fd7c1c 100644
--- a/kernel/bpf/backtrack.c
+++ b/kernel/bpf/backtrack.c
@@ -636,7 +636,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
  * r5 += 1
  * ...
  * call bpf_perf_event_output#25
- *   where .arg5_type = ARG_CONST_SIZE_OR_ZERO
+ *   where .arg5_type = ARG_MEM_SIZE_OR_ZERO
  *
  * and this case:
  * r6 = 1
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index 3983b4ce73c811..82c5988417a0cf 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -186,7 +186,7 @@ static const struct bpf_func_proto bpf_ima_inode_hash_proto = {
 	.arg1_type	= ARG_PTR_TO_BTF_ID,
 	.arg1_btf_id	= &bpf_ima_inode_hash_btf_ids[0],
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.allowed	= bpf_ima_inode_hash_allowed,
 };
 
@@ -205,7 +205,7 @@ static const struct bpf_func_proto bpf_ima_file_hash_proto = {
 	.arg1_type	= ARG_PTR_TO_BTF_ID,
 	.arg1_btf_id	= &bpf_ima_file_hash_btf_ids[0],
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.allowed	= bpf_ima_inode_hash_allowed,
 };
 
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index cbb1e49b9bcbf5..a23a42cbe3b135 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8707,7 +8707,7 @@ const struct bpf_func_proto bpf_btf_find_by_name_kind_proto = {
 	.gpl_only	= false,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg2_type	= ARG_CONST_SIZE,
+	.arg2_type	= ARG_MEM_SIZE,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_ANYTHING,
 };
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 4355ccb78a9c67..fb9357b64cadbc 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -2305,7 +2305,7 @@ static const struct bpf_func_proto bpf_sysctl_get_name_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_WRITE,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -2347,7 +2347,7 @@ static const struct bpf_func_proto bpf_sysctl_get_current_value_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_3(bpf_sysctl_get_new_value, struct bpf_sysctl_kern *, ctx, char *, buf,
@@ -2367,7 +2367,7 @@ static const struct bpf_func_proto bpf_sysctl_get_new_value_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_3(bpf_sysctl_set_new_value, struct bpf_sysctl_kern *, ctx,
@@ -2393,7 +2393,7 @@ static const struct bpf_func_proto bpf_sysctl_set_new_value_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 };
 
 static const struct bpf_func_proto *
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 47fe047ad30b88..a30e7471e9d81e 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -198,7 +198,9 @@ void bpf_prog_jit_attempt_done(struct bpf_prog *prog)
 		prog->aux->jited_linfo = NULL;
 	}
 
-	kfree(prog->aux->kfunc_tab);
+#ifdef CONFIG_BPF_SYSCALL
+	bpf_free_kfunc_desc_tab(prog->aux->kfunc_tab);
+#endif
 	prog->aux->kfunc_tab = NULL;
 }
 
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index c18f1e16edee4c..18be5d6e4f9c29 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -278,7 +278,7 @@ const struct bpf_func_proto bpf_get_current_comm_proto = {
 	.gpl_only	= false,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE,
+	.arg2_type	= ARG_MEM_SIZE,
 };
 
 #if defined(CONFIG_QUEUED_SPINLOCKS) || defined(CONFIG_BPF_ARCH_SPINLOCK)
@@ -539,7 +539,7 @@ const struct bpf_func_proto bpf_strtol_proto = {
 	.gpl_only	= false,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg2_type	= ARG_CONST_SIZE,
+	.arg2_type	= ARG_MEM_SIZE,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
 	.arg4_size	= sizeof(s64),
@@ -567,7 +567,7 @@ const struct bpf_func_proto bpf_strtoul_proto = {
 	.gpl_only	= false,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg2_type	= ARG_CONST_SIZE,
+	.arg2_type	= ARG_MEM_SIZE,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
 	.arg4_size	= sizeof(u64),
@@ -583,7 +583,7 @@ static const struct bpf_func_proto bpf_strncmp_proto = {
 	.gpl_only	= false,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg2_type	= ARG_CONST_SIZE,
+	.arg2_type	= ARG_MEM_SIZE,
 	.arg3_type	= ARG_PTR_TO_CONST_STR,
 };
 
@@ -627,7 +627,7 @@ const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto = {
 	.arg1_type	= ARG_ANYTHING,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type      = ARG_PTR_TO_UNINIT_MEM,
-	.arg4_type      = ARG_CONST_SIZE,
+	.arg4_type      = ARG_MEM_SIZE,
 };
 
 static const struct bpf_func_proto bpf_get_raw_smp_processor_id_proto = {
@@ -653,7 +653,7 @@ const struct bpf_func_proto bpf_event_output_data_proto =  {
 	.arg2_type      = ARG_CONST_MAP_PTR,
 	.arg3_type      = ARG_ANYTHING,
 	.arg4_type      = ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type      = ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type      = ARG_MEM_SIZE_OR_ZERO,
 };
 
 BPF_CALL_3(bpf_copy_from_user, void *, dst, u32, size,
@@ -675,7 +675,7 @@ const struct bpf_func_proto bpf_copy_from_user_proto = {
 	.might_sleep	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 };
 
@@ -706,7 +706,7 @@ const struct bpf_func_proto bpf_copy_from_user_task_proto = {
 	.might_sleep	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_BTF_ID,
 	.arg4_btf_id	= &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
@@ -1093,10 +1093,10 @@ const struct bpf_func_proto bpf_snprintf_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_PTR_TO_CONST_STR,
 	.arg4_type	= ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 static void *map_key_from_value(struct bpf_map *map, void *value, u32 *arr_idx)
@@ -1888,7 +1888,7 @@ static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
 	.gpl_only	= false,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT | MEM_WRITE,
 };
@@ -1943,7 +1943,7 @@ static const struct bpf_func_proto bpf_dynptr_read_proto = {
 	.gpl_only	= false,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_PTR_TO_DYNPTR,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
@@ -2004,7 +2004,7 @@ static const struct bpf_func_proto bpf_dynptr_write_proto = {
 	.arg1_type	= ARG_PTR_TO_DYNPTR,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg4_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg5_type	= ARG_ANYTHING,
 };
 
@@ -3404,10 +3404,10 @@ __bpf_kfunc void bpf_throw(u64 cookie)
 	WARN(1, "A call to BPF exception callback should never return\n");
 }
 
-__bpf_kfunc int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags)
+__bpf_kfunc int bpf_wq_init(struct bpf_wq *wq, void *p__const_map, unsigned int flags)
 {
 	struct bpf_async_kern *async = (struct bpf_async_kern *)wq;
-	struct bpf_map *map = p__map;
+	struct bpf_map *map = p__const_map;
 
 	BUILD_BUG_ON(sizeof(struct bpf_async_kern) > sizeof(struct bpf_wq));
 	BUILD_BUG_ON(__alignof__(struct bpf_async_kern) != __alignof__(struct bpf_wq));
@@ -4642,17 +4642,17 @@ static int bpf_task_work_schedule(struct task_struct *task, struct bpf_task_work
  * mode
  * @task: Task struct for which callback should be scheduled
  * @tw: Pointer to struct bpf_task_work in BPF map value for internal bookkeeping
- * @map__map: bpf_map that embeds struct bpf_task_work in the values
+ * @map__const_map: bpf_map that embeds struct bpf_task_work in the values
  * @callback: pointer to BPF subprogram to call
  * @aux: pointer to bpf_prog_aux of the caller BPF program, implicitly set by the verifier
  *
  * Return: 0 if task work has been scheduled successfully, negative error code otherwise
  */
 __bpf_kfunc int bpf_task_work_schedule_signal(struct task_struct *task, struct bpf_task_work *tw,
-					      void *map__map, bpf_task_work_callback_t callback,
+					      void *map__const_map, bpf_task_work_callback_t callback,
 					      struct bpf_prog_aux *aux)
 {
-	return bpf_task_work_schedule(task, tw, map__map, callback, aux, TWA_SIGNAL);
+	return bpf_task_work_schedule(task, tw, map__const_map, callback, aux, TWA_SIGNAL);
 }
 
 /**
@@ -4660,17 +4660,17 @@ __bpf_kfunc int bpf_task_work_schedule_signal(struct task_struct *task, struct b
  * mode
  * @task: Task struct for which callback should be scheduled
  * @tw: Pointer to struct bpf_task_work in BPF map value for internal bookkeeping
- * @map__map: bpf_map that embeds struct bpf_task_work in the values
+ * @map__const_map: bpf_map that embeds struct bpf_task_work in the values
  * @callback: pointer to BPF subprogram to call
  * @aux: pointer to bpf_prog_aux of the caller BPF program, implicitly set by the verifier
  *
  * Return: 0 if task work has been scheduled successfully, negative error code otherwise
  */
 __bpf_kfunc int bpf_task_work_schedule_resume(struct task_struct *task, struct bpf_task_work *tw,
-					      void *map__map, bpf_task_work_callback_t callback,
+					      void *map__const_map, bpf_task_work_callback_t callback,
 					      struct bpf_prog_aux *aux)
 {
-	return bpf_task_work_schedule(task, tw, map__map, callback, aux, TWA_RESUME);
+	return bpf_task_work_schedule(task, tw, map__const_map, callback, aux, TWA_RESUME);
 }
 
 static int make_file_dynptr(struct file *file, u32 flags, bool may_sleep,
diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c
index 35ae64ade36b83..c1bf7a197a96f3 100644
--- a/kernel/bpf/ringbuf.c
+++ b/kernel/bpf/ringbuf.c
@@ -634,7 +634,7 @@ const struct bpf_func_proto bpf_ringbuf_output_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_CONST_MAP_PTR,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 41fe87d7302f22..463f94ba1cc478 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -781,7 +781,7 @@ const struct bpf_func_proto bpf_get_stack_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -797,7 +797,7 @@ const struct bpf_func_proto bpf_get_stack_sleepable_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -831,7 +831,7 @@ const struct bpf_func_proto bpf_get_task_stack_proto = {
 	.arg1_type	= ARG_PTR_TO_BTF_ID,
 	.arg1_btf_id	= &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -848,7 +848,7 @@ const struct bpf_func_proto bpf_get_task_stack_sleepable_proto = {
 	.arg1_type	= ARG_PTR_TO_BTF_ID,
 	.arg1_btf_id	= &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -911,7 +911,7 @@ const struct bpf_func_proto bpf_get_stack_proto_pe = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0ff9e3aa293d57..0b5dc6788ba27f 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2444,7 +2444,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
 	module_put(prog->aux->mod);
 	kvfree(prog->aux->jited_linfo);
 	kvfree(prog->aux->linfo);
-	kfree(prog->aux->kfunc_tab);
+	bpf_free_kfunc_desc_tab(prog->aux->kfunc_tab);
 	kfree(prog->aux->ctx_arg_info);
 	if (prog->aux->attach_btf)
 		btf_put(prog->aux->attach_btf);
@@ -6544,7 +6544,7 @@ static const struct bpf_func_proto bpf_sys_bpf_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_ANYTHING,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 };
 
 const struct bpf_func_proto * __weak
@@ -6591,7 +6591,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
 	.gpl_only	= false,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
 	.arg4_size	= sizeof(u64),
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 52be0a118cce07..aca37a7bf2cbc7 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2719,8 +2719,25 @@ static int fetch_kfunc_meta(struct bpf_verifier_env *env,
 	return 0;
 }
 
+static int gen_kfunc_arg_proto(struct bpf_verifier_env *env,
+			       struct bpf_call_arg_meta *meta,
+			       struct bpf_func_proto *proto);
+
+void bpf_free_kfunc_desc_tab(struct bpf_kfunc_desc_tab *tab)
+{
+	u32 i;
+
+	if (!tab)
+		return;
+	for (i = 0; i < tab->nr_descs; i++)
+		kfree(tab->descs[i].proto);
+	kfree(tab);
+}
+
 int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset)
 {
+	struct bpf_call_arg_meta meta;
+	struct bpf_func_proto *proto;
 	struct bpf_kfunc_btf_tab *btf_tab;
 	struct btf_func_model func_model;
 	struct bpf_kfunc_desc_tab *tab;
@@ -2806,11 +2823,29 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset)
 	if (err)
 		return err;
 
+	proto = kzalloc_obj(*proto, GFP_KERNEL_ACCOUNT);
+	if (!proto)
+		return -ENOMEM;
+
+	memset(&meta, 0, sizeof(meta));
+	meta.btf = kfunc.btf;
+	meta.func_id = kfunc.id;
+	meta.func_proto = kfunc.proto;
+	meta.func_name = kfunc.name;
+	meta.kfunc_flags = kfunc.flags ? *kfunc.flags : 0;
+
+	err = gen_kfunc_arg_proto(env, &meta, proto);
+	if (err) {
+		kfree(proto);
+		return err;
+	}
+
 	desc = &tab->descs[tab->nr_descs++];
 	desc->func_id = func_id;
 	desc->offset = offset;
 	desc->addr = addr;
 	desc->func_model = func_model;
+	desc->proto = proto;
 	sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]),
 	     kfunc_desc_cmp_by_id_off, NULL);
 	return 0;
@@ -4924,6 +4959,19 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = {
 	[CONST_PTR_TO_MAP] = btf_bpf_map_id,
 };
 
+static enum bpf_reg_type lookup_reg2btf_ids(const struct btf_type *ref_t)
+{
+	enum bpf_reg_type type;
+
+	for (type = 0; type < __BPF_REG_TYPE_MAX; type++) {
+		if (reg2btf_ids[type] &&
+		    btf_type_by_id(btf_vmlinux, *reg2btf_ids[type]) == ref_t)
+			return type;
+	}
+
+	return NOT_INIT;
+}
+
 static bool is_trusted_reg(struct bpf_verifier_env *env, const struct bpf_reg_state *reg)
 {
 	/* A referenced register is always trusted. */
@@ -6873,7 +6921,14 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,
 			      bool zero_size_allowed,
 			      struct bpf_call_arg_meta *meta)
 {
-	int err;
+	bool may_be_null = type_may_be_null(mem_reg->type);
+	struct bpf_reg_state saved_reg;
+	int err = 0;
+
+	if (may_be_null) {
+		saved_reg = *mem_reg;
+		mark_ptr_not_null_reg(mem_reg);
+	}
 
 	/* This is used to refine r0 return value bounds for helpers
 	 * that enforce this value as an upper bound on return values.
@@ -6910,8 +6965,14 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,
 			reg_arg_name(env, size_argno));
 		return -EACCES;
 	}
-	err = check_helper_mem_access(env, mem_reg, mem_argno, reg_umax(size_reg),
-				      access_type, zero_size_allowed, meta);
+
+	if (access_type & BPF_READ)
+		err = check_helper_mem_access(env, mem_reg, mem_argno, reg_umax(size_reg),
+					      BPF_READ, zero_size_allowed, meta);
+	if (!err && access_type & BPF_WRITE)
+		err = check_helper_mem_access(env, mem_reg, mem_argno, reg_umax(size_reg),
+					      BPF_WRITE, zero_size_allowed, meta);
+
 	if (!err) {
 		int regno = reg_from_argno(size_argno);
 
@@ -6920,15 +6981,22 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,
 		else
 			err = mark_stack_arg_precision(env, arg_idx_from_argno(size_argno));
 	}
+
+	if (may_be_null)
+		*mem_reg = saved_reg;
+
 	return err;
 }
 
 static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
-			 argno_t argno, u32 mem_size)
+			 argno_t argno, u32 mem_size, enum bpf_access_type access_type,
+			 struct bpf_call_arg_meta *meta)
 {
+	/* meta->btf is set only for kfuncs; a NULL meta means a global subprog. */
+	bool helper = meta && !meta->btf;
 	bool may_be_null = type_may_be_null(reg->type);
 	struct bpf_reg_state saved_reg;
-	int err;
+	int size, err = 0;
 
 	if (bpf_register_is_null(reg))
 		return 0;
@@ -6948,10 +7016,12 @@ static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg
 		mark_ptr_not_null_reg(reg);
 	}
 
-	int size = base_type(reg->type) == PTR_TO_STACK ? -(int)mem_size : mem_size;
+	size = (!helper && base_type(reg->type) == PTR_TO_STACK) ? -(int)mem_size : mem_size;
 
-	err = check_helper_mem_access(env, reg, argno, size, BPF_READ, true, NULL);
-	err = err ?: check_helper_mem_access(env, reg, argno, size, BPF_WRITE, true, NULL);
+	if (access_type & BPF_READ)
+		err = check_helper_mem_access(env, reg, argno, size, BPF_READ, true, meta);
+	if (!err && (access_type & BPF_WRITE))
+		err = check_helper_mem_access(env, reg, argno, size, BPF_WRITE, true, meta);
 
 	if (may_be_null)
 		*reg = saved_reg;
@@ -6993,28 +7063,33 @@ static int process_const_alloc_mem_size(struct bpf_verifier_env *env, struct bpf
 	return 0;
 }
 
-static int check_kfunc_mem_size_reg(struct bpf_verifier_env *env, struct bpf_reg_state *mem_reg,
-				    struct bpf_reg_state *size_reg, argno_t mem_argno, argno_t size_argno)
+static int process_const_arg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+			     argno_t argno, struct bpf_call_arg_meta *meta)
 {
-	bool may_be_null = type_may_be_null(mem_reg->type);
-	struct bpf_reg_state saved_reg;
-	struct bpf_call_arg_meta meta;
+	int regno = reg_from_argno(argno);
 	int err;
 
-	memset(&meta, 0, sizeof(meta));
+	if (meta->arg_constant.found) {
+		verifier_bug(env, "only one constant argument permitted");
+		return -EFAULT;
+	}
 
-	if (may_be_null) {
-		saved_reg = *mem_reg;
-		mark_ptr_not_null_reg(mem_reg);
+	if (!tnum_is_const(reg->var_off)) {
+		verbose(env, "%s must be a known constant\n", reg_arg_name(env, argno));
+		return -EINVAL;
 	}
 
-	err = check_mem_size_reg(env, mem_reg, size_reg, mem_argno, size_argno, BPF_READ, true, &meta);
-	err = err ?: check_mem_size_reg(env, mem_reg, size_reg, mem_argno, size_argno, BPF_WRITE, true, &meta);
+	if (regno >= 0)
+		err = mark_chain_precision(env, regno);
+	else
+		err = mark_stack_arg_precision(env, arg_idx_from_argno(argno));
+	if (err < 0)
+		return err;
 
-	if (may_be_null)
-		*mem_reg = saved_reg;
+	meta->arg_constant.found = true;
+	meta->arg_constant.value = reg->var_off.value;
 
-	return err;
+	return 0;
 }
 
 enum {
@@ -7224,18 +7299,6 @@ static int process_timer_func(struct bpf_verifier_env *env, struct bpf_reg_state
 	return check_map_field_pointer(env, reg, argno, BPF_TIMER, map);
 }
 
-static int process_timer_helper(struct bpf_verifier_env *env, struct bpf_reg_state *reg, argno_t argno,
-				struct bpf_call_arg_meta *meta)
-{
-	return process_timer_func(env, reg, argno, &meta->map);
-}
-
-static int process_timer_kfunc(struct bpf_verifier_env *env, struct bpf_reg_state *reg, argno_t argno,
-			       struct bpf_call_arg_meta *meta)
-{
-	return process_timer_func(env, reg, argno, &meta->map);
-}
-
 static int process_kptr_func(struct bpf_verifier_env *env, int regno,
 			     struct bpf_call_arg_meta *meta)
 {
@@ -7738,8 +7801,7 @@ static int process_iter_next_call(struct bpf_verifier_env *env, int insn_idx,
 
 static bool arg_type_is_mem_size(enum bpf_arg_type type)
 {
-	return type == ARG_CONST_SIZE ||
-	       type == ARG_CONST_SIZE_OR_ZERO;
+	return base_type(type) == ARG_MEM_SIZE;
 }
 
 static bool arg_type_is_raw_mem(enum bpf_arg_type type)
@@ -7885,8 +7947,7 @@ static const struct bpf_reg_types dynptr_types = {
 static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
 	[ARG_PTR_TO_MAP_KEY]		= &mem_types,
 	[ARG_PTR_TO_MAP_VALUE]		= &mem_types,
-	[ARG_CONST_SIZE]		= &scalar_types,
-	[ARG_CONST_SIZE_OR_ZERO]	= &scalar_types,
+	[ARG_MEM_SIZE]			= &scalar_types,
 	[ARG_CONST_ALLOC_SIZE_OR_ZERO]	= &scalar_types,
 	[ARG_CONST_MAP_PTR]		= &const_map_ptr_types,
 	[ARG_PTR_TO_CTX]		= &context_types,
@@ -8286,11 +8347,55 @@ static int get_constant_map_key(struct bpf_verifier_env *env,
 
 static bool can_elide_value_nullness(const struct bpf_map *map);
 
+/* Record the bpf_map argument of a helper or kfunc call in meta->map.
+ *
+ * When meta->map is already set from an earlier argument (a timer, workqueue or
+ * task_work object that is bound to a map), reject a map pointer that does not
+ * match it. That object sits in the register right before the map argument, and
+ * its type is taken from the bound map's record for the diagnostic.
+ */
+static int process_map_ptr_arg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+			       argno_t argno, struct bpf_call_arg_meta *meta)
+{
+	int map_regno = reg_from_argno(argno);
+
+	/* Use map_uid (which is unique id of inner map) to reject:
+	 * inner_map1 = bpf_map_lookup_elem(outer_map, key1)
+	 * inner_map2 = bpf_map_lookup_elem(outer_map, key2)
+	 * if (inner_map1 && inner_map2) {
+	 *     timer = bpf_map_lookup_elem(inner_map1);
+	 *     if (timer)
+	 *         // mismatch would have been allowed
+	 *         bpf_timer_init(timer, inner_map2);
+	 * }
+	 *
+	 * Comparing map_ptr is enough to distinguish normal and outer maps.
+	 */
+	if (meta->map.ptr &&
+	    (meta->map.ptr != reg->map_ptr || meta->map.uid != reg->map_uid)) {
+		struct btf_record *rec = meta->map.ptr->record;
+		const char *obj_name = "workqueue";
+
+		if (rec->timer_off >= 0)
+			obj_name = "timer";
+		else if (rec->task_work_off >= 0)
+			obj_name = "bpf_task_work";
+
+		verbose(env, "%s pointer in R%d map_uid=%d doesn't match map pointer in R%d map_uid=%d\n",
+			obj_name, map_regno - 1, meta->map.uid, map_regno, reg->map_uid);
+		return -EINVAL;
+	}
+
+	meta->map.ptr = reg->map_ptr;
+	meta->map.uid = reg->map_uid;
+	return 0;
+}
+
 static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
 			  struct bpf_call_arg_meta *meta,
-			  const struct bpf_func_proto *fn,
 			  int insn_idx)
 {
+	const struct bpf_func_proto *fn = meta->fn;
 	u32 regno = BPF_REG_1 + arg;
 	struct bpf_reg_state *reg = reg_state(env, regno);
 	enum bpf_arg_type arg_type = fn->arg_type[arg];
@@ -8361,29 +8466,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
 	switch (base_type(arg_type)) {
 	case ARG_CONST_MAP_PTR:
 		/* bpf_map_xxx(map_ptr) call: remember that map_ptr */
-		if (meta->map.ptr) {
-			/* Use map_uid (which is unique id of inner map) to reject:
-			 * inner_map1 = bpf_map_lookup_elem(outer_map, key1)
-			 * inner_map2 = bpf_map_lookup_elem(outer_map, key2)
-			 * if (inner_map1 && inner_map2) {
-			 *     timer = bpf_map_lookup_elem(inner_map1);
-			 *     if (timer)
-			 *         // mismatch would have been allowed
-			 *         bpf_timer_init(timer, inner_map2);
-			 * }
-			 *
-			 * Comparing map_ptr is enough to distinguish normal and outer maps.
-			 */
-			if (meta->map.ptr != reg->map_ptr ||
-			    meta->map.uid != reg->map_uid) {
-				verbose(env,
-					"timer pointer in R1 map_uid=%d doesn't match map pointer in R2 map_uid=%d\n",
-					meta->map.uid, reg->map_uid);
-				return -EINVAL;
-			}
-		}
-		meta->map.ptr = reg->map_ptr;
-		meta->map.uid = reg->map_uid;
+		err = process_map_ptr_arg(env, reg, argno, meta);
+		if (err)
+			return err;
 		break;
 	case ARG_PTR_TO_MAP_KEY:
 		/* bpf_map_xxx(..., map_ptr, ..., key) call:
@@ -8466,7 +8551,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
 		}
 		break;
 	case ARG_PTR_TO_TIMER:
-		err = process_timer_helper(env, reg, argno, meta);
+		err = process_timer_func(env, reg, argno, &meta->map);
 		if (err)
 			return err;
 		break;
@@ -8474,31 +8559,22 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
 		meta->subprogno = reg->subprogno;
 		break;
 	case ARG_PTR_TO_MEM:
-		/* The access to this pointer is only checked when we hit the
-		 * next is_mem_size argument below.
-		 */
 		if (arg_type & MEM_FIXED_SIZE) {
-			err = check_helper_mem_access(env, reg, argno, fn->arg_size[arg],
-						      arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ,
-						      false, meta);
+			err = check_mem_reg(env, reg, argno_from_reg(regno), fn->arg_size[arg],
+					    arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ, meta);
 			if (err)
 				return err;
 			if (arg_type & MEM_ALIGNED)
 				err = check_ptr_alignment(env, reg, 0, fn->arg_size[arg], true);
+		} else {
+			struct bpf_reg_state *size_reg = reg_state(env, regno + 1);
+
+			err = check_mem_size_reg(env, reg, size_reg, argno,
+						 argno_from_reg(regno + 1),
+						 arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ,
+						 fn->arg_type[arg + 1] & SCALAR_MAYBE_ZERO, meta);
 		}
 		break;
-	case ARG_CONST_SIZE:
-		err = check_mem_size_reg(env, reg_state(env, regno - 1), reg,
-					 argno_from_reg(regno - 1), argno,
-					 fn->arg_type[arg - 1] & MEM_WRITE ? BPF_WRITE : BPF_READ,
-					 false, meta);
-		break;
-	case ARG_CONST_SIZE_OR_ZERO:
-		err = check_mem_size_reg(env, reg_state(env, regno - 1), reg,
-					 argno_from_reg(regno - 1), argno,
-					 fn->arg_type[arg - 1] & MEM_WRITE ? BPF_WRITE : BPF_READ,
-					 true, meta);
-		break;
 	case ARG_PTR_TO_DYNPTR:
 		err = process_dynptr_func(env, reg, argno, insn_idx, arg_type, &meta->ref_obj,
 					  &meta->dynptr);
@@ -8823,7 +8899,7 @@ static bool check_raw_mode_ok(const struct bpf_func_proto *fn, struct bpf_call_a
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
+	for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
 		if (!arg_type_is_raw_mem(fn->arg_type[i]))
 			continue;
 		if (meta->arg_raw_mem.regno)
@@ -8840,7 +8916,7 @@ static bool check_args_pair_invalid(const struct bpf_func_proto *fn, int arg)
 	bool has_size = fn->arg_size[arg] != 0;
 	bool is_next_size = false;
 
-	if (arg + 1 < ARRAY_SIZE(fn->arg_type))
+	if (arg + 1 < MAX_BPF_FUNC_REG_ARGS)
 		is_next_size = arg_type_is_mem_size(fn->arg_type[arg + 1]);
 
 	if (base_type(fn->arg_type[arg]) != ARG_PTR_TO_MEM)
@@ -8871,7 +8947,7 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
+	for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
 		if (base_type(fn->arg_type[i]) == ARG_PTR_TO_BTF_ID)
 			return !!fn->arg_btf_id[i];
 		if (base_type(fn->arg_type[i]) == ARG_PTR_TO_SPIN_LOCK)
@@ -8890,7 +8966,7 @@ static bool check_mem_arg_rw_flag_ok(const struct bpf_func_proto *fn)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
+	for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
 		enum bpf_arg_type arg_type = fn->arg_type[i];
 
 		if (base_type(arg_type) != ARG_PTR_TO_MEM)
@@ -8906,7 +8982,7 @@ static bool check_proto_release_reg(const struct bpf_func_proto *fn, struct bpf_
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
+	for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
 		enum bpf_arg_type arg_type = fn->arg_type[i];
 
 		if (arg_type_is_release(arg_type)) {
@@ -9252,7 +9328,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
 			ret = check_func_arg_reg_off(env, reg, argno, ARG_DONTCARE);
 			if (ret < 0)
 				return ret;
-			if (check_mem_reg(env, reg, argno, arg->mem_size))
+			if (check_mem_reg(env, reg, argno, arg->mem_size, BPF_READ | BPF_WRITE, NULL))
 				return -EINVAL;
 			if (!(arg->arg_type & PTR_MAYBE_NULL) && (reg->type & PTR_MAYBE_NULL)) {
 				bpf_log(log, "%s is expected to be non-NULL\n",
@@ -10297,9 +10373,10 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 		env->insn_aux_data[insn_idx].non_sleepable = true;
 
 	meta.func_id = func_id;
+	meta.fn = fn;
 	/* check args */
 	for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
-		err = check_func_arg(env, i, &meta, fn, insn_idx);
+		err = check_func_arg(env, i, &meta, insn_idx);
 		if (err)
 			return err;
 	}
@@ -10771,26 +10848,24 @@ static bool is_kfunc_rcu_protected(struct bpf_call_arg_meta *meta)
 }
 
 static bool is_kfunc_arg_mem_size(const struct btf *btf,
-				  const struct btf_param *arg,
-				  const struct bpf_reg_state *reg)
+				  const struct btf_param *arg)
 {
 	const struct btf_type *t;
 
 	t = btf_type_skip_modifiers(btf, arg->type, NULL);
-	if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE)
+	if (!btf_type_is_scalar(t))
 		return false;
 
 	return btf_param_match_suffix(btf, arg, "__sz");
 }
 
 static bool is_kfunc_arg_const_mem_size(const struct btf *btf,
-					const struct btf_param *arg,
-					const struct bpf_reg_state *reg)
+					const struct btf_param *arg)
 {
 	const struct btf_type *t;
 
 	t = btf_type_skip_modifiers(btf, arg->type, NULL);
-	if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE)
+	if (!btf_type_is_scalar(t))
 		return false;
 
 	return btf_param_match_suffix(btf, arg, "__szk");
@@ -10811,6 +10886,11 @@ static bool is_kfunc_arg_map(const struct btf *btf, const struct btf_param *arg)
 	return btf_param_match_suffix(btf, arg, "__map");
 }
 
+static bool is_kfunc_arg_const_map(const struct btf *btf, const struct btf_param *arg)
+{
+	return btf_param_match_suffix(btf, arg, "__const_map");
+}
+
 static bool is_kfunc_arg_alloc_obj(const struct btf *btf, const struct btf_param *arg)
 {
 	return btf_param_match_suffix(btf, arg, "__alloc");
@@ -11051,18 +11131,21 @@ enum kfunc_ptr_arg_type {
 	KF_ARG_PTR_TO_LIST_NODE,
 	KF_ARG_PTR_TO_BTF_ID,	       /* Also covers reg2btf_ids conversions */
 	KF_ARG_PTR_TO_MEM,
-	KF_ARG_PTR_TO_MEM_SIZE,	       /* Size derived from next argument, skip it */
 	KF_ARG_PTR_TO_CALLBACK,
 	KF_ARG_PTR_TO_RB_ROOT,
 	KF_ARG_PTR_TO_RB_NODE,
-	KF_ARG_PTR_TO_NULL,
 	KF_ARG_PTR_TO_CONST_STR,
-	KF_ARG_PTR_TO_MAP,
+	KF_ARG_CONST_MAP_PTR,
 	KF_ARG_PTR_TO_TIMER,
 	KF_ARG_PTR_TO_WORKQUEUE,
 	KF_ARG_PTR_TO_IRQ_FLAG,
 	KF_ARG_PTR_TO_RES_SPIN_LOCK,
 	KF_ARG_PTR_TO_TASK_WORK,
+	KF_ARG_CONST_BTF_ID,	       /* const scalar carrying a BTF type id */
+	KF_ARG_CONST_MEM_SIZE,	       /* const scalar sizing a preceding memory arg */
+	KF_ARG_CONST_ALLOC_SIZE_OR_ZERO, /* const scalar sizing a returned buffer */
+	KF_ARG_MEM_SIZE,	       /* scalar sizing a preceding memory arg */
+	KF_ARG_ANYTHING,	       /* unconstrained scalar */
 };
 
 enum special_kfunc_type {
@@ -11318,108 +11401,156 @@ bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta)
 	return meta->func_id == special_kfunc_list[KF_bpf_xdp_pull_data];
 }
 
-static enum kfunc_ptr_arg_type
-get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, struct bpf_func_state *caller,
-		       struct bpf_reg_state *regs, struct bpf_call_arg_meta *meta,
-		       const struct btf_type *t, const struct btf_type *ref_t,
-		       const char *ref_tname, const struct btf_param *args,
-		       int arg, int nargs, argno_t argno, struct bpf_reg_state *reg)
+static int
+get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
+		   const struct btf_param *args, int arg, int nargs, argno_t argno)
 {
+	const struct btf_type *t, *ref_t = NULL;
+	const char *ref_tname = NULL;
 	bool arg_mem_size = false;
+	int arg_type;
 
-	if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||
-	    meta->func_id == special_kfunc_list[KF_bpf_session_is_return] ||
-	    meta->func_id == special_kfunc_list[KF_bpf_session_cookie])
-		return KF_ARG_PTR_TO_CTX;
+	t = btf_type_skip_modifiers(meta->btf, args[arg].type, NULL);
 
-	if (arg + 1 < nargs &&
-	    (is_kfunc_arg_mem_size(meta->btf, &args[arg + 1], get_func_arg_reg(caller, regs, arg + 1)) ||
-	     is_kfunc_arg_const_mem_size(meta->btf, &args[arg + 1], get_func_arg_reg(caller, regs, arg + 1))))
-		arg_mem_size = true;
+	/* Scalar arguments are classified from their BTF suffix/name alone. */
+	if (btf_type_is_scalar(t)) {
+		if (is_kfunc_arg_constant(meta->btf, &args[arg]))
+			return KF_ARG_CONST_BTF_ID;
+		if (is_kfunc_arg_const_mem_size(meta->btf, &args[arg]))
+			return KF_ARG_CONST_MEM_SIZE;
+		if (is_kfunc_arg_mem_size(meta->btf, &args[arg]))
+			return KF_ARG_MEM_SIZE;
+		if (is_kfunc_arg_scalar_with_name(meta->btf, &args[arg], "rdonly_buf_size") ||
+		    is_kfunc_arg_scalar_with_name(meta->btf, &args[arg], "rdwr_buf_size"))
+			return KF_ARG_CONST_ALLOC_SIZE_OR_ZERO;
+		return KF_ARG_ANYTHING;
+	}
+
+	if (!btf_type_is_ptr(t)) {
+		verbose(env, "Unrecognized %s type %s\n",
+			reg_arg_name(env, argno), btf_type_str(t));
+		return -EINVAL;
+	}
+
+	ref_t = btf_type_skip_modifiers(meta->btf, t->type, NULL);
+	ref_tname = btf_name_by_offset(meta->btf, ref_t->name_off);
 
 	/* In this function, we verify the kfunc's BTF as per the argument type,
 	 * leaving the rest of the verification with respect to the register
 	 * type to our caller. When a set of conditions hold in the BTF type of
 	 * arguments, we resolve it to a known kfunc_ptr_arg_type.
 	 */
-	if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), arg))
-		return KF_ARG_PTR_TO_CTX;
-
-	if (is_kfunc_arg_nullable(meta->btf, &args[arg]) && bpf_register_is_null(reg) &&
-	    !arg_mem_size)
-		return KF_ARG_PTR_TO_NULL;
-
-	if (is_kfunc_arg_alloc_obj(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_ALLOC_BTF_ID;
-
-	if (is_kfunc_arg_refcounted_kptr(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_REFCOUNTED_KPTR;
-
-	if (is_kfunc_arg_dynptr(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_DYNPTR;
-
-	if (is_kfunc_arg_iter(meta, arg, &args[arg]))
-		return KF_ARG_PTR_TO_ITER;
-
-	if (is_kfunc_arg_list_head(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_LIST_HEAD;
-
-	if (is_kfunc_arg_list_node(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_LIST_NODE;
-
-	if (is_kfunc_arg_rbtree_root(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_RB_ROOT;
-
-	if (is_kfunc_arg_rbtree_node(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_RB_NODE;
+	if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||
+	    meta->func_id == special_kfunc_list[KF_bpf_session_is_return] ||
+	    meta->func_id == special_kfunc_list[KF_bpf_session_cookie])
+		arg_type = KF_ARG_PTR_TO_CTX;
+	else if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), arg))
+		arg_type = KF_ARG_PTR_TO_CTX;
+	else if (is_kfunc_arg_alloc_obj(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_ALLOC_BTF_ID;
+	else if (is_kfunc_arg_refcounted_kptr(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_REFCOUNTED_KPTR;
+	else if (is_kfunc_arg_dynptr(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_DYNPTR;
+	else if (is_kfunc_arg_iter(meta, arg, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_ITER;
+	else if (is_kfunc_arg_list_head(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_LIST_HEAD;
+	else if (is_kfunc_arg_list_node(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_LIST_NODE;
+	else if (is_kfunc_arg_rbtree_root(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_RB_ROOT;
+	else if (is_kfunc_arg_rbtree_node(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_RB_NODE;
+	else if (is_kfunc_arg_const_str(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_CONST_STR;
+	else if (is_kfunc_arg_const_map(meta->btf, &args[arg]))
+		arg_type = KF_ARG_CONST_MAP_PTR;
+	else if (is_kfunc_arg_map(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_BTF_ID;
+	else if (is_kfunc_arg_wq(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_WORKQUEUE;
+	else if (is_kfunc_arg_timer(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_TIMER;
+	else if (is_kfunc_arg_task_work(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_TASK_WORK;
+	else if (is_kfunc_arg_irq_flag(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_IRQ_FLAG;
+	else if (is_kfunc_arg_res_spin_lock(meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_RES_SPIN_LOCK;
+	else if (is_kfunc_arg_callback(env, meta->btf, &args[arg]))
+		arg_type = KF_ARG_PTR_TO_CALLBACK;
+	else {
+		if (arg + 1 < nargs &&
+		    (is_kfunc_arg_mem_size(meta->btf, &args[arg + 1]) ||
+		     is_kfunc_arg_const_mem_size(meta->btf, &args[arg + 1])))
+			arg_mem_size = true;
+
+		if (btf_type_is_struct(ref_t) && !arg_mem_size) {
+			/* A pointer to a struct without a size argument is classified
+			 * as KF_ARG_PTR_TO_BTF_ID.
+			 */
+			arg_type = KF_ARG_PTR_TO_BTF_ID;
+		} else if (!btf_type_is_scalar(ref_t) &&
+			   !__btf_type_is_scalar_struct(env, meta->btf, ref_t, 0) &&
+			   (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {
+			verbose(env, "%s pointer type %s %s must point to %sscalar, or struct with scalar\n",
+				reg_arg_name(env, argno),
+				btf_type_str(ref_t), ref_tname, arg_mem_size ? "void, " : "");
+			return -EINVAL;
+		} else {
+			/* Otherwise this is a memory buffer supported by
+			 * check_helper_mem_access(): a pointer to a scalar, or to void
+			 * when paired with a size argument. The access size is derived
+			 * from the pointed-to BTF type unless a size argument follows.
+			 */
+			arg_type = arg_mem_size ? KF_ARG_PTR_TO_MEM : KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
+		}
+	}
 
-	if (is_kfunc_arg_const_str(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_CONST_STR;
+	if (is_kfunc_arg_nullable(meta->btf, &args[arg]))
+		arg_type |= PTR_MAYBE_NULL;
 
-	if (is_kfunc_arg_map(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_MAP;
+	return arg_type;
+}
 
-	if (is_kfunc_arg_wq(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_WORKQUEUE;
+static int gen_kfunc_arg_proto(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
+			       struct bpf_func_proto *proto)
+{
+	const struct btf *btf = meta->btf;
+	const struct btf_param *args;
+	u32 i, nargs;
+	int arg_type;
 
-	if (is_kfunc_arg_timer(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_TIMER;
+	args = (const struct btf_param *)(meta->func_proto + 1);
+	nargs = btf_type_vlen(meta->func_proto);
+	if (nargs > MAX_BPF_FUNC_ARGS) {
+		verbose(env, "Function %s has %d > %d args\n", meta->func_name,
+			nargs, MAX_BPF_FUNC_ARGS);
+		return -EINVAL;
+	}
+	if (nargs > MAX_BPF_FUNC_REG_ARGS && !bpf_jit_supports_stack_args()) {
+		verbose(env, "JIT does not support kfunc %s() with %d args\n",
+			meta->func_name, nargs);
+		return -ENOTSUPP;
+	}
 
-	if (is_kfunc_arg_task_work(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_TASK_WORK;
+	for (i = 0; i < nargs; i++) {
+		argno_t argno = argno_from_arg(i + 1);
 
-	if (is_kfunc_arg_irq_flag(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_IRQ_FLAG;
+		if (is_kfunc_arg_prog_aux(btf, &args[i]) ||
+		    is_kfunc_arg_ignore(btf, &args[i]) ||
+		    is_kfunc_arg_implicit(meta, i))
+			continue;
 
-	if (is_kfunc_arg_res_spin_lock(meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_RES_SPIN_LOCK;
+		arg_type = get_kfunc_arg_type(env, meta, args, i, nargs, argno);
+		if (arg_type < 0)
+			return arg_type;
 
-	if ((base_type(reg->type) == PTR_TO_BTF_ID || reg2btf_ids[base_type(reg->type)])) {
-		if (!btf_type_is_struct(ref_t)) {
-			verbose(env, "kernel function %s %s pointer type %s %s is not supported\n",
-				meta->func_name, reg_arg_name(env, argno),
-				btf_type_str(ref_t), ref_tname);
-			return -EINVAL;
-		}
-		return KF_ARG_PTR_TO_BTF_ID;
+		proto->arg_type[i] = arg_type;
 	}
 
-	if (is_kfunc_arg_callback(env, meta->btf, &args[arg]))
-		return KF_ARG_PTR_TO_CALLBACK;
-
-	/* This is the catch all argument type of register types supported by
-	 * check_helper_mem_access. However, we only allow when argument type is
-	 * pointer to scalar, or struct composed (recursively) of scalars. When
-	 * arg_mem_size is true, the pointer can be void *.
-	 */
-	if (!btf_type_is_scalar(ref_t) && !__btf_type_is_scalar_struct(env, meta->btf, ref_t, 0) &&
-	    (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {
-		verbose(env, "%s pointer type %s %s must point to %sscalar, or struct with scalar\n",
-			reg_arg_name(env, argno),
-			btf_type_str(ref_t), ref_tname, arg_mem_size ? "void, " : "");
-		return -EINVAL;
-	}
-	return arg_mem_size ? KF_ARG_PTR_TO_MEM_SIZE : KF_ARG_PTR_TO_MEM;
+	return 0;
 }
 
 static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
@@ -12005,16 +12136,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 
 	args = (const struct btf_param *)(meta->func_proto + 1);
 	nargs = btf_type_vlen(meta->func_proto);
-	if (nargs > MAX_BPF_FUNC_ARGS) {
-		verbose(env, "Function %s has %d > %d args\n", func_name, nargs,
-			MAX_BPF_FUNC_ARGS);
-		return -EINVAL;
-	}
-	if (nargs > MAX_BPF_FUNC_REG_ARGS && !bpf_jit_supports_stack_args()) {
-		verbose(env, "JIT does not support kfunc %s() with %d args\n",
-			func_name, nargs);
-		return -ENOTSUPP;
-	}
 
 	ret = check_outgoing_stack_args(env, caller, nargs);
 	if (ret)
@@ -12031,8 +12152,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 		int regno = reg_from_argno(argno);
 		bool btf_id_fixed_off_ok = true;
 		u32 ref_id, type_size;
-		bool is_ret_buf_sz = false;
-		int kf_arg_type;
+		int kf_arg_type = meta->fn->arg_type[i];
 
 		if (is_kfunc_arg_prog_aux(btf, &args[i])) {
 			/* Reject repeated use bpf_prog_aux */
@@ -12055,52 +12175,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 
 		t = btf_type_skip_modifiers(btf, args[i].type, NULL);
 
-		if (btf_type_is_scalar(t)) {
-			if (reg->type != SCALAR_VALUE) {
-				verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
-				return -EINVAL;
-			}
-
-			if (is_kfunc_arg_constant(meta->btf, &args[i])) {
-				if (meta->arg_constant.found) {
-					verifier_bug(env, "only one constant argument permitted");
-					return -EFAULT;
-				}
-				if (!tnum_is_const(reg->var_off)) {
-					verbose(env, "%s must be a known constant\n",
-						reg_arg_name(env, argno));
-					return -EINVAL;
-				}
-				if (regno >= 0)
-					ret = mark_chain_precision(env, regno);
-				else
-					ret = mark_stack_arg_precision(env, i);
-				if (ret < 0)
-					return ret;
-				meta->arg_constant.found = true;
-				meta->arg_constant.value = reg->var_off.value;
-			} else if (is_kfunc_arg_scalar_with_name(btf, &args[i], "rdonly_buf_size")) {
-				meta->r0_rdonly = true;
-				is_ret_buf_sz = true;
-			} else if (is_kfunc_arg_scalar_with_name(btf, &args[i], "rdwr_buf_size")) {
-				is_ret_buf_sz = true;
-			}
-
-			if (is_ret_buf_sz) {
-				ret = process_const_alloc_mem_size(env, reg, argno, &meta->ret_mem);
-				if (ret < 0)
-					return ret;
-			}
-			continue;
-		}
-
-		if (!btf_type_is_ptr(t)) {
-			verbose(env, "Unrecognized %s type %s\n",
-				reg_arg_name(env, argno), btf_type_str(t));
-			return -EINVAL;
-		}
-
-		if ((bpf_register_is_null(reg) || type_may_be_null(reg->type)) &&
+		if (btf_type_is_ptr(t) && (bpf_register_is_null(reg) || type_may_be_null(reg->type)) &&
 		    !is_kfunc_arg_nullable(meta->btf, &args[i])) {
 			verbose(env, "Possibly NULL pointer passed to trusted %s\n",
 				reg_arg_name(env, argno));
@@ -12117,76 +12192,35 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 		if (reg_is_referenced(env, reg))
 			update_ref_obj(&meta->ref_obj, reg);
 
-		ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
-		ref_tname = btf_name_by_offset(btf, ref_t->name_off);
-
-		kf_arg_type = get_kfunc_ptr_arg_type(env, caller, regs, meta, t, ref_t, ref_tname,
-						     args, i, nargs, argno, reg);
-		if (kf_arg_type < 0)
-			return kf_arg_type;
+		if (btf_type_is_ptr(t)) {
+			ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
+			ref_tname = btf_name_by_offset(btf, ref_t->name_off);
+		}
 
-		switch (kf_arg_type) {
-		case KF_ARG_PTR_TO_NULL:
+		if (bpf_register_is_null(reg) && type_may_be_null(kf_arg_type))
 			continue;
-		case KF_ARG_PTR_TO_MAP:
-			if (!reg->map_ptr) {
-				verbose(env, "pointer in %s isn't map pointer\n",
-					reg_arg_name(env, argno));
-				return -EINVAL;
-			}
-			if (meta->map.ptr && (reg->map_ptr->record->wq_off >= 0 ||
-					      reg->map_ptr->record->task_work_off >= 0)) {
-				/* Use map_uid (which is unique id of inner map) to reject:
-				 * inner_map1 = bpf_map_lookup_elem(outer_map, key1)
-				 * inner_map2 = bpf_map_lookup_elem(outer_map, key2)
-				 * if (inner_map1 && inner_map2) {
-				 *     wq = bpf_map_lookup_elem(inner_map1);
-				 *     if (wq)
-				 *         // mismatch would have been allowed
-				 *         bpf_wq_init(wq, inner_map2);
-				 * }
-				 *
-				 * Comparing map_ptr is enough to distinguish normal and outer maps.
-				 */
-				if (meta->map.ptr != reg->map_ptr ||
-				    meta->map.uid != reg->map_uid) {
-					if (reg->map_ptr->record->task_work_off >= 0) {
-						verbose(env,
-							"bpf_task_work pointer in R2 map_uid=%d doesn't match map pointer in R3 map_uid=%d\n",
-							meta->map.uid, reg->map_uid);
-						return -EINVAL;
-					}
-					verbose(env,
-						"workqueue pointer in R1 map_uid=%d doesn't match map pointer in R2 map_uid=%d\n",
-						meta->map.uid, reg->map_uid);
-					return -EINVAL;
-				}
-			}
-			meta->map.ptr = reg->map_ptr;
-			meta->map.uid = reg->map_uid;
-			fallthrough;
+
+		if (is_kfunc_arg_map(btf, &args[i])) {
+			ref_id = *reg2btf_ids[CONST_PTR_TO_MAP];
+			ref_t = btf_type_by_id(btf_vmlinux, ref_id);
+			ref_tname = btf_name_by_offset(btf, ref_t->name_off);
+		}
+
+		switch (base_type(kf_arg_type)) {
+		case KF_ARG_CONST_BTF_ID:
+		case KF_ARG_CONST_ALLOC_SIZE_OR_ZERO:
+		case KF_ARG_ANYTHING:
 		case KF_ARG_PTR_TO_ALLOC_BTF_ID:
 		case KF_ARG_PTR_TO_BTF_ID:
-			if (!is_trusted_reg(env, reg)) {
-				if (!is_kfunc_rcu(meta)) {
-					verbose(env, "%s must be referenced or trusted\n",
-						reg_arg_name(env, argno));
-					return -EINVAL;
-				}
-				if (!is_rcu_reg(reg)) {
-					verbose(env, "%s must be a rcu pointer\n",
-						reg_arg_name(env, argno));
-					return -EINVAL;
-				}
-			}
-			fallthrough;
+		case KF_ARG_CONST_MAP_PTR:
 		case KF_ARG_PTR_TO_ITER:
 		case KF_ARG_PTR_TO_LIST_HEAD:
 		case KF_ARG_PTR_TO_LIST_NODE:
 		case KF_ARG_PTR_TO_RB_ROOT:
 		case KF_ARG_PTR_TO_RB_NODE:
 		case KF_ARG_PTR_TO_MEM:
-		case KF_ARG_PTR_TO_MEM_SIZE:
+		case KF_ARG_CONST_MEM_SIZE:
+		case KF_ARG_MEM_SIZE:
 		case KF_ARG_PTR_TO_CALLBACK:
 		case KF_ARG_PTR_TO_CONST_STR:
 		case KF_ARG_PTR_TO_WORKQUEUE:
@@ -12217,7 +12251,35 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 		if (ret < 0)
 			return ret;
 
-		switch (kf_arg_type) {
+		switch (base_type(kf_arg_type)) {
+		case KF_ARG_CONST_BTF_ID:
+			if (reg->type != SCALAR_VALUE) {
+				verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
+				return -EINVAL;
+			}
+
+			ret = process_const_arg(env, reg, argno, meta);
+			if (ret < 0)
+				return ret;
+			break;
+		case KF_ARG_CONST_ALLOC_SIZE_OR_ZERO:
+			if (reg->type != SCALAR_VALUE) {
+				verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
+				return -EINVAL;
+			}
+
+			if (is_kfunc_arg_scalar_with_name(btf, &args[i], "rdonly_buf_size"))
+				meta->r0_rdonly = true;
+			ret = process_const_alloc_mem_size(env, reg, argno, &meta->ret_mem);
+			if (ret < 0)
+				return ret;
+			break;
+		case KF_ARG_ANYTHING:
+			if (reg->type != SCALAR_VALUE) {
+				verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
+				return -EINVAL;
+			}
+			break;
 		case KF_ARG_PTR_TO_CTX:
 			if (reg->type != PTR_TO_CTX) {
 				verbose(env, "%s expected pointer to ctx, but got %s\n",
@@ -12386,51 +12448,77 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 			if (ret < 0)
 				return ret;
 			break;
-		case KF_ARG_PTR_TO_MAP:
-			/* If argument has '__map' suffix expect 'struct bpf_map *' */
-			ref_id = *reg2btf_ids[CONST_PTR_TO_MAP];
-			ref_t = btf_type_by_id(btf_vmlinux, ref_id);
-			ref_tname = btf_name_by_offset(btf, ref_t->name_off);
-			fallthrough;
-		case KF_ARG_PTR_TO_BTF_ID:
-			/* Only base_type is checked, further checks are done here */
-			if ((base_type(reg->type) != PTR_TO_BTF_ID ||
-			     (bpf_type_has_unsafe_modifiers(reg->type) && !is_rcu_reg(reg))) &&
-			    !reg2btf_ids[base_type(reg->type)]) {
-				verbose(env, "%s is %s ", reg_arg_name(env, argno),
-					reg_type_str(env, reg->type));
-				verbose(env, "expected %s or socket\n",
-					reg_type_str(env, base_type(reg->type) |
-							  (type_flag(reg->type) & BPF_REG_TRUSTED_MODIFIERS)));
+		case KF_ARG_CONST_MAP_PTR:
+			if (!reg->map_ptr) {
+				verbose(env, "pointer in %s isn't map pointer\n",
+					reg_arg_name(env, argno));
 				return -EINVAL;
 			}
-			ret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i, argno);
+			ret = process_map_ptr_arg(env, reg, argno, meta);
 			if (ret < 0)
 				return ret;
 			break;
-		case KF_ARG_PTR_TO_MEM:
-			resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
-			if (IS_ERR(resolve_ret)) {
-				verbose(env, "%s reference type('%s %s') size cannot be determined: %ld\n",
-					reg_arg_name(env, argno), btf_type_str(ref_t),
-					ref_tname, PTR_ERR(resolve_ret));
+		case KF_ARG_PTR_TO_BTF_ID:
+			/* Only base_type is checked, further checks are done here */
+			if (base_type(reg->type) == PTR_TO_BTF_ID ||
+			    reg2btf_ids[base_type(reg->type)]) {
+
+				if (!is_trusted_reg(env, reg)) {
+					if (!is_kfunc_rcu(meta)) {
+						verbose(env, "%s must be referenced or trusted\n",
+							reg_arg_name(env, argno));
+						return -EINVAL;
+					}
+					if (!is_rcu_reg(reg)) {
+						verbose(env, "%s must be a rcu pointer\n",
+							reg_arg_name(env, argno));
+						return -EINVAL;
+					}
+				}
+
+				ret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i, argno);
+				if (ret < 0)
+					return ret;
+				break;
+			}
+
+			if (!__btf_type_is_scalar_struct(env, meta->btf, ref_t, 0)) {
+				enum bpf_reg_type reg2btf_type = lookup_reg2btf_ids(ref_t);
+
+				verbose(env, "%s is %s expected %s %s",
+					reg_arg_name(env, argno), reg_type_str(env, reg->type),
+					btf_type_str(ref_t), ref_tname);
+				if (reg2btf_type != NOT_INIT)
+					verbose(env, " or %s", reg_type_str(env, reg2btf_type));
+				verbose(env, "\n");
 				return -EINVAL;
 			}
-			ret = check_mem_reg(env, reg, argno, type_size);
-			if (ret < 0)
-				return ret;
-			break;
-		case KF_ARG_PTR_TO_MEM_SIZE:
-		{
-			struct bpf_reg_state *buff_reg = reg;
-			const struct btf_param *buff_arg = &args[i];
-			struct bpf_reg_state *size_reg = get_func_arg_reg(caller, regs, i + 1);
-			const struct btf_param *size_arg = &args[i + 1];
-			argno_t next_argno = argno_from_arg(i + 2);
-
-			if (!bpf_register_is_null(buff_reg) || !is_kfunc_arg_nullable(meta->btf, buff_arg)) {
-				ret = check_kfunc_mem_size_reg(env, buff_reg, size_reg,
-							       argno, next_argno);
+
+			/*
+			 * If the register does not contain btf id but the argument type is a pointer to
+			 * scalar-only struct, allow verifying it as a fixed size memory.
+			 */
+			kf_arg_type = KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
+			fallthrough;
+		case KF_ARG_PTR_TO_MEM:
+			if (kf_arg_type & MEM_FIXED_SIZE) {
+				resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
+				if (IS_ERR(resolve_ret)) {
+					verbose(env, "%s reference type('%s %s') size cannot be determined: %ld\n",
+						reg_arg_name(env, argno), btf_type_str(ref_t),
+						ref_tname, PTR_ERR(resolve_ret));
+					return -EINVAL;
+				}
+				ret = check_mem_reg(env, reg, argno, type_size, BPF_READ | BPF_WRITE, meta);
+				if (ret < 0)
+					return ret;
+			} else {
+				struct bpf_reg_state *buff_reg = reg;
+				struct bpf_reg_state *size_reg = get_func_arg_reg(caller, regs, i + 1);
+				argno_t next_argno = argno_from_arg(i + 2);
+
+				ret = check_mem_size_reg(env, buff_reg, size_reg, argno, next_argno,
+							 BPF_READ | BPF_WRITE, true, meta);
 				if (ret < 0) {
 					verbose(env, "%s and ", reg_arg_name(env, argno));
 					verbose(env, "%s memory, len pair leads to invalid memory access\n",
@@ -12438,25 +12526,20 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 					return ret;
 				}
 			}
-
-			if (is_kfunc_arg_const_mem_size(meta->btf, size_arg, size_reg)) {
-				if (meta->arg_constant.found) {
-					verifier_bug(env, "only one constant argument permitted");
-					return -EFAULT;
-				}
-				if (!tnum_is_const(size_reg->var_off)) {
-					verbose(env, "%s must be a known constant\n",
-						reg_arg_name(env, next_argno));
-					return -EINVAL;
-				}
-				meta->arg_constant.found = true;
-				meta->arg_constant.value = size_reg->var_off.value;
+			break;
+		case KF_ARG_CONST_MEM_SIZE:
+			if (reg->type != SCALAR_VALUE) {
+				verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
+				return -EINVAL;
 			}
 
-			/* Skip next '__sz' or '__szk' argument */
-			i++;
+			ret = process_const_arg(env, reg, argno, meta);
+			if (ret < 0)
+				return ret;
+
+			fallthrough;
+		case KF_ARG_MEM_SIZE:
 			break;
-		}
 		case KF_ARG_PTR_TO_CALLBACK:
 			if (reg->type != PTR_TO_FUNC) {
 				verbose(env, "%s expected pointer to func\n", reg_arg_name(env, argno));
@@ -12514,7 +12597,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 					reg_arg_name(env, argno));
 				return -EINVAL;
 			}
-			ret = process_timer_kfunc(env, reg, argno, meta);
+			ret = process_timer_func(env, reg, argno, &meta->map);
 			if (ret < 0)
 				return ret;
 			break;
@@ -12676,7 +12759,7 @@ s64 bpf_helper_stack_access_bytes(struct bpf_verifier_env *env, struct bpf_insn
 			size = fn->arg_size[arg];
 			goto out;
 		}
-		if (arg + 1 < ARRAY_SIZE(fn->arg_type) &&
+		if (arg + 1 < MAX_BPF_FUNC_REG_ARGS &&
 		    arg_type_is_mem_size(fn->arg_type[arg + 1])) {
 			int size_reg = BPF_REG_1 + arg + 1;
 
@@ -12975,6 +13058,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 	int err, insn_idx = *insn_idx_p;
 	const struct btf_param *args;
 	u32 i, nargs, ptr_type_id;
+	struct bpf_kfunc_desc *desc;
 	struct btf *desc_btf;
 	int id;
 
@@ -12991,6 +13075,13 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 	func_name = meta.func_name;
 	insn_aux = &env->insn_aux_data[insn_idx];
 
+	desc = find_kfunc_desc(env->prog, insn->imm, insn->off);
+	if (!desc) {
+		verifier_bug(env, "kfunc descriptor not found for func_id %u", insn->imm);
+		return -EFAULT;
+	}
+	meta.fn = desc->proto;
+
 	insn_aux->is_iter_next = bpf_is_iter_next_kfunc(&meta);
 
 	if (!insn->off &&
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 76ab51deaa6b95..891897f8a1b357 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -221,7 +221,7 @@ const struct bpf_func_proto bpf_probe_read_user_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 };
 
@@ -258,7 +258,7 @@ const struct bpf_func_proto bpf_probe_read_user_str_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 };
 
@@ -273,7 +273,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 };
 
@@ -308,7 +308,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_str_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 };
 
@@ -328,7 +328,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 };
 
@@ -347,7 +347,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_str_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_ANYTHING,
 };
 #endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
@@ -383,7 +383,7 @@ static const struct bpf_func_proto bpf_probe_write_user_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_ANYTHING,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 };
 
 #define MAX_TRACE_PRINTK_VARARGS	3
@@ -418,7 +418,7 @@ static const struct bpf_func_proto bpf_trace_printk_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg2_type	= ARG_CONST_SIZE,
+	.arg2_type	= ARG_MEM_SIZE,
 };
 
 static void __set_printk_clr_event(struct work_struct *work)
@@ -474,9 +474,9 @@ static const struct bpf_func_proto bpf_trace_vprintk_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg2_type	= ARG_CONST_SIZE,
+	.arg2_type	= ARG_MEM_SIZE,
 	.arg3_type	= ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg4_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 const struct bpf_func_proto *bpf_get_trace_vprintk_proto(void)
@@ -518,9 +518,9 @@ static const struct bpf_func_proto bpf_seq_printf_proto = {
 	.arg1_type	= ARG_PTR_TO_BTF_ID,
 	.arg1_btf_id	= &btf_seq_file_ids[0],
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.arg4_type      = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
-	.arg5_type      = ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type      = ARG_MEM_SIZE_OR_ZERO,
 };
 
 BPF_CALL_3(bpf_seq_write, struct seq_file *, m, const void *, data, u32, len)
@@ -535,7 +535,7 @@ static const struct bpf_func_proto bpf_seq_write_proto = {
 	.arg1_type	= ARG_PTR_TO_BTF_ID,
 	.arg1_btf_id	= &btf_seq_file_ids[0],
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 BPF_CALL_4(bpf_seq_printf_btf, struct seq_file *, m, struct btf_ptr *, ptr,
@@ -559,7 +559,7 @@ static const struct bpf_func_proto bpf_seq_printf_btf_proto = {
 	.arg1_type	= ARG_PTR_TO_BTF_ID,
 	.arg1_btf_id	= &btf_seq_file_ids[0],
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -633,7 +633,7 @@ static const struct bpf_func_proto bpf_perf_event_read_value_proto = {
 	.arg1_type	= ARG_CONST_MAP_PTR,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 };
 
 const struct bpf_func_proto *bpf_get_perf_event_read_value_proto(void)
@@ -730,7 +730,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto = {
 	.arg2_type	= ARG_CONST_MAP_PTR,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 static DEFINE_PER_CPU(int, bpf_event_output_nest_level);
@@ -996,7 +996,7 @@ static const struct bpf_func_proto bpf_d_path_proto = {
 	.arg1_type	= ARG_PTR_TO_BTF_ID,
 	.arg1_btf_id	= &bpf_d_path_btf_ids[0],
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_WRITE,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.allowed	= bpf_d_path_allowed,
 };
 
@@ -1053,9 +1053,9 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = {
 	.gpl_only	= false,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM | MEM_WRITE,
-	.arg2_type	= ARG_CONST_SIZE,
+	.arg2_type	= ARG_MEM_SIZE,
 	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 	.arg5_type	= ARG_ANYTHING,
 };
 
@@ -1218,7 +1218,7 @@ const struct bpf_func_proto bpf_get_branch_snapshot_proto = {
 	.gpl_only	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 BPF_CALL_3(get_func_arg, void *, ctx, u32, n, u64 *, value)
@@ -1421,7 +1421,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_tp = {
 	.arg2_type	= ARG_CONST_MAP_PTR,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 BPF_CALL_3(bpf_get_stackid_tp, void *, tp_buff, struct bpf_map *, map,
@@ -1462,7 +1462,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_tp = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -1524,12 +1524,12 @@ BPF_CALL_3(bpf_perf_prog_read_value, struct bpf_perf_event_data_kern *, ctx,
 }
 
 static const struct bpf_func_proto bpf_perf_prog_read_value_proto = {
-         .func           = bpf_perf_prog_read_value,
-         .gpl_only       = true,
-         .ret_type       = RET_INTEGER,
-         .arg1_type      = ARG_PTR_TO_CTX,
-         .arg2_type      = ARG_PTR_TO_UNINIT_MEM,
-         .arg3_type      = ARG_CONST_SIZE,
+	.func           = bpf_perf_prog_read_value,
+	.gpl_only       = true,
+	.ret_type       = RET_INTEGER,
+	.arg1_type      = ARG_PTR_TO_CTX,
+	.arg2_type      = ARG_PTR_TO_UNINIT_MEM,
+	.arg3_type      = ARG_MEM_SIZE,
 };
 
 BPF_CALL_4(bpf_read_branch_records, struct bpf_perf_event_data_kern *, ctx,
@@ -1566,7 +1566,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = {
 	.ret_type       = RET_INTEGER,
 	.arg1_type      = ARG_PTR_TO_CTX,
 	.arg2_type      = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE,
-	.arg3_type      = ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type      = ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type      = ARG_ANYTHING,
 };
 
@@ -1646,7 +1646,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_raw_tp = {
 	.arg2_type	= ARG_CONST_MAP_PTR,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 extern const struct bpf_func_proto bpf_skb_output_proto;
@@ -1701,7 +1701,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
diff --git a/net/core/filter.c b/net/core/filter.c
index 0b7afdd0ae4748..eb0b706af4b296 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1747,7 +1747,7 @@ static const struct bpf_func_proto bpf_skb_store_bytes_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 	.arg5_type	= ARG_ANYTHING,
 };
 
@@ -1784,7 +1784,7 @@ static const struct bpf_func_proto bpf_skb_load_bytes_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 };
 
 int __bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len)
@@ -1823,7 +1823,7 @@ static const struct bpf_func_proto bpf_flow_dissector_load_bytes_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_skb_load_bytes_relative, const struct sk_buff *, skb,
@@ -1867,7 +1867,7 @@ static const struct bpf_func_proto bpf_skb_load_bytes_relative_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 	.arg5_type	= ARG_ANYTHING,
 };
 
@@ -2063,9 +2063,9 @@ static const struct bpf_func_proto bpf_csum_diff_proto = {
 	.pkt_access	= true,
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
-	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg2_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg3_type	= ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg4_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg5_type	= ARG_ANYTHING,
 };
 
@@ -2621,7 +2621,7 @@ static const struct bpf_func_proto bpf_redirect_neigh_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_ANYTHING,
 	.arg2_type      = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
-	.arg3_type      = ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type      = ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -4194,7 +4194,7 @@ static const struct bpf_func_proto bpf_xdp_load_bytes_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 };
 
 int __bpf_xdp_load_bytes(struct xdp_buff *xdp, u32 offset, void *buf, u32 len)
@@ -4226,7 +4226,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 };
 
 int __bpf_xdp_store_bytes(struct xdp_buff *xdp, u32 offset, void *buf, u32 len)
@@ -4789,7 +4789,7 @@ static const struct bpf_func_proto bpf_skb_event_output_proto = {
 	.arg2_type	= ARG_CONST_MAP_PTR,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 BTF_ID_LIST_SINGLE(bpf_skb_output_btf_ids, struct, sk_buff)
@@ -4803,7 +4803,7 @@ const struct bpf_func_proto bpf_skb_output_proto = {
 	.arg2_type	= ARG_CONST_MAP_PTR,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 static unsigned short bpf_tunnel_key_af(u64 flags)
@@ -4886,7 +4886,7 @@ static const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -4921,7 +4921,7 @@ static const struct bpf_func_proto bpf_skb_get_tunnel_opt_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 };
 
 static struct metadata_dst __percpu *md_dst;
@@ -5003,7 +5003,7 @@ static const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -5031,7 +5031,7 @@ static const struct bpf_func_proto bpf_skb_set_tunnel_opt_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 };
 
 static const struct bpf_func_proto *
@@ -5203,7 +5203,7 @@ static const struct bpf_func_proto bpf_xdp_event_output_proto = {
 	.arg2_type	= ARG_CONST_MAP_PTR,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 BTF_ID_LIST_SINGLE(bpf_xdp_output_btf_ids, struct, xdp_buff)
@@ -5217,7 +5217,7 @@ const struct bpf_func_proto bpf_xdp_output_proto = {
 	.arg2_type	= ARG_CONST_MAP_PTR,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg5_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 BPF_CALL_1(bpf_get_socket_cookie, struct sk_buff *, skb)
@@ -5764,7 +5764,7 @@ const struct bpf_func_proto bpf_sk_setsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_sk_getsockopt, struct sock *, sk, int, level,
@@ -5781,7 +5781,7 @@ const struct bpf_func_proto bpf_sk_getsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_sk_setsockopt_nodelay, struct sock *, sk, int, level,
@@ -5805,7 +5805,7 @@ const struct bpf_func_proto bpf_sk_setsockopt_nodelay_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_unlocked_sk_setsockopt, struct sock *, sk, int, level,
@@ -5822,7 +5822,7 @@ const struct bpf_func_proto bpf_unlocked_sk_setsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_unlocked_sk_getsockopt, struct sock *, sk, int, level,
@@ -5839,7 +5839,7 @@ const struct bpf_func_proto bpf_unlocked_sk_getsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_sock_addr_setsockopt, struct bpf_sock_addr_kern *, ctx,
@@ -5856,7 +5856,7 @@ static const struct bpf_func_proto bpf_sock_addr_setsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_sock_addr_getsockopt, struct bpf_sock_addr_kern *, ctx,
@@ -5873,7 +5873,7 @@ static const struct bpf_func_proto bpf_sock_addr_getsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 static int sk_bpf_set_get_bypass_prot_mem(struct sock *sk,
@@ -5918,7 +5918,7 @@ static const struct bpf_func_proto bpf_sock_create_setsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_sock_create_getsockopt, struct sock *, sk, int, level,
@@ -5944,7 +5944,7 @@ static const struct bpf_func_proto bpf_sock_create_getsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_sock_ops_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
@@ -5970,7 +5970,7 @@ static const struct bpf_func_proto bpf_sock_ops_setsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 static int bpf_sock_ops_get_syn(struct bpf_sock_ops_kern *bpf_sock,
@@ -6080,7 +6080,7 @@ static const struct bpf_func_proto bpf_sock_ops_getsockopt_proto = {
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_2(bpf_sock_ops_cb_flags_set, struct bpf_sock_ops_kern *, bpf_sock,
@@ -6147,7 +6147,7 @@ static const struct bpf_func_proto bpf_bind_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 };
 
 #ifdef CONFIG_XFRM
@@ -6200,7 +6200,7 @@ static const struct bpf_func_proto bpf_skb_get_xfrm_state_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 	.arg5_type	= ARG_ANYTHING,
 };
 #endif
@@ -6607,7 +6607,7 @@ static const struct bpf_func_proto bpf_xdp_fib_lookup_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type      = ARG_PTR_TO_CTX,
 	.arg2_type      = ARG_PTR_TO_MEM | MEM_WRITE,
-	.arg3_type      = ARG_CONST_SIZE,
+	.arg3_type      = ARG_MEM_SIZE,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -6667,7 +6667,7 @@ static const struct bpf_func_proto bpf_skb_fib_lookup_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type      = ARG_PTR_TO_CTX,
 	.arg2_type      = ARG_PTR_TO_MEM | MEM_WRITE,
-	.arg3_type      = ARG_CONST_SIZE,
+	.arg3_type      = ARG_MEM_SIZE,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -6865,7 +6865,7 @@ static const struct bpf_func_proto bpf_lwt_in_push_encap_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE
+	.arg4_type	= ARG_MEM_SIZE
 };
 
 static const struct bpf_func_proto bpf_lwt_xmit_push_encap_proto = {
@@ -6875,7 +6875,7 @@ static const struct bpf_func_proto bpf_lwt_xmit_push_encap_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE
+	.arg4_type	= ARG_MEM_SIZE
 };
 
 #if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)
@@ -6919,7 +6919,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_store_bytes_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE
+	.arg4_type	= ARG_MEM_SIZE
 };
 
 static void bpf_update_srh_state(struct sk_buff *skb)
@@ -7008,7 +7008,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_action_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg4_type	= ARG_CONST_SIZE
+	.arg4_type	= ARG_MEM_SIZE
 };
 
 BPF_CALL_3(bpf_lwt_seg6_adjust_srh, struct sk_buff *, skb, u32, offset,
@@ -7249,7 +7249,7 @@ static const struct bpf_func_proto bpf_skc_lookup_tcp_proto = {
 	.ret_type	= RET_PTR_TO_SOCK_COMMON_OR_NULL,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
 };
@@ -7268,7 +7268,7 @@ static const struct bpf_func_proto bpf_sk_lookup_tcp_proto = {
 	.ret_type	= RET_PTR_TO_SOCKET_OR_NULL,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
 };
@@ -7287,7 +7287,7 @@ static const struct bpf_func_proto bpf_sk_lookup_udp_proto = {
 	.ret_type	= RET_PTR_TO_SOCKET_OR_NULL,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
 };
@@ -7311,7 +7311,7 @@ static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = {
 	.ret_type	= RET_PTR_TO_SOCK_COMMON_OR_NULL,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
 };
@@ -7335,7 +7335,7 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = {
 	.ret_type	= RET_PTR_TO_SOCKET_OR_NULL,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
 };
@@ -7359,7 +7359,7 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_udp_proto = {
 	.ret_type	= RET_PTR_TO_SOCKET_OR_NULL,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
 };
@@ -7397,7 +7397,7 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_udp_proto = {
 	.ret_type       = RET_PTR_TO_SOCKET_OR_NULL,
 	.arg1_type      = ARG_PTR_TO_CTX,
 	.arg2_type      = ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type      = ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type      = ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type      = ARG_ANYTHING,
 	.arg5_type      = ARG_ANYTHING,
 };
@@ -7421,7 +7421,7 @@ static const struct bpf_func_proto bpf_xdp_skc_lookup_tcp_proto = {
 	.ret_type       = RET_PTR_TO_SOCK_COMMON_OR_NULL,
 	.arg1_type      = ARG_PTR_TO_CTX,
 	.arg2_type      = ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type      = ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type      = ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type      = ARG_ANYTHING,
 	.arg5_type      = ARG_ANYTHING,
 };
@@ -7445,7 +7445,7 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_tcp_proto = {
 	.ret_type       = RET_PTR_TO_SOCKET_OR_NULL,
 	.arg1_type      = ARG_PTR_TO_CTX,
 	.arg2_type      = ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type      = ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type      = ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type      = ARG_ANYTHING,
 	.arg5_type      = ARG_ANYTHING,
 };
@@ -7465,7 +7465,7 @@ static const struct bpf_func_proto bpf_sock_addr_skc_lookup_tcp_proto = {
 	.ret_type	= RET_PTR_TO_SOCK_COMMON_OR_NULL,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
 };
@@ -7484,7 +7484,7 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_tcp_proto = {
 	.ret_type	= RET_PTR_TO_SOCKET_OR_NULL,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
 };
@@ -7503,7 +7503,7 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_udp_proto = {
 	.ret_type	= RET_PTR_TO_SOCKET_OR_NULL,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 	.arg4_type	= ARG_ANYTHING,
 	.arg5_type	= ARG_ANYTHING,
 };
@@ -7823,9 +7823,9 @@ static const struct bpf_func_proto bpf_tcp_check_syncookie_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_BTF_ID_SOCK_COMMON,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,
@@ -7892,9 +7892,9 @@ static const struct bpf_func_proto bpf_tcp_gen_syncookie_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_BTF_ID_SOCK_COMMON,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.arg4_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg5_type	= ARG_CONST_SIZE,
+	.arg5_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_3(bpf_sk_assign, struct sk_buff *, skb, struct sock *, sk, u64, flags)
@@ -8048,7 +8048,7 @@ static const struct bpf_func_proto bpf_sock_ops_load_hdr_opt_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_WRITE,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -8126,7 +8126,7 @@ static const struct bpf_func_proto bpf_sock_ops_store_hdr_opt_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE,
+	.arg3_type	= ARG_MEM_SIZE,
 	.arg4_type	= ARG_ANYTHING,
 };
 
@@ -8221,7 +8221,7 @@ static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv4_proto = {
 	.arg1_type	= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY,
 	.arg1_size	= sizeof(struct iphdr),
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv6, struct ipv6hdr *, iph,
@@ -8253,7 +8253,7 @@ static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv6_proto = {
 	.arg1_type	= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY,
 	.arg1_size	= sizeof(struct ipv6hdr),
 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
-	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
+	.arg3_type	= ARG_MEM_SIZE_OR_ZERO,
 };
 
 BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv4, struct iphdr *, iph,
@@ -11726,7 +11726,7 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 };
 
 BPF_CALL_5(sk_reuseport_load_bytes_relative,
@@ -11744,7 +11744,7 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_relative_proto = {
 	.arg1_type	= ARG_PTR_TO_CTX,
 	.arg2_type	= ARG_ANYTHING,
 	.arg3_type	= ARG_PTR_TO_UNINIT_MEM,
-	.arg4_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_MEM_SIZE,
 	.arg5_type	= ARG_ANYTHING,
 };
 
diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index be97f6887f0e7f..a81faa709dd5bb 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -67,6 +67,7 @@
 #include "verifier_masking.skel.h"
 #include "verifier_may_goto_1.skel.h"
 #include "verifier_may_goto_2.skel.h"
+#include "verifier_mem_size_reg.skel.h"
 #include "verifier_meta_access.skel.h"
 #include "verifier_movsx.skel.h"
 #include "verifier_mtu.skel.h"
@@ -221,6 +222,7 @@ void test_verifier_map_ret_val(void)          { RUN(verifier_map_ret_val); }
 void test_verifier_masking(void)              { RUN(verifier_masking); }
 void test_verifier_may_goto_1(void)           { RUN(verifier_may_goto_1); }
 void test_verifier_may_goto_2(void)           { RUN(verifier_may_goto_2); }
+void test_verifier_mem_size_reg(void)         { RUN(verifier_mem_size_reg); }
 void test_verifier_meta_access(void)          { RUN(verifier_meta_access); }
 void test_verifier_movsx(void)                 { RUN(verifier_movsx); }
 void test_verifier_mul(void)                  { RUN(verifier_mul); }
diff --git a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
index d0d65d6d450cf5..efe7bcae70f85a 100644
--- a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
+++ b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
@@ -64,7 +64,7 @@ int BPF_PROG(cgrp_kfunc_acquire_no_null_check, struct cgroup *cgrp, const char *
 }
 
 SEC("tp_btf/cgroup_mkdir")
-__failure __msg("R1 pointer type STRUCT cgroup must point")
+__failure __msg("R1 is fp expected STRUCT cgroup")
 int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path)
 {
 	struct cgroup *acquired, *stack_cgrp = (struct cgroup *)&path;
diff --git a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
index 5b4453747c2308..0952d1ebf0f17a 100644
--- a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
+++ b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
@@ -137,7 +137,7 @@ int helper_param_not_ok(void *ctx)
 
 	p = bpf_rdonly_cast(0, 0);
 	/*
-	 * Any helper with ARG_CONST_SIZE_OR_ZERO constraint will do,
+	 * Any helper with ARG_MEM_SIZE_OR_ZERO constraint will do,
 	 * the most permissive constraint
 	 */
 	bpf_copy_from_user(p, 0, (void *)42);
diff --git a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c
index 8942b547812917..5c99b1e6532bfd 100644
--- a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c
+++ b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c
@@ -50,7 +50,7 @@ int BPF_PROG(task_kfunc_acquire_untrusted, struct task_struct *task, u64 clone_f
 }
 
 SEC("tp_btf/task_newtask")
-__failure __msg("R1 pointer type STRUCT task_struct must point")
+__failure __msg("R1 is fp expected STRUCT task_struct")
 int BPF_PROG(task_kfunc_acquire_fp, struct task_struct *task, u64 clone_flags)
 {
 	struct task_struct *acquired, *stack_task = (struct task_struct *)&clone_flags;
diff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c
index bc038ac2df98e2..1a273e416fedff 100644
--- a/tools/testing/selftests/bpf/progs/verifier_bounds.c
+++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c
@@ -1195,7 +1195,7 @@ l0_%=:	r1 = r6;					\
 	r3 += -8;					\
 	r5 = 0;						\
 	/* The 4th argument of bpf_skb_store_bytes is defined as \
-	 * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \
+	 * ARG_MEM_SIZE, so 0 is not allowed. The 'r4 != 0' \
 	 * is providing us this exclusion of zero from initial \
 	 * [0, 7] range.				\
 	 */						\
diff --git a/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c b/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c
index f2c54e4d89ebef..343fc08d974798 100644
--- a/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c
+++ b/tools/testing/selftests/bpf/progs/verifier_helper_access_var_len.c
@@ -85,7 +85,7 @@ __naked void stack_bitwise_and_zero_included(void)
 	r2 += -64;					\
 	r4 = 0;						\
 	/* Call bpf_ringbuf_output(), it is one of a few helper functions with\
-	 * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\
+	 * ARG_MEM_SIZE_OR_ZERO parameter allowed in unpriv mode.\
 	 * For unpriv this should signal an error, because memory at &fp[-64] is\
 	 * not initialized.				\
 	 */						\
@@ -278,7 +278,7 @@ __naked void stack_jmp_no_min_check(void)
 	r2 += -64;					\
 	r4 = 0;						\
 	/* Call bpf_ringbuf_output(), it is one of a few helper functions with\
-	 * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\
+	 * ARG_MEM_SIZE_OR_ZERO parameter allowed in unpriv mode.\
 	 * For unpriv this should signal an error, because memory at &fp[-64] is\
 	 * not initialized.				\
 	 */						\
@@ -778,7 +778,7 @@ __naked void variable_memory_8_bytes_leak(void)
 	r3 += 1;					\
 	r4 = 0;						\
 	/* Call bpf_ringbuf_output(), it is one of a few helper functions with\
-	 * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\
+	 * ARG_MEM_SIZE_OR_ZERO parameter allowed in unpriv mode.\
 	 * For unpriv this should signal an error, because memory region [1, 64]\
 	 * at &fp[-64] is not fully initialized.	\
 	 */						\
diff --git a/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c b/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c
index 6d2a38597c34f4..c6603a118fdc39 100644
--- a/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c
+++ b/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c
@@ -91,7 +91,7 @@ l0_%=:	exit;						\
 
 /* Call a function taking a pointer and a size which doesn't allow the size to
  * be zero (i.e. bpf_trace_printk() declares the second argument to be
- * ARG_CONST_SIZE, not ARG_CONST_SIZE_OR_ZERO). We attempt to pass zero for the
+ * ARG_MEM_SIZE, not ARG_MEM_SIZE_OR_ZERO). We attempt to pass zero for the
  * size and expect to fail.
  */
 SEC("tracepoint")
diff --git a/tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c b/tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c
new file mode 100644
index 00000000000000..78a9ad22b10dfd
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+#include "bpf_kfuncs.h"
+
+char _license[] SEC("license") = "GPL";
+
+struct inner_map {
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	__uint(max_entries, 1);
+	__type(key, int);
+	__type(value, int);
+} inner_map SEC(".maps");
+
+struct {
+	__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
+	__uint(max_entries, 1);
+	__type(key, int);
+	__array(values, struct inner_map);
+} outer_map SEC(".maps") = {
+	.values = { [0] = &inner_map },
+};
+
+/* An un-narrowed map-of-maps value must be rejected as a __nullable kfunc mem buffer */
+SEC("?tc")
+__failure
+int mapofmaps_value_as_kfunc_mem_buf(struct __sk_buff *skb)
+{
+	struct bpf_dynptr dptr;
+	__u32 key = 0;
+	void *inner;
+	char *p;
+
+	inner = bpf_map_lookup_elem(&outer_map, &key);
+	/* intentionally NOT NULL-checked: reg stays PTR_TO_MAP_VALUE_OR_NULL */
+
+	bpf_dynptr_from_skb(skb, 0, &dptr);
+	/* pass the un-narrowed map-of-maps value as the scratch buffer */
+	p = bpf_dynptr_slice(&dptr, 0, inner, 8);
+	if (p)
+		return p[0];
+	return 0;
+}
+
+/* An un-narrowed map-of-maps value must be rejected as a PTR_MAYBE_NULL helper mem buffer */
+SEC("?tc")
+__failure
+int mapofmaps_value_as_helper_mem_buf(struct __sk_buff *skb)
+{
+	__u32 key = 0;
+	void *inner;
+
+	inner = bpf_map_lookup_elem(&outer_map, &key);
+	/* intentionally NOT NULL-checked: reg stays PTR_TO_MAP_VALUE_OR_NULL */
+
+	/* @from is a nullable read-only mem+size arg; outer value_size is 4 */
+	return bpf_csum_diff(inner, 4, NULL, 0, 0) + skb->len;
+}
diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
index 2870738d93f7ec..8f0c45421f8938 100644
--- a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
+++ b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
@@ -28,7 +28,7 @@ int BPF_PROG(get_task_exe_file_kfunc_null)
 }
 
 SEC("lsm.s/inode_getxattr")
-__failure __msg("R1 pointer type STRUCT task_struct must point to scalar, or struct with scalar")
+__failure __msg("R1 is fp expected STRUCT task_struct")
 int BPF_PROG(get_task_exe_file_kfunc_fp)
 {
 	u64 x;
@@ -98,7 +98,7 @@ int BPF_PROG(path_d_path_kfunc_null)
 }
 
 SEC("lsm.s/task_alloc")
-__failure __msg("R1 must be referenced or trusted")
+__failure __msg("dereference of modified untrusted_ptr_")
 int BPF_PROG(path_d_path_kfunc_untrusted_from_argument, struct task_struct *task)
 {
 	struct path *root;
@@ -112,7 +112,7 @@ int BPF_PROG(path_d_path_kfunc_untrusted_from_argument, struct task_struct *task
 }
 
 SEC("lsm.s/file_open")
-__failure __msg("R1 must be referenced or trusted")
+__failure __msg("dereference of modified untrusted_ptr_")
 int BPF_PROG(path_d_path_kfunc_untrusted_from_current)
 {
 	struct path *pwd;
diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c
index 302d712e0d7ed2..8cd626e0455157 100644
--- a/tools/testing/selftests/bpf/verifier/calls.c
+++ b/tools/testing/selftests/bpf/verifier/calls.c
@@ -31,7 +31,7 @@
 	},
 	.prog_type = BPF_PROG_TYPE_SCHED_CLS,
 	.result = REJECT,
-	.errstr = "R1 pointer type STRUCT prog_test_fail1 must point to scalar",
+	.errstr = "R1 is fp expected STRUCT prog_test_fail1",
 	.fixup_kfunc_btf_id = {
 		{ "bpf_kfunc_call_test_fail1", 2 },
 	},
@@ -46,7 +46,7 @@
 	},
 	.prog_type = BPF_PROG_TYPE_SCHED_CLS,
 	.result = REJECT,
-	.errstr = "max struct nesting depth exceeded\nR1 pointer type STRUCT prog_test_fail2",
+	.errstr = "max struct nesting depth exceeded\nR1 is fp expected STRUCT prog_test_fail2",
 	.fixup_kfunc_btf_id = {
 		{ "bpf_kfunc_call_test_fail2", 2 },
 	},
@@ -61,7 +61,7 @@
 	},
 	.prog_type = BPF_PROG_TYPE_SCHED_CLS,
 	.result = REJECT,
-	.errstr = "R1 pointer type STRUCT prog_test_fail3 must point to scalar",
+	.errstr = "R1 is fp expected STRUCT prog_test_fail3",
 	.fixup_kfunc_btf_id = {
 		{ "bpf_kfunc_call_test_fail3", 2 },
 	},

3/2 2026/07/24 09:17 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 46954
							output: 208
							thoughts: 891
						

Thoughts:
**Fuzzing Target: eBPF Verifier Kfunc Argument Handling**

Okay, so I've been looking at this patch and it's making some pretty fundamental changes to how the eBPF verifier deals with arguments to kfuncs and helper functions. It seems like a lot of the logic surrounding argument validation is being revamped. They're introducing `__const_map` and `__map` annotations for kfuncs, replacing some of the older stuff.  Essentially, there's a shift in how the verifier determines and uses information about constant maps, particularly during the handling of kfuncs.

Specifically, it looks like they're trying to unify the argument checking process.  We're going from `ARG_CONST_SIZE` and `ARG_CONST_SIZE_OR_ZERO` to `ARG_MEM_SIZE` and `ARG_MEM_SIZE_OR_ZERO`.  This whole area is super sensitive, and any change has to be carefully scrutinized.  There's also this new function, `gen_kfunc_arg_proto()`, which is used to generate `bpf_func_proto` structures for kfuncs, similar to how it’s done for helper functions.  This definitely looks like a significant functional change within the verifier.

It's clear that the execution flow of the verifier is going to be altered significantly, especially in how it validates those all-important arguments for both BPF helpers and kfuncs. The introduction of this `gen_kfunc_arg_proto` is a critical new point, and I need to see how it integrates with the existing argument validation routines.  Specifically, `check_func_arg()` and `check_kfunc_args()` are being modified to do a more unified argument check.  `process_map_ptr_arg()` is also being tweaked to handle map pointer arguments for both helpers and kfuncs. This is a lot of touchpoints to check.

The eBPF verifier is a core component, and it's already heavily fuzzed, so *any* changes in this area are going to need a lot of attention. Given the scope of these modifications, and the criticality of this part of the kernel, I'm thinking this is definitely worth fuzzing. The patch introduces some new functionality and also reuses existing infrastructure in new ways. The focus should be on the areas impacted:

*   `gen_kfunc_arg_proto` - This one is brand new, so it’s critical to verify its behavior.
*   `get_kfunc_arg_type` - This is related to the argument types.
*   `process_map_ptr_arg` - It's dealing with map pointers for both helpers and kfuncs, which is a key area.
*   `check_kfunc_args` - This is the core kfunc argument validation.
*   `check_func_arg` - It is the core function argument validation.
*   `check_mem_size_reg` - For memory size checks.
*   `check_mem_reg` - For memory register checks.
*   `process_const_arg` - This is related to how constant arguments are processed.

I should also make sure that `BPF_SYSCALL` and `DEBUG_INFO_BTF` are enabled for proper testing and coverage, particularly because of the BTF dependency on kfuncs.

So, let's fire up the `set-results` tool... It looks like a good plan to fuzz this patch.



4/2 2026/07/24 09:17 tool set-results
0m Args:
{
  "EnableConfigs": [
    "BPF_SYSCALL",
    "DEBUG_INFO_BTF"
  ],
  "FocusSymbols": [
    "gen_kfunc_arg_proto",
    "get_kfunc_arg_type",
    "process_map_ptr_arg",
    "check_kfunc_args",
    "check_func_arg",
    "check_mem_size_reg",
    "check_mem_reg",
    "process_const_arg"
  ],
  "Reasoning": "The patch significantly refactors how the eBPF verifier handles arguments for kfuncs and helper functions, introducing new argument types (ARG_MEM_SIZE, ARG_MEM_SIZE_OR_ZERO) and a new way to generate kfunc prototypes (gen_kfunc_arg_proto). This is core verifier logic that is highly complex and prone to security vulnerabilities, making it a prime target for fuzzing.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "BPF_SYSCALL",
    "DEBUG_INFO_BTF"
  ],
  "FocusSymbols": [
    "gen_kfunc_arg_proto",
    "get_kfunc_arg_type",
    "process_map_ptr_arg",
    "check_kfunc_args",
    "check_func_arg",
    "check_mem_size_reg",
    "check_mem_reg",
    "process_const_arg"
  ],
  "Reasoning": "The patch significantly refactors how the eBPF verifier handles arguments for kfuncs and helper functions, introducing new argument types (ARG_MEM_SIZE, ARG_MEM_SIZE_OR_ZERO) and a new way to generate kfunc prototypes (gen_kfunc_arg_proto). This is core verifier logic that is highly complex and prone to security vulnerabilities, making it a prime target for fuzzing.",
  "WorthFuzzing": true
}

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)