| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/06 17:57 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"check_func_arg",
"check_func_args",
"check_helper_call",
"check_kfunc_call",
"resolve_func_arg_type",
"get_kfunc_arg_type",
"check_func_arg_nullability",
"check_func_arg_release",
"process_arg_ptr_to_btf_id",
"bpf_do_misc_fixups"
],
"KMSANReasoning": "The patch series is a refactor and consolidation of the BPF verifier's argument-checking subsystem. It merges the validation paths for BPF helper calls and kfuncs into unified helper/kfunc argument checking (`check_func_args`), renames `ARG_ANYTHING` to `ARG_SCALAR` and `ARG_DONTCARE` to `ARG_UNUSED`, and extends `enum bpf_arg_type` with kfunc argument types while updating error diagnostics and selftest expected messages.\n\nThere are no changes that introduce uninitialized stack or heap allocations, no modifications to kernel-to-user copy routines (e.g. `copy_to_user`, `put_user`, socket options, or netlink), and no alterations to data buffer initialization or info-leak vectors. Any potential logic bugs in verifier register typing or bounds checking would be caught by standard verifier checks, KASAN, or existing testing suites. Therefore, dedicated KMSAN fuzzing is not required.",
"NeedsKMSAN": false,
"Reasoning": "The patch refactors and unifies BPF helper and kfunc argument verification in the BPF verifier (kernel/bpf/verifier.c) and instruction fixups (kernel/bpf/fixups.c). These core verifier changes modify verification rules, nullability checks, argument type resolution, and bytecode rewriting, all of which are directly reachable via the bpf() system call and represent high-value fuzzing targets.",
"WorthFuzzing": true
} |
| 1/1 | 2026/09/06 17:57 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit b3736d7edfb0ded619d427677f8b5828c42e1d69\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sun Sep 6 17:57:48 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c\nindex 2f7564f26445c..108edf440c891 100644\n--- a/drivers/media/rc/bpf-lirc.c\n+++ b/drivers/media/rc/bpf-lirc.c\n@@ -52,9 +52,9 @@ static const struct bpf_func_proto rc_keydown_proto = {\n \t.gpl_only = true, /* rc_keydown is EXPORT_SYMBOL_GPL */\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n-\t.arg3_type = ARG_ANYTHING,\n-\t.arg4_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n+\t.arg3_type = ARG_SCALAR,\n+\t.arg4_type = ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_rc_pointer_rel, u32*, sample, s32, rel_x, s32, rel_y)\n@@ -75,8 +75,8 @@ static const struct bpf_func_proto rc_pointer_rel_proto = {\n \t.gpl_only = true,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n-\t.arg3_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n+\t.arg3_type = ARG_SCALAR,\n };\n \n static const struct bpf_func_proto *\ndiff --git a/include/linux/bpf.h b/include/linux/bpf.h\nindex 3a7eb2185c354..fe6ab92ceeffe 100644\n--- a/include/linux/bpf.h\n+++ b/include/linux/bpf.h\n@@ -874,7 +874,7 @@ enum bpf_type_flag {\n \n /* function argument constraints */\n enum bpf_arg_type {\n-\tARG_DONTCARE = 0,\t/* unused argument in helper function */\n+\tARG_UNUSED = 0,\t/* unused argument; terminates argument iteration */\n \n \t/* the following constraints used to prototype\n \t * bpf_map_lookup/update/delete_elem() functions\n@@ -893,7 +893,7 @@ enum bpf_arg_type {\n \tARG_MEM_SIZE_OR_ZERO,\t/* number of bytes accessed from memory or 0 */\n \n \tARG_PTR_TO_CTX,\t\t/* pointer to context */\n-\tARG_ANYTHING,\t\t/* any (initialized) argument is ok */\n+\tARG_SCALAR,\t\t/* any (initialized) scalar is ok */\n \tARG_PTR_TO_SPIN_LOCK,\t/* pointer to bpf_spin_lock */\n \tARG_PTR_TO_SOCK_COMMON,\t/* pointer to sock_common */\n \tARG_PTR_TO_SOCKET,\t/* pointer to bpf_sock (fullsock) */\n@@ -908,6 +908,22 @@ enum bpf_arg_type {\n \tARG_PTR_TO_TIMER,\t/* pointer to bpf_timer */\n \tARG_KPTR_XCHG_DEST,\t/* pointer to destination that kptrs are bpf_kptr_xchg'd into */\n \tARG_PTR_TO_DYNPTR, /* pointer to bpf_dynptr. See bpf_type_flag for dynptr type */\n+\n+\tARG_CONST_SCALAR,\t/* scalar known at verification time */\n+\tARG_CONST_MEM_SIZE,\t/* ARG_MEM_SIZE that must be constant */\n+\tARG_PTR_TO_ALLOC_BTF_ID,\t/* pointer to an allocated object */\n+\tARG_PTR_TO_REFCOUNTED_KPTR,\t/* pointer to a refcounted local kptr */\n+\tARG_PTR_TO_ITER,\t/* pointer to an iterator */\n+\tARG_PTR_TO_LIST_HEAD,\t/* pointer to bpf_list_head */\n+\tARG_PTR_TO_LIST_NODE,\t/* pointer to bpf_list_node */\n+\tARG_PTR_TO_RB_ROOT,\t/* pointer to bpf_rb_root */\n+\tARG_PTR_TO_RB_NODE,\t/* pointer to bpf_rb_node */\n+\tARG_PTR_TO_WORKQUEUE,\t/* pointer to bpf_wq */\n+\tARG_PTR_TO_TASK_WORK,\t/* pointer to bpf_task_work */\n+\tARG_PTR_TO_IRQ_FLAG,\t/* pointer to saved IRQ flags on the stack */\n+\tARG_PTR_TO_RES_SPIN_LOCK,\t/* pointer to bpf_res_spin_lock */\n+\tARG_PTR_TO_PROG_AUX,\t/* pointer to the caller's bpf_prog_aux */\n+\tARG_IGNORE,\t\t/* argument the verifier does not check at all */\n \t__BPF_ARG_TYPE_MAX,\n \n \t/* Extended arg_types. */\n@@ -1004,13 +1020,13 @@ struct bpf_func_proto {\n \t};\n \tunion {\n \t\tstruct {\n-\t\t\tu32 *arg1_btf_id;\n-\t\t\tu32 *arg2_btf_id;\n-\t\t\tu32 *arg3_btf_id;\n-\t\t\tu32 *arg4_btf_id;\n-\t\t\tu32 *arg5_btf_id;\n+\t\t\tconst u32 *arg1_btf_id;\n+\t\t\tconst u32 *arg2_btf_id;\n+\t\t\tconst u32 *arg3_btf_id;\n+\t\t\tconst u32 *arg4_btf_id;\n+\t\t\tconst u32 *arg5_btf_id;\n \t\t};\n-\t\tu32 *arg_btf_id[MAX_BPF_FUNC_ARGS];\n+\t\tconst u32 *arg_btf_id[MAX_BPF_FUNC_ARGS];\n \t\tstruct {\n \t\t\tsize_t arg1_size;\n \t\t\tsize_t arg2_size;\ndiff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h\nindex 1a3c44ab06a15..e919e308f2720 100644\n--- a/include/linux/bpf_verifier.h\n+++ b/include/linux/bpf_verifier.h\n@@ -1585,7 +1585,6 @@ struct bpf_call_arg_meta {\n \tstruct btf *arg_btf;\n \tu32 arg_btf_id;\n \tbool arg_owning_ref;\n-\tbool arg_prog;\n \n \tstruct {\n \t\tstruct btf_field *field;\ndiff --git a/kernel/bpf/backtrack.c b/kernel/bpf/backtrack.c\nindex 653db80bcc47b..c5c9c5f3b0781 100644\n--- a/kernel/bpf/backtrack.c\n+++ b/kernel/bpf/backtrack.c\n@@ -634,7 +634,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,\n * The approach of starting with precise=true for all registers and then\n * backtrack to mark a register as not precise when the verifier detects\n * that program doesn't care about specific value (e.g., when helper\n- * takes register as ARG_ANYTHING parameter) is not safe.\n+ * takes register as ARG_SCALAR parameter) is not safe.\n *\n * It's ok to walk single parentage chain of the verifier states.\n * It's possible that this backtracking will go all the way till 1st insn.\ndiff --git a/kernel/bpf/bpf_cgrp_storage.c b/kernel/bpf/bpf_cgrp_storage.c\nindex c76e9b0fabba8..095d5c93e4ba6 100644\n--- a/kernel/bpf/bpf_cgrp_storage.c\n+++ b/kernel/bpf/bpf_cgrp_storage.c\n@@ -180,7 +180,7 @@ const struct bpf_func_proto bpf_cgrp_storage_get_proto = {\n \t.arg2_type\t= ARG_PTR_TO_BTF_ID_OR_NULL,\n \t.arg2_btf_id\t= \u0026bpf_cgroup_btf_id[0],\n \t.arg3_type\t= ARG_PTR_TO_MAP_VALUE_OR_NULL,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n const struct bpf_func_proto bpf_cgrp_storage_delete_proto = {\ndiff --git a/kernel/bpf/bpf_inode_storage.c b/kernel/bpf/bpf_inode_storage.c\nindex f9e81060c1f45..69e1876650dd7 100644\n--- a/kernel/bpf/bpf_inode_storage.c\n+++ b/kernel/bpf/bpf_inode_storage.c\n@@ -220,7 +220,7 @@ const struct bpf_func_proto bpf_inode_storage_get_proto = {\n \t.arg2_type\t= ARG_PTR_TO_BTF_ID_OR_NULL,\n \t.arg2_btf_id\t= \u0026bpf_inode_storage_btf_ids[0],\n \t.arg3_type\t= ARG_PTR_TO_MAP_VALUE_OR_NULL,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n const struct bpf_func_proto bpf_inode_storage_delete_proto = {\ndiff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c\nindex 14a5fdfa04214..1068bf8621f08 100644\n--- a/kernel/bpf/bpf_iter.c\n+++ b/kernel/bpf/bpf_iter.c\n@@ -721,7 +721,7 @@ const struct bpf_func_proto bpf_for_each_map_elem_proto = {\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n \t.arg2_type\t= ARG_PTR_TO_FUNC,\n \t.arg3_type\t= ARG_PTR_TO_STACK_OR_NULL,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_loop, u32, nr_loops, void *, callback_fn, void *, callback_ctx,\n@@ -754,10 +754,10 @@ const struct bpf_func_proto bpf_loop_proto = {\n \t.func\t\t= bpf_loop,\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n \t.arg2_type\t= ARG_PTR_TO_FUNC,\n \t.arg3_type\t= ARG_PTR_TO_STACK_OR_NULL,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n struct bpf_iter_num_kern {\ndiff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c\nindex 82c5988417a0c..9ee39c654dc0a 100644\n--- a/kernel/bpf/bpf_lsm.c\n+++ b/kernel/bpf/bpf_lsm.c\n@@ -163,7 +163,7 @@ static const struct bpf_func_proto bpf_bprm_opts_set_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026bpf_bprm_opts_set_btf_ids[0],\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_ima_inode_hash, struct inode *, inode, void *, dst, u32, size)\ndiff --git a/kernel/bpf/bpf_task_storage.c b/kernel/bpf/bpf_task_storage.c\nindex 4b342be29eac7..e002df9d3a143 100644\n--- a/kernel/bpf/bpf_task_storage.c\n+++ b/kernel/bpf/bpf_task_storage.c\n@@ -243,7 +243,7 @@ const struct bpf_func_proto bpf_task_storage_get_proto = {\n \t.arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,\n \t.arg2_btf_id = \u0026btf_tracing_ids[BTF_TRACING_TYPE_TASK],\n \t.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,\n-\t.arg4_type = ARG_ANYTHING,\n+\t.arg4_type = ARG_SCALAR,\n };\n \n const struct bpf_func_proto bpf_task_storage_delete_proto = {\ndiff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c\nindex 9c2cab08bb794..0bd26b2ec77db 100644\n--- a/kernel/bpf/btf.c\n+++ b/kernel/bpf/btf.c\n@@ -8222,7 +8222,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)\n \t\t\treturn -EINVAL;\n \t\t}\n \t\tif (btf_type_is_int(t) || btf_is_any_enum(t)) {\n-\t\t\tsub-\u003eargs[i].arg_type = ARG_ANYTHING;\n+\t\t\tsub-\u003eargs[i].arg_type = ARG_SCALAR;\n \t\t\tcontinue;\n \t\t}\n \t\tif (!is_global)\n@@ -8747,8 +8747,8 @@ const struct bpf_func_proto bpf_btf_find_by_name_kind_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg2_type\t= ARG_MEM_SIZE,\n-\t.arg3_type\t= ARG_ANYTHING,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BTF_ID_LIST_GLOBAL(btf_tracing_ids, MAX_BTF_TRACING_TYPE)\ndiff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c\nindex 149672c76c49c..aa7da999cdb8a 100644\n--- a/kernel/bpf/cgroup.c\n+++ b/kernel/bpf/cgroup.c\n@@ -1840,7 +1840,7 @@ const struct bpf_func_proto bpf_get_local_storage_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_PTR_TO_MAP_VALUE,\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_0(bpf_get_retval)\n@@ -1870,7 +1870,7 @@ const struct bpf_func_proto bpf_set_retval_proto = {\n \t.func\t\t= bpf_set_retval,\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n };\n \n static const struct bpf_func_proto *\n@@ -2331,7 +2331,7 @@ static const struct bpf_func_proto bpf_sysctl_get_name_proto = {\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_MEM_SIZE,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n static int copy_sysctl_value(char *dst, size_t dst_len, char *src,\ndiff --git a/kernel/bpf/core.c b/kernel/bpf/core.c\nindex 5db77d7915dfc..404dc6db06915 100644\n--- a/kernel/bpf/core.c\n+++ b/kernel/bpf/core.c\n@@ -3208,7 +3208,7 @@ const struct bpf_func_proto bpf_tail_call_proto = {\n \t.ret_type\t= RET_VOID,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n /* Stub for JITs that only support cBPF. eBPF programs are interpreted.\ndiff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c\nindex b682fd2be443e..c740ae070e61b 100644\n--- a/kernel/bpf/diagnostics.c\n+++ b/kernel/bpf/diagnostics.c\n@@ -960,6 +960,35 @@ const char *bpf_diag_reg_type_plain(struct bpf_verifier_env *env, enum bpf_reg_t\n \t}\n }\n \n+const char *bpf_diag_arg_type_plain(enum bpf_arg_type type)\n+{\n+\tswitch (base_type(type)) {\n+\tcase ARG_MEM_SIZE:\n+\tcase ARG_CONST_MEM_SIZE:\n+\t\treturn \"an integer scalar length for this memory argument\";\n+\tcase ARG_PTR_TO_CTX:\n+\t\treturn \"the original program context pointer or preserve it before modifying registers\";\n+\tcase ARG_SCALAR:\n+\tcase ARG_CONST_SCALAR:\n+\tcase ARG_CONST_ALLOC_SIZE_OR_ZERO:\n+\t\treturn \"an integer scalar value for this argument, not a pointer or resource object\";\n+\tcase ARG_PTR_TO_CONST_STR:\n+\t\treturn \"a constant string pointer that the verifier recognizes, such as a string stored in a read-only map value\";\n+\tcase ARG_PTR_TO_DYNPTR:\n+\t\treturn \"the address of a stack dynptr object, or use a const dynptr pointer returned by the verifier-supported path\";\n+\tcase ARG_PTR_TO_ALLOC_BTF_ID:\n+\t\treturn \"a pointer returned by the matching BPF object allocation path\";\n+\tcase ARG_PTR_TO_REFCOUNTED_KPTR:\n+\t\treturn \"an owning or non-owning pointer to a BPF-managed object containing a bpf_refcount field\";\n+\tcase ARG_PTR_TO_ITER:\n+\t\treturn \"the address of a stack iterator object for iterator new, next, and destroy calls\";\n+\tcase ARG_PTR_TO_IRQ_FLAG:\n+\t\treturn \"the same stack slot used by bpf_local_irq_save() or bpf_res_spin_lock_irqsave()\";\n+\tdefault:\n+\t\treturn \"a value with one of the accepted pointer or scalar types for this call\";\n+\t}\n+}\n+\n static const char *diag_arg_ordinal(int argno)\n {\n \tswitch (argno) {\ndiff --git a/kernel/bpf/diagnostics.h b/kernel/bpf/diagnostics.h\nindex d1b79945008a8..a4102fb049ece 100644\n--- a/kernel/bpf/diagnostics.h\n+++ b/kernel/bpf/diagnostics.h\n@@ -51,6 +51,7 @@ const char *bpf_diag_vfmt(struct bpf_verifier_env *env, const char *fmt, va_list\n const char *bpf_diag_fmt(struct bpf_verifier_env *env, const char *fmt, ...) __printf(2, 3);\n const char *bpf_diag_fmt_btf_type(struct bpf_verifier_env *env, const struct btf *btf, u32 type_id);\n const char *bpf_diag_reg_type_plain(struct bpf_verifier_env *env, enum bpf_reg_type type);\n+const char *bpf_diag_arg_type_plain(enum bpf_arg_type type);\n u64 bpf_diag_event_log_save(struct bpf_verifier_env *env);\n void bpf_diag_event_log_restore(struct bpf_verifier_env *env, u64 log_pos);\n u32 bpf_diag_irq_depth(const struct bpf_verifier_state *state);\ndiff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c\nindex 73fb3ffc18e33..9512f6497d328 100644\n--- a/kernel/bpf/fixups.c\n+++ b/kernel/bpf/fixups.c\n@@ -2015,7 +2015,8 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)\n \t\t\tgoto next_insn;\n \t\t}\n \n-\t\tif (insn-\u003eimm == BPF_FUNC_timer_set_callback) {\n+\t\taux = \u0026env-\u003einsn_aux_data[i + delta];\n+\t\tif (aux-\u003earg_prog) {\n \t\t\t/* The verifier will process callback_fn as many times as necessary\n \t\t\t * with different maps and the register states prepared by\n \t\t\t * set_timer_callback_state will be accurate.\n@@ -2030,7 +2031,7 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)\n \t\t\t * bpf_timer_set_callback-ed will return -EINVAL.\n \t\t\t */\n \t\t\tstruct bpf_insn ld_addrs[2] = {\n-\t\t\t\tBPF_LD_IMM64(BPF_REG_3, (long)prog-\u003eaux),\n+\t\t\t\tBPF_LD_IMM64(aux-\u003earg_prog, (long)prog-\u003eaux),\n \t\t\t};\n \n \t\t\tinsn_buf[0] = ld_addrs[0];\ndiff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c\nindex b3cc5c8fc8756..1b731aad54da6 100644\n--- a/kernel/bpf/helpers.c\n+++ b/kernel/bpf/helpers.c\n@@ -71,7 +71,7 @@ const struct bpf_func_proto bpf_map_update_elem_proto = {\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n \t.arg2_type\t= ARG_PTR_TO_MAP_KEY,\n \t.arg3_type\t= ARG_PTR_TO_MAP_VALUE,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_map_delete_elem, struct bpf_map *, map, void *, key)\n@@ -101,7 +101,7 @@ const struct bpf_func_proto bpf_map_push_elem_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_MAP_VALUE,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_map_pop_elem, struct bpf_map *, map, void *, value)\n@@ -143,7 +143,7 @@ const struct bpf_func_proto bpf_map_lookup_percpu_elem_proto = {\n \t.ret_type\t= RET_PTR_TO_MAP_VALUE_OR_NULL,\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n \t.arg2_type\t= ARG_PTR_TO_MAP_KEY,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n const struct bpf_func_proto bpf_get_prandom_u32_proto = {\n@@ -441,7 +441,7 @@ const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto = {\n \t.func\t\t= bpf_get_current_ancestor_cgroup_id,\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n };\n #endif /* CONFIG_CGROUPS */\n \n@@ -540,7 +540,7 @@ const struct bpf_func_proto bpf_strtol_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg2_type\t= ARG_MEM_SIZE,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\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 };\n@@ -568,7 +568,7 @@ const struct bpf_func_proto bpf_strtoul_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg2_type\t= ARG_MEM_SIZE,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\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 };\n@@ -624,8 +624,8 @@ const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto = {\n \t.func\t\t= bpf_get_ns_current_pid_tgid,\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type = ARG_PTR_TO_UNINIT_MEM,\n \t.arg4_type = ARG_MEM_SIZE,\n };\n@@ -651,7 +651,7 @@ const struct bpf_func_proto bpf_event_output_data_proto = {\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_CONST_MAP_PTR,\n-\t.arg3_type = ARG_ANYTHING,\n+\t.arg3_type = ARG_SCALAR,\n \t.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type = ARG_MEM_SIZE_OR_ZERO,\n };\n@@ -676,7 +676,7 @@ const struct bpf_func_proto bpf_copy_from_user_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_copy_from_user_task, void *, dst, u32, size,\n@@ -707,10 +707,10 @@ const struct bpf_func_proto bpf_copy_from_user_task_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg4_btf_id\t= \u0026btf_tracing_ids[BTF_TRACING_TYPE_TASK],\n-\t.arg5_type\t= ARG_ANYTHING\n+\t.arg5_type\t= ARG_SCALAR\n };\n \n BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)\n@@ -726,7 +726,7 @@ const struct bpf_func_proto bpf_per_cpu_ptr_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY,\n \t.arg1_type\t= ARG_PTR_TO_PERCPU_BTF_ID,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)\n@@ -1415,7 +1415,7 @@ static const struct bpf_func_proto bpf_timer_init_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_TIMER,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n static int bpf_async_update_prog_callback(struct bpf_async_cb *cb,\n@@ -1510,6 +1510,7 @@ static const struct bpf_func_proto bpf_timer_set_callback_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_TIMER,\n \t.arg2_type\t= ARG_PTR_TO_FUNC,\n+\t.arg3_type\t= ARG_PTR_TO_PROG_AUX,\n };\n \n static bool defer_timer_wq_op(void)\n@@ -1558,8 +1559,8 @@ static const struct bpf_func_proto bpf_timer_start_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_TIMER,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_1(bpf_timer_cancel, struct bpf_async_kern *, async)\n@@ -1889,7 +1890,7 @@ static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT | MEM_WRITE,\n };\n \n@@ -1945,8 +1946,8 @@ static const struct bpf_func_proto bpf_dynptr_read_proto = {\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\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+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n int __bpf_dynptr_write(const struct bpf_dynptr_kern *dst, u64 offset, void *src,\n@@ -2002,10 +2003,10 @@ static const struct bpf_func_proto bpf_dynptr_write_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_DYNPTR,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg4_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_dynptr_data, const struct bpf_dynptr_kern *, ptr, u64, offset, u64, len)\n@@ -2045,7 +2046,7 @@ static const struct bpf_func_proto bpf_dynptr_data_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_PTR_TO_DYNPTR_MEM_OR_NULL,\n \t.arg1_type\t= ARG_PTR_TO_DYNPTR,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_CONST_ALLOC_SIZE_OR_ZERO,\n };\n \n@@ -2957,7 +2958,7 @@ const struct bpf_func_proto bpf_current_task_under_cgroup_proto = {\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_CONST_MAP_PTR,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n };\n \n /**\ndiff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c\nindex 3f1013d805446..63c0aba56a3f3 100644\n--- a/kernel/bpf/ringbuf.c\n+++ b/kernel/bpf/ringbuf.c\n@@ -553,7 +553,7 @@ const struct bpf_func_proto bpf_ringbuf_reserve_proto = {\n \t.ret_type\t= RET_PTR_TO_RINGBUF_MEM_OR_NULL,\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n \t.arg2_type\t= ARG_CONST_ALLOC_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n static void bpf_ringbuf_commit(void *sample, u64 flags, bool discard)\n@@ -594,7 +594,7 @@ const struct bpf_func_proto bpf_ringbuf_submit_proto = {\n \t.func\t\t= bpf_ringbuf_submit,\n \t.ret_type\t= RET_VOID,\n \t.arg1_type\t= ARG_PTR_TO_RINGBUF_MEM | OBJ_RELEASE,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_ringbuf_discard, void *, sample, u64, flags)\n@@ -607,7 +607,7 @@ const struct bpf_func_proto bpf_ringbuf_discard_proto = {\n \t.func\t\t= bpf_ringbuf_discard,\n \t.ret_type\t= RET_VOID,\n \t.arg1_type\t= ARG_PTR_TO_RINGBUF_MEM | OBJ_RELEASE,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_ringbuf_output, struct bpf_map *, map, void *, data, u64, size,\n@@ -635,7 +635,7 @@ const struct bpf_func_proto bpf_ringbuf_output_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_ringbuf_query, struct bpf_map *, map, u64, flags)\n@@ -664,7 +664,7 @@ const struct bpf_func_proto bpf_ringbuf_query_proto = {\n \t.func\t\t= bpf_ringbuf_query,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_ringbuf_reserve_dynptr, struct bpf_map *, map, u32, size, u64, flags,\n@@ -702,8 +702,8 @@ const struct bpf_func_proto bpf_ringbuf_reserve_dynptr_proto = {\n \t.func\t\t= bpf_ringbuf_reserve_dynptr,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT | MEM_WRITE,\n };\n \n@@ -723,7 +723,7 @@ const struct bpf_func_proto bpf_ringbuf_submit_dynptr_proto = {\n \t.func\t\t= bpf_ringbuf_submit_dynptr,\n \t.ret_type\t= RET_VOID,\n \t.arg1_type\t= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | OBJ_RELEASE,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_ringbuf_discard_dynptr, struct bpf_dynptr_kern *, ptr, u64, flags)\n@@ -742,7 +742,7 @@ const struct bpf_func_proto bpf_ringbuf_discard_dynptr_proto = {\n \t.func\t\t= bpf_ringbuf_discard_dynptr,\n \t.ret_type\t= RET_VOID,\n \t.arg1_type\t= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | OBJ_RELEASE,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n static int __bpf_user_ringbuf_peek(struct bpf_ringbuf *rb, void **sample, u32 *size)\n@@ -876,5 +876,5 @@ const struct bpf_func_proto bpf_user_ringbuf_drain_proto = {\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n \t.arg2_type\t= ARG_PTR_TO_FUNC,\n \t.arg3_type\t= ARG_PTR_TO_STACK_OR_NULL,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\ndiff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c\nindex a839041e0d008..272678b825005 100644\n--- a/kernel/bpf/stackmap.c\n+++ b/kernel/bpf/stackmap.c\n@@ -665,7 +665,7 @@ const struct bpf_func_proto bpf_get_stackid_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n static __u64 count_kernel_ip(const struct perf_callchain_entry *trace)\n@@ -739,7 +739,7 @@ const struct bpf_func_proto bpf_get_stackid_proto_pe = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n static u32 callchain_store(const struct perf_callchain_entry *trace, u32 trace_nr,\n@@ -863,7 +863,7 @@ const struct bpf_func_proto bpf_get_stack_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_get_stack_sleepable, struct pt_regs *, regs, void *, buf, u32, size,\n@@ -879,7 +879,7 @@ const struct bpf_func_proto bpf_get_stack_sleepable_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n static long __bpf_get_task_stack(struct task_struct *task, void *buf, u32 size,\n@@ -916,7 +916,7 @@ const struct bpf_func_proto bpf_get_task_stack_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_get_task_stack_sleepable, struct task_struct *, task, void *, buf,\n@@ -933,7 +933,7 @@ const struct bpf_func_proto bpf_get_task_stack_sleepable_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n static int __bpf_get_stack_pe(const struct perf_callchain_entry *trace, u32 trace_nr,\n@@ -1015,7 +1015,7 @@ const struct bpf_func_proto bpf_get_stack_proto_pe = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n /* Called from eBPF program */\ndiff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c\nindex 6874ba1424af0..6950517f6364b 100644\n--- a/kernel/bpf/syscall.c\n+++ b/kernel/bpf/syscall.c\n@@ -6569,7 +6569,7 @@ static const struct bpf_func_proto bpf_sys_bpf_proto = {\n \t.func\t\t= bpf_sys_bpf,\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg3_type\t= ARG_MEM_SIZE,\n };\n@@ -6594,7 +6594,7 @@ static const struct bpf_func_proto bpf_sys_close_proto = {\n \t.func\t\t= bpf_sys_close,\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flags, u64 *, res)\n@@ -6619,7 +6619,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\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 };\ndiff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c\nindex 13e1aabe6f886..91b166acb3b5c 100644\n--- a/kernel/bpf/task_iter.c\n+++ b/kernel/bpf/task_iter.c\n@@ -824,10 +824,10 @@ const struct bpf_func_proto bpf_find_vma_proto = {\n \t.ret_type\t= RET_INTEGER,\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_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_FUNC,\n \t.arg4_type\t= ARG_PTR_TO_STACK_OR_NULL,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n static inline void bpf_iter_mmput_async(struct mm_struct *mm)\ndiff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c\nindex 5b51e7ee1a3f9..54656fb31bbe7 100644\n--- a/kernel/bpf/verifier.c\n+++ b/kernel/bpf/verifier.c\n@@ -951,8 +951,12 @@ static enum bpf_dynptr_type dynptr_reg_type(struct bpf_verifier_env *env, struct\n static bool is_dynptr_type_expected(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n \t\t\t\t enum bpf_arg_type arg_type)\n {\n-\t/* ARG_PTR_TO_DYNPTR takes any type of dynptr */\n-\tif (arg_type == ARG_PTR_TO_DYNPTR)\n+\t/*\n+\t * ARG_PTR_TO_DYNPTR without a type flag takes any type of dynptr.\n+\t * Test the flags rather than the whole arg_type, which may carry\n+\t * unrelated ones such as PTR_MAYBE_NULL.\n+\t */\n+\tif (!(arg_type \u0026 DYNPTR_TYPE_FLAG_MASK))\n \t\treturn true;\n \n \treturn dynptr_reg_type(env, reg) == arg_to_dynptr_type(arg_type);\n@@ -4845,7 +4849,7 @@ static int check_map_access(struct bpf_verifier_env *env, struct bpf_reg_state *\n }\n \n static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,\n-\t\t\t const struct bpf_func_proto *fn,\n+\t\t\t const struct bpf_call_arg_meta *meta,\n \t\t\t enum bpf_access_type t)\n {\n \tenum bpf_prog_type prog_type = resolve_prog_type(env-\u003eprog);\n@@ -4869,10 +4873,11 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,\n \tcase BPF_PROG_TYPE_LWT_XMIT:\n \tcase BPF_PROG_TYPE_SK_SKB:\n \tcase BPF_PROG_TYPE_SK_MSG:\n-\t\tif (fn)\n-\t\t\treturn fn-\u003epkt_access;\n+\t\tif (meta \u0026\u0026 !meta-\u003ebtf \u0026\u0026 meta-\u003efunc_id)\n+\t\t\treturn meta-\u003efn-\u003epkt_access;\n \n-\t\tenv-\u003eseen_direct_write = true;\n+\t\tif (t == BPF_WRITE)\n+\t\t\tenv-\u003eseen_direct_write = true;\n \t\treturn true;\n \n \tcase BPF_PROG_TYPE_CGROUP_SOCKOPT:\n@@ -5130,18 +5135,6 @@ 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(u32 ref_id)\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 *reg2btf_ids[type] == ref_id)\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@@ -7056,6 +7049,10 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, struct bpf_reg_\n \tswitch (base_type(reg-\u003etype)) {\n \tcase PTR_TO_PACKET:\n \tcase PTR_TO_PACKET_META:\n+\t\tif (!may_access_direct_pkt_data(env, meta, access_type)) {\n+\t\t\tverbose(env, \"function access to the packet is not allowed\\n\");\n+\t\t\treturn -EACCES;\n+\t\t}\n \t\treturn check_packet_access(env, reg, argno, 0, access_size,\n \t\t\t\t\t zero_size_allowed);\n \tcase PTR_TO_MAP_KEY:\n@@ -7172,7 +7169,7 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,\n \t * the memory that the helper could just partially fill up.\n \t */\n \tif (!tnum_is_const(size_reg-\u003evar_off))\n-\t\tmeta = NULL;\n+\t\tmeta-\u003earg_raw_mem.regno = 0;\n \n \tif (reg_smin(size_reg) \u003c 0) {\n \t\tverbose(env, \"%s min value is negative, either use unsigned or 'var \u0026= const'\\n\",\n@@ -7618,11 +7615,11 @@ __printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u\n /*\n * Validate dynptr arguments for helper, kfunc and subprog.\n *\n- * @dynptr is both input and output. It is populated when the argument is\n- * tagged with MEM_UNINIT (i.e., the dynptr argument that will be constructed)\n- * and consumed when the argument is expecting to be an initialized dynptr.\n- * @parent_id is used to track the referenced parent object (e.g., file or skb in\n- * qdisc program) when constructing a dynptr.\n+ * @meta carries the dynptr and referenced-object state. The dynptr is populated\n+ * when the argument is tagged with MEM_UNINIT (i.e., the dynptr argument that\n+ * will be constructed) and consumed when the argument is expected to be an\n+ * initialized dynptr. The reference tracks the parent object (e.g., file or skb\n+ * in qdisc program) when constructing a dynptr.\n *\n * There are two register types representing a bpf_dynptr, one is PTR_TO_STACK\n * which points to a stack slot, and the other is CONST_PTR_TO_DYNPTR.\n@@ -7639,9 +7636,8 @@ __printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u\n * and checked dynamically during runtime.\n */\n static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n-\t\t\t argno_t argno, int insn_idx, const char *call_name,\n-\t\t\t enum bpf_arg_type arg_type,\n-\t\t\t struct ref_obj_desc *ref_obj, struct bpf_dynptr_desc *dynptr)\n+\t\t\t argno_t argno, int insn_idx, enum bpf_arg_type arg_type,\n+\t\t\t struct bpf_call_arg_meta *meta)\n {\n \tint spi, err = 0;\n \n@@ -7650,7 +7646,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat\n \t\t\t\"%s expected pointer to stack or const struct bpf_dynptr\\n\",\n \t\t\treg_arg_name(env, argno));\n \t\tbpf_diag_call_arg_fmt(\n-\t\t\tenv, insn_idx, argno, call_name,\n+\t\t\tenv, insn_idx, argno, meta-\u003efunc_name,\n \t\t\t\"Pass the address of a stack dynptr object, or use a const dynptr pointer returned by the verifier-supported path.\",\n \t\t\t\"a dynptr argument must be a pointer to a dynptr stack slot or a verifier-provided const struct bpf_dynptr, but %s is %s\",\n \t\t\treg_arg_name(env, argno), bpf_diag_reg_type_plain(env, reg-\u003etype));\n@@ -7678,7 +7674,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat\n \t\t\tverbose(env, \"Dynptr has to be an uninitialized dynptr\\n\");\n \t\t\tbpf_diag_res(\n \t\t\t\tenv, insn_idx, \"dynptr is already initialized\",\n-\t\t\t\t\"This kfunc constructs a dynptr and requires an uninitialized dynptr stack slot, but the selected slot already holds dynptr state.\",\n+\t\t\t\t\"This function constructs a dynptr and requires an uninitialized dynptr stack slot, but the selected slot already holds dynptr state.\",\n \t\t\t\t\"Use a fresh stack dynptr slot, or release/destroy the existing dynptr before reusing the slot.\");\n \t\t\treturn -EINVAL;\n \t\t}\n@@ -7691,7 +7687,8 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat\n \t\t\t\treturn err;\n \t\t}\n \n-\t\terr = mark_stack_slots_dynptr(env, reg, arg_type, insn_idx, ref_obj, dynptr);\n+\t\terr = mark_stack_slots_dynptr(env, reg, arg_type, insn_idx,\n+\t\t\t\t\t \u0026meta-\u003eref_obj, \u0026meta-\u003edynptr);\n \t} else /* OBJ_RELEASE and None case from above */ {\n \t\t/* For the reg-\u003etype == PTR_TO_STACK case, bpf_dynptr is never const */\n \t\tif (reg-\u003etype == CONST_PTR_TO_DYNPTR \u0026\u0026 (arg_type \u0026 OBJ_RELEASE)) {\n@@ -7721,7 +7718,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat\n \t\t\tverbose(env, \"Expected a dynptr of type %s as %s\\n\",\n \t\t\t\tdynptr_type_str(expected_type), reg_arg_name(env, argno));\n \t\t\tbpf_diag_call_arg_fmt(\n-\t\t\t\tenv, insn_idx, argno, call_name,\n+\t\t\t\tenv, insn_idx, argno, meta-\u003efunc_name,\n \t\t\t\t\"Use a dynptr constructor that matches this operation, or call an operation that accepts the dynptr's current type.\",\n \t\t\t\t\"the dynptr is initialized with backing object type %s, but this operation expects dynptr type %s\",\n \t\t\t\tdynptr_type_str(actual_type), dynptr_type_str(expected_type));\n@@ -7740,11 +7737,9 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat\n \t\t\treg = \u0026state-\u003estack[spi].spilled_ptr;\n \t\t}\n \n-\t\tif (dynptr) {\n-\t\t\tdynptr-\u003etype = reg-\u003edynptr.type;\n-\t\t\tdynptr-\u003eid = reg-\u003eid;\n-\t\t\tdynptr-\u003eparent_id = reg-\u003eparent_id;\n-\t\t}\n+\t\tmeta-\u003edynptr.type = reg-\u003edynptr.type;\n+\t\tmeta-\u003edynptr.id = reg-\u003eid;\n+\t\tmeta-\u003edynptr.parent_id = reg-\u003eparent_id;\n \t}\n \treturn err;\n }\n@@ -7808,8 +7803,8 @@ static int process_iter_arg(struct bpf_verifier_env *env, struct bpf_reg_state *\n \t\t\treg_arg_name(env, argno));\n \t\tbpf_diag_call_arg(\n \t\t\tenv, insn_idx, argno, meta-\u003efunc_name,\n-\t\t\t\"the kfunc expects a recognized iterator state pointer, but this argument does not match a valid iterator type\",\n-\t\t\t\"Pass the exact iterator state type expected by this kfunc.\");\n+\t\t\t\"the function expects a recognized iterator state pointer, but this argument does not match a valid iterator type\",\n+\t\t\t\"Pass the exact iterator state type expected by this function.\");\n \t\treturn -EINVAL;\n \t}\n \tt = btf_type_by_id(meta-\u003ebtf, btf_id);\n@@ -8133,9 +8128,43 @@ static bool arg_type_is_dynptr(enum bpf_arg_type type)\n \treturn base_type(type) == ARG_PTR_TO_DYNPTR;\n }\n \n+/*\n+ * An argument that only ever takes a scalar, so a zero register passed to it\n+ * is a value rather than a NULL pointer.\n+ */\n+static bool arg_type_is_scalar(enum bpf_arg_type type)\n+{\n+\tswitch (base_type(type)) {\n+\tcase ARG_SCALAR:\n+\tcase ARG_CONST_SCALAR:\n+\tcase ARG_MEM_SIZE:\n+\tcase ARG_MEM_SIZE_OR_ZERO:\n+\tcase ARG_CONST_MEM_SIZE:\n+\tcase ARG_CONST_ALLOC_SIZE_OR_ZERO:\n+\t\treturn true;\n+\tdefault:\n+\t\treturn false;\n+\t}\n+}\n+\n+/*\n+ * A kfunc is named by a BTF ID, which can take the same numeric value as an\n+ * enum bpf_func_id. Only test meta-\u003efunc_id against a BPF_FUNC_* once the call\n+ * is known to be to a helper; meta-\u003ebtf is set only for a kfunc.\n+ */\n+static bool is_helper_call(const struct bpf_call_arg_meta *meta, enum bpf_func_id func_id)\n+{\n+\treturn !meta-\u003ebtf \u0026\u0026 meta-\u003efunc_id == func_id;\n+}\n+\n+static bool is_kfunc_call(const struct bpf_call_arg_meta *meta, u32 btf_id)\n+{\n+\treturn meta-\u003ebtf \u0026\u0026 meta-\u003efunc_id == btf_id;\n+}\n+\n static int resolve_map_arg_type(struct bpf_verifier_env *env,\n-\t\t\t\t const struct bpf_call_arg_meta *meta,\n-\t\t\t\t enum bpf_arg_type *arg_type)\n+\t\t\t\tconst struct bpf_call_arg_meta *meta,\n+\t\t\t\tenum bpf_arg_type *arg_type)\n {\n \tif (!meta-\u003emap.ptr) {\n \t\t/* kernel subsystem misconfigured verifier */\n@@ -8154,7 +8183,7 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,\n \t\t}\n \t\tbreak;\n \tcase BPF_MAP_TYPE_BLOOM_FILTER:\n-\t\tif (meta-\u003efunc_id == BPF_FUNC_map_peek_elem)\n+\t\tif (is_helper_call(meta, BPF_FUNC_map_peek_elem))\n \t\t\t*arg_type = ARG_PTR_TO_MAP_VALUE;\n \t\tbreak;\n \tdefault:\n@@ -8163,6 +8192,48 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,\n \treturn 0;\n }\n \n+static int resolve_func_arg_type(struct bpf_verifier_env *env,\n+\t\t\t\t struct bpf_reg_state *reg, u32 arg,\n+\t\t\t\t struct bpf_call_arg_meta *meta,\n+\t\t\t\t enum bpf_arg_type *arg_type, u32 *arg_size);\n+static int process_arg_ptr_to_btf_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n+\t\t\t\t argno_t argno, enum bpf_arg_type arg_type,\n+\t\t\t\t const struct btf *arg_btf, u32 arg_btf_id,\n+\t\t\t\t struct bpf_call_arg_meta *meta, int insn_idx);\n+static bool is_kfunc_arg_nonown_allowed(const struct btf *btf,\n+\t\t\t\t\tconst struct btf_param *arg);\n+static bool is_kfunc_arg_scalar_with_name(const struct btf *btf,\n+\t\t\t\t\t const struct btf_param *arg,\n+\t\t\t\t\t const char *name);\n+static bool is_bpf_cast_to_kern_ctx_kfunc(const struct bpf_call_arg_meta *meta);\n+static bool is_bpf_dynptr_clone_kfunc(const struct bpf_call_arg_meta *meta);\n+static bool is_bpf_iter_css_task_new_kfunc(const struct bpf_call_arg_meta *meta);\n+static bool is_bpf_obj_drop_kfunc(u32 func_id);\n+static bool is_bpf_percpu_obj_drop_kfunc(u32 func_id);\n+static bool is_bpf_rbtree_add_kfunc(u32 func_id);\n+static int get_bpf_res_spin_lock_kfunc_flags(const struct bpf_call_arg_meta *meta);\n+static struct bpf_insn_aux_data *cur_aux(const struct bpf_verifier_env *env);\n+static int process_irq_flag(struct bpf_verifier_env *env,\n+\t\t\t struct bpf_reg_state *reg, argno_t argno,\n+\t\t\t struct bpf_call_arg_meta *meta);\n+static int process_kf_arg_ptr_to_list_head(struct bpf_verifier_env *env,\n+\t\t\t\t\t struct bpf_reg_state *reg,\n+\t\t\t\t\t argno_t argno,\n+\t\t\t\t\t struct bpf_call_arg_meta *meta);\n+static int process_kf_arg_ptr_to_rbtree_root(struct bpf_verifier_env *env,\n+\t\t\t\t\t struct bpf_reg_state *reg,\n+\t\t\t\t\t argno_t argno,\n+\t\t\t\t\t struct bpf_call_arg_meta *meta);\n+static int process_kf_arg_ptr_to_list_node(struct bpf_verifier_env *env,\n+\t\t\t\t\t struct bpf_reg_state *reg,\n+\t\t\t\t\t argno_t argno,\n+\t\t\t\t\t struct bpf_call_arg_meta *meta);\n+static int process_kf_arg_ptr_to_rbtree_node(struct bpf_verifier_env *env,\n+\t\t\t\t\t struct bpf_reg_state *reg,\n+\t\t\t\t\t argno_t argno,\n+\t\t\t\t\t struct bpf_call_arg_meta *meta);\n+static bool check_css_task_iter_allowlist(struct bpf_verifier_env *env);\n+\n struct bpf_reg_types {\n \tconst enum bpf_reg_type types[10];\n \tu32 *btf_id;\n@@ -8206,7 +8277,7 @@ static const struct bpf_reg_types mem_types = {\n \t},\n };\n \n-static const struct bpf_reg_types spin_lock_types = {\n+static const struct bpf_reg_types map_value_or_alloc_obj_types = {\n \t.types = {\n \t\tPTR_TO_MAP_VALUE,\n \t\tPTR_TO_BTF_ID | MEM_ALLOC,\n@@ -8235,7 +8306,29 @@ static const struct bpf_reg_types percpu_btf_ptr_types = {\n static const struct bpf_reg_types func_ptr_types = { .types = { PTR_TO_FUNC } };\n static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK } };\n static const struct bpf_reg_types const_str_ptr_types = { .types = { PTR_TO_MAP_VALUE } };\n-static const struct bpf_reg_types timer_types = { .types = { PTR_TO_MAP_VALUE } };\n+static const struct bpf_reg_types map_value_types = { .types = { PTR_TO_MAP_VALUE } };\n+static const struct bpf_reg_types arena_types = {\n+\t.types = {\n+\t\tPTR_TO_ARENA,\n+\t\tSCALAR_VALUE,\n+\t}\n+};\n+\n+static const struct bpf_reg_types alloc_obj_types = {\n+\t.types = {\n+\t\tPTR_TO_BTF_ID | MEM_ALLOC,\n+\t\tPTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU,\n+\t}\n+};\n+\n+static const struct bpf_reg_types alloc_obj_or_non_own_ref_types = {\n+\t.types = {\n+\t\tPTR_TO_BTF_ID | MEM_ALLOC,\n+\t\tPTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF,\n+\t\tPTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU,\n+\t}\n+};\n+\n static const struct bpf_reg_types kptr_xchg_dest_types = {\n \t.types = {\n \t\tPTR_TO_MAP_VALUE,\n@@ -8265,16 +8358,32 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {\n #endif\n \t[ARG_PTR_TO_SOCKET]\t\t= \u0026fullsock_types,\n \t[ARG_PTR_TO_BTF_ID]\t\t= \u0026btf_ptr_types,\n-\t[ARG_PTR_TO_SPIN_LOCK]\t\t= \u0026spin_lock_types,\n+\t[ARG_PTR_TO_SPIN_LOCK]\t\t= \u0026map_value_or_alloc_obj_types,\n \t[ARG_PTR_TO_MEM]\t\t= \u0026mem_types,\n \t[ARG_PTR_TO_RINGBUF_MEM]\t= \u0026ringbuf_mem_types,\n \t[ARG_PTR_TO_PERCPU_BTF_ID]\t= \u0026percpu_btf_ptr_types,\n \t[ARG_PTR_TO_FUNC]\t\t= \u0026func_ptr_types,\n \t[ARG_PTR_TO_STACK]\t\t= \u0026stack_ptr_types,\n \t[ARG_PTR_TO_CONST_STR]\t\t= \u0026const_str_ptr_types,\n-\t[ARG_PTR_TO_TIMER]\t\t= \u0026timer_types,\n+\t[ARG_PTR_TO_TIMER]\t\t= \u0026map_value_types,\n \t[ARG_KPTR_XCHG_DEST]\t\t= \u0026kptr_xchg_dest_types,\n \t[ARG_PTR_TO_DYNPTR]\t\t= \u0026dynptr_types,\n+\t/* Argument kinds only a kfunc can have. */\n+\t[ARG_SCALAR]\t\t\t= \u0026scalar_types,\n+\t[ARG_CONST_SCALAR]\t\t= \u0026scalar_types,\n+\t[ARG_CONST_MEM_SIZE]\t\t= \u0026scalar_types,\n+\t[ARG_PTR_TO_ALLOC_BTF_ID]\t= \u0026alloc_obj_types,\n+\t[ARG_PTR_TO_REFCOUNTED_KPTR]\t= \u0026alloc_obj_or_non_own_ref_types,\n+\t[ARG_PTR_TO_ITER]\t\t= \u0026stack_ptr_types,\n+\t[ARG_PTR_TO_LIST_HEAD]\t\t= \u0026map_value_or_alloc_obj_types,\n+\t[ARG_PTR_TO_LIST_NODE]\t\t= \u0026alloc_obj_or_non_own_ref_types,\n+\t[ARG_PTR_TO_RB_ROOT]\t\t= \u0026map_value_or_alloc_obj_types,\n+\t[ARG_PTR_TO_RB_NODE]\t\t= \u0026alloc_obj_or_non_own_ref_types,\n+\t[ARG_PTR_TO_RES_SPIN_LOCK]\t= \u0026map_value_or_alloc_obj_types,\n+\t[ARG_PTR_TO_WORKQUEUE]\t\t= \u0026map_value_types,\n+\t[ARG_PTR_TO_TASK_WORK]\t\t= \u0026map_value_types,\n+\t[ARG_PTR_TO_IRQ_FLAG]\t\t= \u0026stack_ptr_types,\n+\t[ARG_PTR_TO_ARENA]\t\t= \u0026arena_types,\n };\n \n static void bpf_diag_call_arg(struct bpf_verifier_env *env, u32 insn_idx, argno_t argno,\n@@ -8314,6 +8423,71 @@ __printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u\n \tbpf_diag_call_arg(env, insn_idx, argno, call_name, reason, suggestion);\n }\n \n+static int check_func_arg_nullability(struct bpf_verifier_env *env,\n+\t\t\t\t struct bpf_reg_state *reg, argno_t argno,\n+\t\t\t\t enum bpf_arg_type arg_type,\n+\t\t\t\t struct bpf_call_arg_meta *meta, int insn_idx)\n+{\n+\tconst char *expected_type = \"pointer\";\n+\n+\tif (arg_type_is_scalar(arg_type) || type_may_be_null(arg_type) ||\n+\t (!bpf_register_is_null(reg) \u0026\u0026 !type_may_be_null(reg-\u003etype)))\n+\t\treturn 0;\n+\n+\tif (meta-\u003ebtf) {\n+\t\tu32 arg_btf_id;\n+\n+\t\targ_btf_id = btf_params(meta-\u003efunc_proto)[arg_idx_from_argno(argno)].type;\n+\t\texpected_type = bpf_diag_fmt(env, \"value of type %s\",\n+\t\t\t\t\t bpf_diag_fmt_btf_type(env, meta-\u003ebtf, arg_btf_id));\n+\t}\n+\n+\tverbose(env, \"Possibly NULL pointer passed to trusted %s\\n\",\n+\t\treg_arg_name(env, argno));\n+\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t \"Add a NULL check and make the call only on the non-NULL path.\",\n+\t\t\t \"the pointer may be NULL, but this call requires a non-NULL %s\",\n+\t\t\t expected_type);\n+\treturn -EACCES;\n+}\n+\n+static int check_func_arg_release(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n+\t\t\t\t argno_t argno, enum bpf_arg_type arg_type,\n+\t\t\t\t struct bpf_call_arg_meta *meta, int insn_idx)\n+{\n+\tconst char *expected_type = \"pointer\";\n+\n+\tif (!arg_type_is_release(arg_type))\n+\t\treturn 0;\n+\n+\tif (arg_type_is_dynptr(arg_type) || reg_is_referenced(env, reg) ||\n+\t bpf_register_is_null(reg))\n+\t\treturn 0;\n+\n+\tverbose(env, \"release function %s expects referenced PTR_TO_BTF_ID passed to %s\\n\",\n+\t\tmeta-\u003efunc_name, reg_arg_name(env, argno));\n+\n+\tif (meta-\u003ebtf) {\n+\t\tconst struct btf_param *btf_arg;\n+\t\tconst struct btf_type *t;\n+\t\tu32 ref_id;\n+\n+\t\tbtf_arg = \u0026btf_params(meta-\u003efunc_proto)[arg_idx_from_argno(argno)];\n+\t\tref_id = btf_arg-\u003etype;\n+\t\tt = btf_type_skip_modifiers(meta-\u003ebtf, btf_arg-\u003etype, NULL);\n+\t\tif (btf_type_is_ptr(t))\n+\t\t\tbtf_type_skip_modifiers(meta-\u003ebtf, t-\u003etype, \u0026ref_id);\n+\t\texpected_type = bpf_diag_fmt(env, \"value of type %s\",\n+\t\t\t\t\t bpf_diag_fmt_btf_type(env, meta-\u003ebtf, ref_id));\n+\t}\n+\n+\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t bpf_diag_fmt(env, \"Pass the resource-owning %s returned by the matching acquire call, or avoid the release function after ownership has already been transferred or released.\",\n+\t\t\t\t\t expected_type),\n+\t\t\t \"release functions require a value that owns a live resource returned by a matching acquire function\");\n+\treturn -EINVAL;\n+}\n+\n static const char *bpf_diag_expected_reg_types(struct bpf_verifier_env *env,\n \t\t\t\t\t const enum bpf_reg_type *types, int count)\n {\n@@ -8335,19 +8509,21 @@ static const char *bpf_diag_expected_reg_types(struct bpf_verifier_env *env,\n }\n \n static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *reg, argno_t argno,\n-\t\t\t enum bpf_arg_type arg_type, const u32 *arg_btf_id,\n-\t\t\t struct bpf_call_arg_meta *meta, const char *call_name)\n+\t\t\t enum bpf_arg_type arg_type, struct bpf_call_arg_meta *meta)\n {\n \tenum bpf_reg_type expected, type = reg-\u003etype;\n \tconst struct bpf_reg_types *compatible;\n \tconst char *actual, *accepted;\n-\tint i, j, err;\n+\tint i, j;\n \n \tcompatible = compatible_reg_types[base_type(arg_type)];\n \tif (!compatible) {\n \t\tverifier_bug(env, \"unsupported arg type %d\", arg_type);\n \t\treturn -EFAULT;\n \t}\n+\tif (meta-\u003ebtf \u0026\u0026 base_type(arg_type) == ARG_PTR_TO_BTF_ID \u0026\u0026\n+\t (base_type(type) == PTR_TO_BTF_ID || reg2btf_ids[base_type(type)]))\n+\t\tgoto found;\n \n \t/* ARG_PTR_TO_MEM + RDONLY is compatible with PTR_TO_MEM and PTR_TO_MEM + RDONLY,\n \t * but ARG_PTR_TO_MEM is compatible only with PTR_TO_MEM and NOT with PTR_TO_MEM + RDONLY\n@@ -8369,7 +8545,8 @@ static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *re\n \t\ttype \u0026= ~DYNPTR_TYPE_FLAG_MASK;\n \n \t/* Local kptr types are allowed as the source argument of bpf_kptr_xchg */\n-\tif (meta-\u003efunc_id == BPF_FUNC_kptr_xchg \u0026\u0026 type_is_alloc(type) \u0026\u0026 reg_from_argno(argno) == BPF_REG_2) {\n+\tif (is_helper_call(meta, BPF_FUNC_kptr_xchg) \u0026\u0026 type_is_alloc(type) \u0026\u0026\n+\t reg_from_argno(argno) == BPF_REG_2) {\n \t\ttype \u0026= ~MEM_ALLOC;\n \t\ttype \u0026= ~MEM_PERCPU;\n \t}\n@@ -8389,115 +8566,13 @@ static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *re\n \tverbose(env, \"%s\\n\", reg_type_str(env, compatible-\u003etypes[j]));\n \tactual = bpf_diag_fmt(env, \"%s\", reg_type_str(env, reg-\u003etype));\n \taccepted = bpf_diag_expected_reg_types(env, compatible-\u003etypes, i);\n-\tbpf_diag_call_arg_fmt(env, env-\u003einsn_idx, argno, call_name,\n-\t\t\t \"Pass a value with one of the accepted pointer or scalar types for this call.\",\n+\tbpf_diag_call_arg_fmt(env, env-\u003einsn_idx, argno, meta-\u003efunc_name,\n+\t\t\t bpf_diag_fmt(env, \"Pass %s.\", bpf_diag_arg_type_plain(arg_type)),\n \t\t\t \"it has type %s, but this argument accepts %s\",\n \t\t\t actual, accepted);\n \treturn -EACCES;\n \n found:\n-\tif (base_type(reg-\u003etype) != PTR_TO_BTF_ID)\n-\t\treturn 0;\n-\n-\tif (compatible == \u0026mem_types) {\n-\t\tif (!(arg_type \u0026 MEM_RDONLY)) {\n-\t\t\tverbose(env,\n-\t\t\t\t\"%s() may write into memory pointed by %s type=%s\\n\",\n-\t\t\t\tfunc_id_name(meta-\u003efunc_id),\n-\t\t\t\treg_arg_name(env, argno), reg_type_str(env, reg-\u003etype));\n-\t\t\treturn -EACCES;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\n-\tswitch ((int)reg-\u003etype) {\n-\tcase PTR_TO_BTF_ID:\n-\tcase PTR_TO_BTF_ID | PTR_TRUSTED:\n-\tcase PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL:\n-\tcase PTR_TO_BTF_ID | MEM_RCU:\n-\tcase PTR_TO_BTF_ID | PTR_MAYBE_NULL:\n-\tcase PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU:\n-\t{\n-\t\t/* For bpf_sk_release, it needs to match against first member\n-\t\t * 'struct sock_common', hence make an exception for it. This\n-\t\t * allows bpf_sk_release to work for multiple socket types.\n-\t\t */\n-\t\tbool strict_type_match = arg_type_is_release(arg_type) \u0026\u0026\n-\t\t\t\t\t meta-\u003efunc_id != BPF_FUNC_sk_release;\n-\n-\t\tif (type_may_be_null(reg-\u003etype) \u0026\u0026\n-\t\t (!type_may_be_null(arg_type) || arg_type_is_release(arg_type))) {\n-\t\t\tverbose(env, \"Possibly NULL pointer passed to helper %s\\n\",\n-\t\t\t\treg_arg_name(env, argno));\n-\t\t\tbpf_diag_call_arg(\n-\t\t\t\tenv, env-\u003einsn_idx, argno, call_name,\n-\t\t\t\t\"the pointer may be NULL, but this call requires a non-NULL pointer\",\n-\t\t\t\t\"Add a NULL check and make the call only on the non-NULL path.\");\n-\t\t\treturn -EACCES;\n-\t\t}\n-\n-\t\tif (!arg_btf_id) {\n-\t\t\tif (!compatible-\u003ebtf_id) {\n-\t\t\t\tverifier_bug(env, \"missing arg compatible BTF ID\");\n-\t\t\t\treturn -EFAULT;\n-\t\t\t}\n-\t\t\targ_btf_id = compatible-\u003ebtf_id;\n-\t\t}\n-\n-\t\tif (meta-\u003efunc_id == BPF_FUNC_kptr_xchg) {\n-\t\t\tif (map_kptr_match_type(env, meta-\u003ekptr_field, reg, reg_from_argno(argno)))\n-\t\t\t\treturn -EACCES;\n-\t\t} else {\n-\t\t\tif (arg_btf_id == BPF_PTR_POISON) {\n-\t\t\t\tverbose(env, \"verifier internal error:\");\n-\t\t\t\tverbose(env, \"%s has non-overwritten BPF_PTR_POISON type\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\treturn -EACCES;\n-\t\t\t}\n-\n-\t\t\terr = __check_ptr_off_reg(env, reg, argno, true);\n-\t\t\tif (err)\n-\t\t\t\treturn err;\n-\n-\t\t\tif (!btf_struct_ids_match(\u0026env-\u003elog, reg-\u003ebtf, reg-\u003ebtf_id,\n-\t\t\t\t\t\t reg-\u003evar_off.value, btf_vmlinux, *arg_btf_id,\n-\t\t\t\t\t\t strict_type_match, !type_is_alloc(reg-\u003etype))) {\n-\t\t\t\tverbose(env, \"%s is of type %s but %s is expected\\n\",\n-\t\t\t\t\treg_arg_name(env, argno),\n-\t\t\t\t\tbtf_type_name(reg-\u003ebtf, reg-\u003ebtf_id),\n-\t\t\t\t\tbtf_type_name(btf_vmlinux, *arg_btf_id));\n-\t\t\t\treturn -EACCES;\n-\t\t\t}\n-\t\t}\n-\t\tbreak;\n-\t}\n-\tcase PTR_TO_BTF_ID | MEM_ALLOC:\n-\tcase PTR_TO_BTF_ID | MEM_PERCPU | MEM_ALLOC:\n-\tcase PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF:\n-\tcase PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU:\n-\t\tif (meta-\u003efunc_id != BPF_FUNC_spin_lock \u0026\u0026 meta-\u003efunc_id != BPF_FUNC_spin_unlock \u0026\u0026\n-\t\t meta-\u003efunc_id != BPF_FUNC_kptr_xchg) {\n-\t\t\tverifier_bug(env, \"unimplemented handling of MEM_ALLOC\");\n-\t\t\treturn -EFAULT;\n-\t\t}\n-\t\t/* Check if local kptr in src arg matches kptr in dst arg */\n-\t\tif (meta-\u003efunc_id == BPF_FUNC_kptr_xchg) {\n-\t\t\tint regno = reg_from_argno(argno);\n-\n-\t\t\tif (regno == BPF_REG_2 \u0026\u0026\n-\t\t\t map_kptr_match_type(env, meta-\u003ekptr_field, reg, regno))\n-\t\t\t\treturn -EACCES;\n-\t\t}\n-\t\tbreak;\n-\tcase PTR_TO_BTF_ID | MEM_PERCPU:\n-\tcase PTR_TO_BTF_ID | MEM_PERCPU | MEM_RCU:\n-\tcase PTR_TO_BTF_ID | MEM_PERCPU | PTR_TRUSTED:\n-\t\t/* Handled by helper specific checks */\n-\t\tbreak;\n-\tdefault:\n-\t\tverifier_bug(env, \"invalid PTR_TO_BTF_ID register for type match\");\n-\t\treturn -EFAULT;\n-\t}\n \treturn 0;\n }\n \n@@ -8518,10 +8593,9 @@ reg_find_field_offset(const struct bpf_reg_state *reg, s32 off, u32 fields)\n \treturn field;\n }\n \n-static int __check_func_arg_reg_off(struct bpf_verifier_env *env,\n-\t\t\t\t const struct bpf_reg_state *reg, argno_t argno,\n-\t\t\t\t enum bpf_arg_type arg_type,\n-\t\t\t\t bool btf_id_fixed_off_ok)\n+static int check_func_arg_reg_off(struct bpf_verifier_env *env,\n+\t\t\t\t const struct bpf_reg_state *reg, argno_t argno,\n+\t\t\t\t enum bpf_arg_type arg_type)\n {\n \tu32 type = reg-\u003etype;\n \n@@ -8577,12 +8651,15 @@ static int __check_func_arg_reg_off(struct bpf_verifier_env *env,\n \tcase PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF:\n \tcase PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU:\n \t\t/* When referenced PTR_TO_BTF_ID is passed to release function,\n-\t\t * its fixed offset must be 0. In the other cases, fixed offset\n-\t\t * can be non-zero unless the caller requires otherwise.\n-\t\t * var_off always must be 0 for PTR_TO_BTF_ID, hence we still\n-\t\t * need to do checks instead of returning.\n+\t\t * its fixed offset must be 0. bpf_refcount_acquire() returns the\n+\t\t * pointer it was given while incrementing the refcount at the\n+\t\t * refcount field offset, so it needs a zero offset too. In the\n+\t\t * other cases, fixed offset can be non-zero. var_off always must\n+\t\t * be 0 for PTR_TO_BTF_ID, hence we still need to do checks\n+\t\t * instead of returning.\n \t\t */\n-\t\treturn __check_ptr_off_reg(env, reg, argno, btf_id_fixed_off_ok);\n+\t\treturn __check_ptr_off_reg(env, reg, argno,\n+\t\t\t\t\t base_type(arg_type) != ARG_PTR_TO_REFCOUNTED_KPTR);\n \tcase PTR_TO_CTX:\n \t\t/*\n \t\t * Allow fixed and variable offsets for syscall context, but\n@@ -8598,13 +8675,6 @@ static int __check_func_arg_reg_off(struct bpf_verifier_env *env,\n \t}\n }\n \n-static int check_func_arg_reg_off(struct bpf_verifier_env *env,\n-\t\t\t\t const struct bpf_reg_state *reg, argno_t argno,\n-\t\t\t\t enum bpf_arg_type arg_type)\n-{\n-\treturn __check_func_arg_reg_off(env, reg, argno, arg_type, true);\n-}\n-\n static int check_arg_const_str(struct bpf_verifier_env *env,\n \t\t\t struct bpf_reg_state *reg, argno_t argno)\n {\n@@ -8770,57 +8840,53 @@ 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 int insn_idx)\n {\n+\tconst struct btf_param *btf_arg = meta-\u003ebtf ? \u0026btf_params(meta-\u003efunc_proto)[arg] : NULL;\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+\tstruct bpf_func_state *caller = cur_func(env);\n+\tstruct bpf_reg_state *regs = cur_regs(env);\n+\targno_t argno = argno_from_arg(arg + 1);\n+\tstruct bpf_reg_state *reg = get_func_arg_reg(caller, regs, arg);\n \tenum bpf_arg_type arg_type = fn-\u003earg_type[arg];\n-\targno_t argno = argno_from_reg(regno);\n-\tenum bpf_reg_type type = reg-\u003etype;\n-\tu32 *arg_btf_id = NULL;\n+\tint regno = reg_from_argno(argno);\n+\tu32 arg_size = arg_type \u0026 MEM_FIXED_SIZE ? fn-\u003earg_size[arg] : 0;\n \tu32 key_size;\n \tint err = 0;\n \n-\tif (arg_type == ARG_DONTCARE)\n+\tif (arg_type == ARG_PTR_TO_PROG_AUX) {\n+\t\tcur_aux(env)-\u003earg_prog = regno;\n+\t\treturn 0;\n+\t}\n+\tif (arg_type == ARG_IGNORE)\n \t\treturn 0;\n \n-\terr = check_reg_arg(env, regno, SRC_OP);\n-\tif (err)\n-\t\treturn err;\n+\tif (regno \u003e= 0) {\n+\t\terr = check_reg_arg(env, regno, SRC_OP);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n \n-\tif (arg_type == ARG_ANYTHING) {\n-\t\tif (is_pointer_value(env, regno)) {\n-\t\t\tverbose(env, \"R%d leaks addr into helper function\\n\",\n-\t\t\t\tregno);\n+\t/* Preserve the legacy helper behavior for privileged pointer leaks. */\n+\tif (!meta-\u003ebtf \u0026\u0026 arg_type == ARG_SCALAR) {\n+\t\tif (__is_pointer_value(env-\u003eallow_ptr_leaks, reg)) {\n+\t\t\tverbose(env, \"%s leaks addr into helper function\\n\",\n+\t\t\t\treg_arg_name(env, argno));\n \t\t\treturn -EACCES;\n \t\t}\n \t\treturn 0;\n \t}\n \n-\tif (type_is_pkt_pointer(type) \u0026\u0026\n-\t !may_access_direct_pkt_data(env, fn, BPF_READ)) {\n-\t\tverbose(env, \"helper access to the packet is not allowed\\n\");\n-\t\treturn -EACCES;\n-\t}\n-\n-\tif (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE) {\n-\t\terr = resolve_map_arg_type(env, meta, \u0026arg_type);\n-\t\tif (err)\n-\t\t\treturn err;\n-\t}\n+\terr = resolve_func_arg_type(env, reg, arg, meta, \u0026arg_type, \u0026arg_size);\n+\tif (err)\n+\t\treturn err;\n \n \tif (bpf_register_is_null(reg) \u0026\u0026 type_may_be_null(arg_type))\n-\t\t/* A NULL register has a SCALAR_VALUE type, so skip\n-\t\t * type checking.\n-\t\t */\n-\t\tgoto skip_type_check;\n+\t\treturn 0;\n \n-\t/* arg_btf_id and arg_size are in a union. */\n-\tif (base_type(arg_type) == ARG_PTR_TO_BTF_ID ||\n-\t base_type(arg_type) == ARG_PTR_TO_SPIN_LOCK)\n-\t\targ_btf_id = fn-\u003earg_btf_id[arg];\n+\terr = check_func_arg_nullability(env, reg, argno, arg_type, meta, insn_idx);\n+\tif (err)\n+\t\treturn err;\n \n-\terr = check_reg_type(env, reg, argno, arg_type, arg_btf_id, meta,\n-\t\t\t func_id_name(meta-\u003efunc_id));\n+\terr = check_reg_type(env, reg, argno, arg_type, meta);\n \tif (err)\n \t\treturn err;\n \n@@ -8828,22 +8894,27 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \tif (err)\n \t\treturn err;\n \n-skip_type_check:\n-\tif (arg_type_is_release(arg_type) \u0026\u0026 !arg_type_is_dynptr(arg_type) \u0026\u0026\n-\t !reg_is_referenced(env, reg) \u0026\u0026 !bpf_register_is_null(reg)) {\n-\t\tverbose(env, \"release helper %s expects referenced PTR_TO_BTF_ID passed to %s\\n\",\n-\t\t\tfunc_id_name(meta-\u003efunc_id), reg_arg_name(env, argno));\n-\t\tbpf_diag_call_arg(\n-\t\t\tenv, insn_idx, argno, func_id_name(meta-\u003efunc_id),\n-\t\t\t\"release helpers require a value that owns a live resource returned by a matching acquire helper\",\n-\t\t\t\"Pass the resource-owning pointer returned by the matching acquire helper, and avoid calling the release helper after ownership has already been transferred or released.\");\n-\t\treturn -EINVAL;\n-\t}\n+\terr = check_func_arg_release(env, reg, argno, arg_type, meta, insn_idx);\n+\tif (err)\n+\t\treturn err;\n \n \tif (reg_is_referenced(env, reg))\n \t\tupdate_ref_obj(\u0026meta-\u003eref_obj, reg);\n \n \tswitch (base_type(arg_type)) {\n+\tcase ARG_CONST_SCALAR:\n+\t\terr = process_const_arg(env, reg, argno, meta);\n+\t\tif (err \u003c 0) {\n+\t\t\tif (err == -EINVAL)\n+\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\t \"Pass a compile-time constant or a value the verifier can prove is constant at this call.\",\n+\t\t\t\t\t\t \"the function requires this scalar argument to be a verifier-known constant, but %s is variable on this path\",\n+\t\t\t\t\t\t reg_arg_name(env, argno));\n+\t\t\treturn err;\n+\t\t}\n+\t\tbreak;\n+\tcase ARG_SCALAR:\n+\t\tbreak;\n \tcase ARG_CONST_MAP_PTR:\n \t\t/* bpf_map_xxx(map_ptr) call: remember that map_ptr */\n \t\terr = process_map_ptr_arg(env, reg, argno, meta);\n@@ -8865,7 +8936,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \t\t\treturn -EFAULT;\n \t\t}\n \t\tkey_size = meta-\u003emap.ptr-\u003ekey_size;\n-\t\terr = check_helper_mem_access(env, reg, argno, key_size, BPF_READ, false, NULL,\n+\t\terr = check_helper_mem_access(env, reg, argno, key_size, BPF_READ, false, meta,\n \t\t\t\t\t NULL);\n \t\tif (err)\n \t\t\treturn err;\n@@ -8897,7 +8968,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \t\t * Disable raw mode for bpf_map_peek_elem() on a bloom filter. The helper reads\n \t\t * the value buffer as an input rather than filling it.\n \t\t */\n-\t\tif (meta-\u003efunc_id == BPF_FUNC_map_peek_elem \u0026\u0026\n+\t\tif (is_helper_call(meta, BPF_FUNC_map_peek_elem) \u0026\u0026\n \t\t meta-\u003emap.ptr-\u003emap_type == BPF_MAP_TYPE_BLOOM_FILTER)\n \t\t\tmeta-\u003earg_raw_mem.regno = 0;\n \n@@ -8905,9 +8976,80 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \t\t\t\t\t arg_type \u0026 MEM_WRITE ? BPF_WRITE : BPF_READ,\n \t\t\t\t\t false, meta, NULL);\n \t\tbreak;\n+\tcase ARG_PTR_TO_BTF_ID:\n+\tcase ARG_PTR_TO_BTF_ID_SOCK_COMMON:\n+\t{\n+\t\tconst u32 *arg_btf_id = fn-\u003earg_btf_id[arg];\n+\t\tconst struct btf *arg_btf = meta-\u003ebtf ?: btf_vmlinux;\n+\n+\t\tif (!meta-\u003ebtf) {\n+\t\t\tconst struct bpf_reg_types *compatible;\n+\n+\t\t\tif (base_type(reg-\u003etype) != PTR_TO_BTF_ID)\n+\t\t\t\tbreak;\n+\n+\t\t\tif (is_helper_call(meta, BPF_FUNC_kptr_xchg))\n+\t\t\t\treturn map_kptr_match_type(env, meta-\u003ekptr_field, reg, regno) ?\n+\t\t\t\t -EACCES : 0;\n+\n+\t\t\tif (!arg_btf_id) {\n+\t\t\t\tcompatible = compatible_reg_types[base_type(arg_type)];\n+\t\t\t\tif (!compatible-\u003ebtf_id) {\n+\t\t\t\t\tverifier_bug(env, \"missing arg compatible BTF ID\");\n+\t\t\t\t\treturn -EFAULT;\n+\t\t\t\t}\n+\t\t\t\targ_btf_id = compatible-\u003ebtf_id;\n+\t\t\t}\n+\t\t\tif (arg_btf_id == BPF_PTR_POISON) {\n+\t\t\t\tverbose(env, \"verifier internal error:\");\n+\t\t\t\tverbose(env, \"%s has non-overwritten BPF_PTR_POISON type\\n\",\n+\t\t\t\t\treg_arg_name(env, argno));\n+\t\t\t\treturn -EACCES;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (meta-\u003ebtf \u0026\u0026 (!is_trusted_reg(env, reg) ||\n+\t\t\t\t bpf_type_has_unsafe_modifiers(reg-\u003etype))) {\n+\t\t\tif (!(arg_type \u0026 MEM_RCU)) {\n+\t\t\t\tconst char *actual_type, *arg_name, *expected_type;\n+\n+\t\t\t\texpected_type = bpf_diag_fmt_btf_type(env, arg_btf, *arg_btf_id);\n+\t\t\t\tverbose(env, \"%s must be referenced or trusted\\n\",\n+\t\t\t\t\treg_arg_name(env, argno));\n+\t\t\t\targ_name = reg_arg_name(env, argno);\n+\t\t\t\tactual_type = bpf_diag_reg_type_plain(env, reg-\u003etype);\n+\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\t \"Pass a pointer acquired from a verifier-tracked source, or call this function only inside the required protection if it accepts RCU pointers.\",\n+\t\t\t\t\t\t \"the function requires a trusted or resource-owning pointer to %s, but %s is %s\",\n+\t\t\t\t\t\t expected_type, arg_name, actual_type);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\tif (!is_rcu_reg(reg)) {\n+\t\t\t\tconst char *actual_type, *arg_name, *expected_type;\n+\n+\t\t\t\texpected_type = bpf_diag_fmt_btf_type(env, arg_btf, *arg_btf_id);\n+\t\t\t\tverbose(env, \"%s must be a rcu pointer\\n\",\n+\t\t\t\t\treg_arg_name(env, argno));\n+\t\t\t\targ_name = reg_arg_name(env, argno);\n+\t\t\t\tactual_type = bpf_diag_reg_type_plain(env, reg-\u003etype);\n+\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\t \"Use this function with a pointer that is valid in an RCU read lock region.\",\n+\t\t\t\t\t\t \"the function requires an RCU-protected pointer to %s, but %s is %s\",\n+\t\t\t\t\t\t expected_type, arg_name, actual_type);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\n+\t\terr = process_arg_ptr_to_btf_id(env, reg, argno, arg_type, arg_btf,\n+\t\t\t\t\t\t*arg_btf_id, meta, insn_idx);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\t}\n \tcase ARG_PTR_TO_PERCPU_BTF_ID:\n \t\tif (!reg-\u003ebtf_id) {\n-\t\t\tverbose(env, \"Helper has invalid btf_id in R%d\\n\", regno);\n+\t\t\tverbose(env, \"Helper has invalid btf_id in %s\\n\",\n+\t\t\t\treg_arg_name(env, argno));\n \t\t\treturn -EACCES;\n \t\t}\n \t\tmeta-\u003eret_btf = reg-\u003ebtf;\n@@ -8918,11 +9060,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \t\t\tverbose(env, \"can't spin_{lock,unlock} in rbtree cb\\n\");\n \t\t\treturn -EACCES;\n \t\t}\n-\t\tif (meta-\u003efunc_id == BPF_FUNC_spin_lock) {\n+\t\tif (is_helper_call(meta, BPF_FUNC_spin_lock)) {\n \t\t\terr = process_spin_lock(env, reg, argno, PROCESS_SPIN_LOCK);\n \t\t\tif (err)\n \t\t\t\treturn err;\n-\t\t} else if (meta-\u003efunc_id == BPF_FUNC_spin_unlock) {\n+\t\t} else if (is_helper_call(meta, BPF_FUNC_spin_unlock)) {\n \t\t\terr = process_spin_lock(env, reg, argno, 0);\n \t\t\tif (err)\n \t\t\t\treturn err;\n@@ -8936,45 +9078,273 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \t\tif (err)\n \t\t\treturn err;\n \t\tbreak;\n+\tcase ARG_PTR_TO_CTX:\n+\t\tif (is_bpf_cast_to_kern_ctx_kfunc(meta)) {\n+\t\t\terr = get_kern_ctx_btf_id(\u0026env-\u003elog, resolve_prog_type(env-\u003eprog));\n+\t\t\tif (err \u003c 0)\n+\t\t\t\treturn -EINVAL;\n+\t\t\tmeta-\u003eret_btf_id = err;\n+\t\t}\n+\t\tbreak;\n+\tcase ARG_PTR_TO_ARENA:\n+\t\tbreak;\n+\tcase ARG_PTR_TO_ALLOC_BTF_ID:\n+\t\tif (reg-\u003etype == (PTR_TO_BTF_ID | MEM_ALLOC)) {\n+\t\t\tif (!is_bpf_obj_drop_kfunc(meta-\u003efunc_id)) {\n+\t\t\t\tverbose(env, \"%s expected for bpf_obj_drop()\\n\",\n+\t\t\t\t\treg_arg_name(env, argno));\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t} else if (reg-\u003etype == (PTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU)) {\n+\t\t\tif (!is_bpf_percpu_obj_drop_kfunc(meta-\u003efunc_id)) {\n+\t\t\t\tverbose(env, \"%s expected for bpf_percpu_obj_drop()\\n\",\n+\t\t\t\t\treg_arg_name(env, argno));\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\t\tif (!reg_is_referenced(env, reg)) {\n+\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n+\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t \"Pass the owned object pointer before it is released or transferred.\",\n+\t\t\t\t\t \"the allocated object pointer in %s must still carry verifier-tracked ownership, but this pointer no longer owns a live resource\",\n+\t\t\t\t\t reg_arg_name(env, argno));\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tif (meta-\u003ebtf == btf_vmlinux) {\n+\t\t\tmeta-\u003earg_btf = reg-\u003ebtf;\n+\t\t\tmeta-\u003earg_btf_id = reg-\u003ebtf_id;\n+\t\t}\n+\t\tbreak;\n \tcase ARG_PTR_TO_FUNC:\n \t\tmeta-\u003esubprogno = reg-\u003esubprogno;\n \t\tbreak;\n \tcase ARG_PTR_TO_MEM:\n+\t{\n+\t\tenum bpf_access_type access_type;\n+\t\tbool known_memory;\n+\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_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, NULL);\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\tif (!(arg_type \u0026 MEM_FIXED_SIZE))\n+\t\t\tbreak;\n+\n+\t\taccess_type = arg_type \u0026 MEM_WRITE ? BPF_WRITE : BPF_READ;\n+\t\tif (meta-\u003ebtf)\n+\t\t\taccess_type = BPF_READ | BPF_WRITE;\n+\n+\t\terr = check_mem_reg(env, reg, argno, arg_size, access_type, meta, \u0026known_memory);\n+\t\tif (err \u003c 0) {\n+\t\t\tif (known_memory)\n+\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\"Pass memory with at least the required number of accessible bytes and suitable read or write access.\",\n+\t\t\t\t\t\"the function expects %u bytes of memory, but the verifier cannot prove that %s provides a range of that size with the required read or write access\",\n+\t\t\t\t\targ_size,\n+\t\t\t\t\tbpf_diag_reg_type_plain(env, reg-\u003etype));\n+\t\t\telse\n+\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\"Pass stack, map, context, or other verifier-known memory of the expected type and size, not an integer cast to a pointer.\",\n+\t\t\t\t\t\"the function expects %u bytes of memory, but it is %s and not verifier-known memory\",\n+\t\t\t\t\targ_size,\n+\t\t\t\t\tbpf_diag_reg_type_plain(env, reg-\u003etype));\n+\t\t\treturn err;\n \t\t}\n+\t\tif (arg_type \u0026 MEM_ALIGNED)\n+\t\t\terr = check_ptr_alignment(env, reg, 0, arg_size, true);\n \t\tbreak;\n+\t}\n+\tcase ARG_CONST_MEM_SIZE:\n+\t\terr = process_const_arg(env, reg, argno, meta);\n+\t\tif (err \u003c 0) {\n+\t\t\tif (err == -EINVAL)\n+\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\t \"Pass a compile-time constant or a value the verifier can prove is constant at this call.\",\n+\t\t\t\t\t\t \"the function requires this memory size to be a verifier-known constant, but %s is variable on this path\",\n+\t\t\t\t\t\t reg_arg_name(env, argno));\n+\t\t\treturn err;\n+\t\t}\n+\t\tfallthrough;\n \tcase ARG_MEM_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, NULL);\n-\t\tbreak;\n \tcase ARG_MEM_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, NULL);\n-\t\tbreak;\n-\tcase ARG_PTR_TO_DYNPTR:\n-\t\terr = process_dynptr_func(env, reg, argno, insn_idx, func_id_name(meta-\u003efunc_id),\n-\t\t\t\t\t arg_type, \u0026meta-\u003eref_obj, \u0026meta-\u003edynptr);\n+\t{\n+\t\tstruct bpf_reg_state *buff_reg = get_func_arg_reg(caller, regs, arg - 1);\n+\t\targno_t buff_argno = argno_from_arg(arg);\n+\t\tenum bpf_mem_size_failure failure;\n+\t\tu32 access_type;\n+\t\tbool zero_size_allowed;\n+\n+\t\tif (meta-\u003ebtf \u0026\u0026 bpf_register_is_null(buff_reg))\n+\t\t\tbreak;\n+\n+\t\taccess_type = fn-\u003earg_type[arg - 1] \u0026 MEM_WRITE ? BPF_WRITE : BPF_READ;\n+\t\tif (meta-\u003ebtf)\n+\t\t\taccess_type = BPF_READ | BPF_WRITE;\n+\t\tzero_size_allowed = meta-\u003ebtf || base_type(arg_type) == ARG_MEM_SIZE_OR_ZERO;\n+\n+\t\terr = check_mem_size_reg(env, buff_reg, reg, buff_argno, argno,\n+\t\t\t\t\t access_type, zero_size_allowed, meta, \u0026failure);\n+\t\tif (err \u003c 0) {\n+\t\t\tconst char *buff_arg, *size_arg;\n+\n+\t\t\tbuff_arg = bpf_diag_arg_name(env, buff_argno);\n+\t\t\tsize_arg = bpf_diag_arg_name(env, argno);\n+\t\t\tverbose(env, \"%s and \", reg_arg_name(env, buff_argno));\n+\t\t\tverbose(env, \"%s memory, len pair leads to invalid memory access\\n\",\n+\t\t\t\treg_arg_name(env, argno));\n+\t\t\tif (failure == BPF_MEM_SIZE_FAIL_MEMORY) {\n+\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, buff_argno, meta-\u003efunc_name,\n+\t\t\t\t\t\t \"Pass a stack, map, context, or other verifier-known memory pointer, and keep the paired length within that object.\",\n+\t\t\t\t\t\t \"it is the memory pointer in a memory/length pair with %s, but %s does not provide a verifier-accessible range of the requested length\",\n+\t\t\t\t\t\t size_arg, buff_arg);\n+\t\t\t} else if (failure == BPF_MEM_SIZE_FAIL_SIZE) {\n+\t\t\t\tif (reg_smin(reg) \u003c 0)\n+\t\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\t\"Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.\",\n+\t\t\t\t\t\t\"the memory size in %s may be negative because its signed minimum is %lld\",\n+\t\t\t\t\t\tsize_arg, reg_smin(reg));\n+\t\t\t\telse if (!zero_size_allowed \u0026\u0026 reg_umin(reg) == 0)\n+\t\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\t\"Ensure the memory size is non-zero before this call.\",\n+\t\t\t\t\t\t\"the memory size in %s may be zero, but the function requires a non-zero size\",\n+\t\t\t\t\t\tsize_arg);\n+\t\t\t\telse\n+\t\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\t\"Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.\",\n+\t\t\t\t\t\t\"the memory size in %s may reach %llu bytes, but variable memory accesses must stay below %u bytes\",\n+\t\t\t\t\t\tsize_arg, reg_umax(reg), BPF_MAX_VAR_SIZ);\n+\t\t\t}\n+\t\t}\n+\t\tbreak;\n+\t}\n+\tcase ARG_PTR_TO_DYNPTR: {\n+\t\tif (is_bpf_dynptr_clone_kfunc(meta) \u0026\u0026\n+\t\t (arg_type \u0026 MEM_UNINIT)) {\n+\t\t\tenum bpf_dynptr_type parent_type = meta-\u003edynptr.type;\n+\n+\t\t\tif (parent_type == BPF_DYNPTR_TYPE_INVALID) {\n+\t\t\t\tverifier_bug(env, \"no dynptr type for parent of clone\");\n+\t\t\t\treturn -EFAULT;\n+\t\t\t}\n+\n+\t\t\targ_type |= (unsigned int)get_dynptr_type_flag(parent_type);\n+\t\t}\n+\n+\t\terr = process_dynptr_func(env, reg, argno, insn_idx, arg_type, meta);\n \t\tif (err)\n \t\t\treturn err;\n \t\tbreak;\n+\t}\n+\tcase ARG_PTR_TO_ITER:\n+\t\tif (is_bpf_iter_css_task_new_kfunc(meta) \u0026\u0026\n+\t\t !check_css_task_iter_allowlist(env)) {\n+\t\t\tverbose(env, \"css_task_iter is only allowed in bpf_lsm, bpf_iter and sleepable progs\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\terr = process_iter_arg(env, reg, argno, insn_idx, meta);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\tcase ARG_PTR_TO_LIST_HEAD:\n+\t\tif (reg-\u003etype == (PTR_TO_BTF_ID | MEM_ALLOC) \u0026\u0026\n+\t\t !reg_is_referenced(env, reg)) {\n+\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\terr = process_kf_arg_ptr_to_list_head(env, reg, argno, meta);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\tcase ARG_PTR_TO_RB_ROOT:\n+\t\tif (reg-\u003etype == (PTR_TO_BTF_ID | MEM_ALLOC) \u0026\u0026\n+\t\t !reg_is_referenced(env, reg)) {\n+\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\terr = process_kf_arg_ptr_to_rbtree_root(env, reg, argno, meta);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\tcase ARG_PTR_TO_LIST_NODE:\n+\t\tif (!(is_kfunc_arg_nonown_allowed(meta-\u003ebtf, btf_arg) \u0026\u0026\n+\t\t type_is_non_owning_ref(reg-\u003etype) \u0026\u0026 !reg_is_referenced(env, reg))) {\n+\t\t\tif (reg-\u003etype != (PTR_TO_BTF_ID | MEM_ALLOC)) {\n+\t\t\t\tverbose(env, \"%s expected pointer to allocated object\\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 (!reg_is_referenced(env, reg)) {\n+\t\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\t\terr = process_kf_arg_ptr_to_list_node(env, reg, argno, meta);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\tcase ARG_PTR_TO_RB_NODE:\n+\t\tif (is_bpf_rbtree_add_kfunc(meta-\u003efunc_id)) {\n+\t\t\tif (reg-\u003etype != (PTR_TO_BTF_ID | MEM_ALLOC)) {\n+\t\t\t\tverbose(env, \"%s expected pointer to allocated object\\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 (!reg_is_referenced(env, reg)) {\n+\t\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t} else {\n+\t\t\tif (!type_is_non_owning_ref(reg-\u003etype) \u0026\u0026\n+\t\t\t !reg_is_referenced(env, reg)) {\n+\t\t\t\tverbose(env, \"%s can only take non-owning or refcounted bpf_rb_node pointer\\n\",\n+\t\t\t\t\tmeta-\u003efunc_name);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\tif (in_rbtree_lock_required_cb(env)) {\n+\t\t\t\tverbose(env, \"%s not allowed in rbtree cb\\n\", meta-\u003efunc_name);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\t\terr = process_kf_arg_ptr_to_rbtree_node(env, reg, argno, meta);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n \tcase ARG_CONST_ALLOC_SIZE_OR_ZERO:\n+\t\tif (meta-\u003ebtf \u0026\u0026 is_kfunc_arg_scalar_with_name(meta-\u003ebtf, btf_arg,\n+\t\t\t\t\t\t\t \"rdonly_buf_size\"))\n+\t\t\tmeta-\u003er0_rdonly = true;\n \t\terr = process_const_alloc_mem_size(env, reg, argno, \u0026meta-\u003eret_mem);\n-\t\tif (err)\n+\t\tif (err \u003c 0) {\n+\t\t\tif (meta-\u003ebtf \u0026\u0026 err == -EINVAL)\n+\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, meta-\u003efunc_name,\n+\t\t\t\t\t\t \"Pass a verifier-known constant size for this function's buffer argument.\",\n+\t\t\t\t\t\t \"the function uses this argument as a return-buffer size, but %s is invalid or variable on this path\",\n+\t\t\t\t\t\t reg_arg_name(env, argno));\n \t\t\treturn err;\n+\t\t}\n+\t\tbreak;\n+\tcase ARG_PTR_TO_REFCOUNTED_KPTR:\n+\t{\n+\t\tstruct btf_record *rec;\n+\n+\t\tif (!type_is_non_owning_ref(reg-\u003etype))\n+\t\t\tmeta-\u003earg_owning_ref = true;\n+\n+\t\trec = reg_btf_record(reg);\n+\t\tif (!rec) {\n+\t\t\tverifier_bug(env, \"Couldn't find btf_record\");\n+\t\t\treturn -EFAULT;\n+\t\t}\n+\n+\t\tif (rec-\u003erefcount_off \u003c 0) {\n+\t\t\tverbose(env, \"%s doesn't point to a type with bpf_refcount field\\n\",\n+\t\t\t\treg_arg_name(env, argno));\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tmeta-\u003earg_btf = reg-\u003ebtf;\n+\t\tmeta-\u003earg_btf_id = reg-\u003ebtf_id;\n \t\tbreak;\n+\t}\n \tcase ARG_PTR_TO_CONST_STR:\n \t{\n \t\terr = check_arg_const_str(env, reg, argno);\n@@ -8982,6 +9352,33 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \t\t\treturn err;\n \t\tbreak;\n \t}\n+\tcase ARG_PTR_TO_WORKQUEUE:\n+\t\terr = check_map_field_pointer(env, reg, argno, BPF_WORKQUEUE, \u0026meta-\u003emap);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\tcase ARG_PTR_TO_TASK_WORK:\n+\t\terr = check_map_field_pointer(env, reg, argno, BPF_TASK_WORK, \u0026meta-\u003emap);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\tcase ARG_PTR_TO_IRQ_FLAG:\n+\t\terr = process_irq_flag(env, reg, argno, meta);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\tcase ARG_PTR_TO_RES_SPIN_LOCK:\n+\t{\n+\t\tint flags;\n+\n+\t\tflags = get_bpf_res_spin_lock_kfunc_flags(meta);\n+\t\tif (!flags)\n+\t\t\treturn -EFAULT;\n+\t\terr = process_spin_lock(env, reg, argno, flags);\n+\t\tif (err \u003c 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\t}\n \tcase ARG_KPTR_XCHG_DEST:\n \t\terr = process_kptr_func(env, regno, meta);\n \t\tif (err)\n@@ -8992,6 +9389,37 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n \treturn err;\n }\n \n+static int check_func_args(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,\n+\t\t\t int insn_idx)\n+{\n+\tstruct bpf_func_state *caller = cur_func(env);\n+\tconst struct btf_param *args = NULL;\n+\tu32 arg, nargs = MAX_BPF_FUNC_REG_ARGS;\n+\tint err;\n+\n+\tif (meta-\u003ebtf) {\n+\t\targs = btf_params(meta-\u003efunc_proto);\n+\t\tnargs = btf_type_vlen(meta-\u003efunc_proto);\n+\t}\n+\n+\tif (nargs \u003e MAX_BPF_FUNC_REG_ARGS) {\n+\t\terr = check_outgoing_stack_args(env, caller, nargs, meta-\u003efunc_name,\n+\t\t\t\t\t\tmeta-\u003ebtf, args);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\tfor (arg = 0; arg \u003c nargs; arg++) {\n+\t\tif (meta-\u003efn-\u003earg_type[arg] == ARG_UNUSED)\n+\t\t\tbreak;\n+\t\terr = check_func_arg(env, arg, meta, insn_idx);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\treturn 0;\n+}\n+\n static bool may_update_sockmap(struct bpf_verifier_env *env, int func_id)\n {\n \tenum bpf_attach_type eatype = env-\u003eprog-\u003eexpected_attach_type;\n@@ -9289,7 +9717,7 @@ static bool check_raw_mode_ok(const struct bpf_func_proto *fn, struct bpf_call_a\n \tint i;\n \n \tfor (i = 0; i \u003c ARRAY_SIZE(fn-\u003earg_type); i++) {\n-\t\tif (fn-\u003earg_type[i] == ARG_DONTCARE)\n+\t\tif (fn-\u003earg_type[i] == ARG_UNUSED)\n \t\t\tbreak;\n \t\tif (!arg_type_is_raw_mem(fn-\u003earg_type[i]))\n \t\t\tcontinue;\n@@ -9339,7 +9767,7 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn)\n \tint i;\n \n \tfor (i = 0; i \u003c ARRAY_SIZE(fn-\u003earg_type); i++) {\n-\t\tif (fn-\u003earg_type[i] == ARG_DONTCARE)\n+\t\tif (fn-\u003earg_type[i] == ARG_UNUSED)\n \t\t\tbreak;\n \t\tif (base_type(fn-\u003earg_type[i]) == ARG_PTR_TO_BTF_ID)\n \t\t\treturn !!fn-\u003earg_btf_id[i];\n@@ -9362,7 +9790,7 @@ static bool check_mem_arg_rw_flag_ok(const struct bpf_func_proto *fn)\n \tfor (i = 0; i \u003c ARRAY_SIZE(fn-\u003earg_type); i++) {\n \t\tenum bpf_arg_type arg_type = fn-\u003earg_type[i];\n \n-\t\tif (arg_type == ARG_DONTCARE)\n+\t\tif (arg_type == ARG_UNUSED)\n \t\t\tbreak;\n \t\tif (base_type(arg_type) != ARG_PTR_TO_MEM)\n \t\t\tcontinue;\n@@ -9380,7 +9808,7 @@ static bool check_proto_release_reg(const struct bpf_func_proto *fn, struct bpf_\n \tfor (i = 0; i \u003c ARRAY_SIZE(fn-\u003earg_type); i++) {\n \t\tenum bpf_arg_type arg_type = fn-\u003earg_type[i];\n \n-\t\tif (arg_type == ARG_DONTCARE)\n+\t\tif (arg_type == ARG_UNUSED)\n \t\t\tbreak;\n \t\tif (arg_type_is_release(arg_type)) {\n \t\t\tif (meta-\u003erelease_regno)\n@@ -9392,9 +9820,42 @@ static bool check_proto_release_reg(const struct bpf_func_proto *fn, struct bpf_\n \treturn true;\n }\n \n-static int check_func_proto(const struct bpf_func_proto *fn, struct bpf_call_arg_meta *meta)\n+static bool check_arg_prog_aux(struct bpf_verifier_env *env,\n+\t\t\t const struct bpf_func_proto *proto)\n+{\n+\tbool seen = false;\n+\targno_t argno;\n+\tu32 i;\n+\n+\tfor (i = 0; i \u003c ARRAY_SIZE(proto-\u003earg_type); i++) {\n+\t\tif (proto-\u003earg_type[i] == ARG_UNUSED)\n+\t\t\tbreak;\n+\t\tif (proto-\u003earg_type[i] != ARG_PTR_TO_PROG_AUX)\n+\t\t\tcontinue;\n+\n+\t\tif (seen) {\n+\t\t\tverifier_bug(env, \"Only 1 prog-\u003eaux argument supported\");\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\targno = argno_from_arg(i + 1);\n+\t\tif (reg_from_argno(argno) \u003c 0) {\n+\t\t\tverbose(env, \"%s prog-\u003eaux cannot be a stack argument\\n\",\n+\t\t\t\treg_arg_name(env, argno));\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\tseen = true;\n+\t}\n+\n+\treturn true;\n+}\n+\n+static int check_func_proto(struct bpf_verifier_env *env, const struct bpf_func_proto *fn,\n+\t\t\t struct bpf_call_arg_meta *meta)\n {\n-\treturn check_raw_mode_ok(fn, meta) \u0026\u0026\n+\treturn check_arg_prog_aux(env, fn) \u0026\u0026\n+\t check_raw_mode_ok(fn, meta) \u0026\u0026\n \t check_arg_pair_ok(fn) \u0026\u0026\n \t check_mem_arg_rw_flag_ok(fn) \u0026\u0026\n \t check_proto_release_reg(fn, meta) \u0026\u0026\n@@ -9713,12 +10174,16 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,\n \tstruct bpf_subprog_info *sub = subprog_info(env, subprog);\n \tstruct bpf_func_state *caller = cur_func(env);\n \tstruct bpf_verifier_log *log = \u0026env-\u003elog;\n-\tstruct ref_obj_desc ref_obj = {};\n \tconst struct btf_param *args;\n \tconst struct btf_type *func, *func_proto;\n+\tstruct bpf_call_arg_meta meta;\n \tu32 i;\n \tint ret, err;\n \n+\t/* Leave btf and func_id zero: this is neither a helper nor a kfunc. */\n+\tmemset(\u0026meta, 0, sizeof(meta));\n+\tmeta.func_name = bpf_subprog_name(env, subprog);\n+\n \tret = btf_prepare_func_args(env, subprog);\n \tif (ret) {\n \t\tif (bpf_in_stack_arg_cnt(sub) \u003e 0) {\n@@ -9747,7 +10212,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,\n \t\tstruct bpf_reg_state *reg = get_func_arg_reg(caller, regs, i);\n \t\tstruct bpf_subprog_arg_info *arg = \u0026sub-\u003eargs[i];\n \n-\t\tif (arg-\u003earg_type == ARG_ANYTHING) {\n+\t\tif (arg-\u003earg_type == ARG_SCALAR) {\n \t\t\tif (reg-\u003etype != SCALAR_VALUE) {\n \t\t\t\tbpf_log(log, \"%s is not a scalar\\n\", reg_arg_name(env, argno));\n \t\t\t\treturn -EINVAL;\n@@ -9771,7 +10236,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,\n \t\t\t\treturn -EINVAL;\n \t\t\t}\n \t\t} else if (base_type(arg-\u003earg_type) == ARG_PTR_TO_MEM) {\n-\t\t\tret = check_func_arg_reg_off(env, reg, argno, ARG_DONTCARE);\n+\t\t\tret = check_func_arg_reg_off(env, reg, argno, ARG_PTR_TO_MEM);\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, BPF_READ | BPF_WRITE, NULL,\n@@ -9802,21 +10267,21 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,\n \t\t\t\treturn ret;\n \n \t\t\tret = process_dynptr_func(env, reg, argno, env-\u003einsn_idx,\n-\t\t\t\t\t\t bpf_subprog_name(env, subprog), arg-\u003earg_type,\n-\t\t\t\t\t\t \u0026ref_obj, NULL);\n+\t\t\t\t\t\t arg-\u003earg_type, \u0026meta);\n \t\t\tif (ret)\n \t\t\t\treturn ret;\n \t\t} else if (base_type(arg-\u003earg_type) == ARG_PTR_TO_BTF_ID) {\n-\t\t\tstruct bpf_call_arg_meta meta;\n \t\t\tint err;\n \n \t\t\tif (bpf_register_is_null(reg) \u0026\u0026 type_may_be_null(arg-\u003earg_type))\n \t\t\t\tcontinue;\n \n-\t\t\tmemset(\u0026meta, 0, sizeof(meta)); /* leave func_id as zero */\n-\t\t\terr = check_reg_type(env, reg, argno, arg-\u003earg_type, \u0026arg-\u003ebtf_id, \u0026meta,\n-\t\t\t\t\t bpf_subprog_name(env, subprog));\n+\t\t\terr = check_reg_type(env, reg, argno, arg-\u003earg_type, \u0026meta);\n \t\t\terr = err ?: check_func_arg_reg_off(env, reg, argno, arg-\u003earg_type);\n+\t\t\tif (!err \u0026\u0026 base_type(reg-\u003etype) == PTR_TO_BTF_ID)\n+\t\t\t\terr = process_arg_ptr_to_btf_id(env, reg, argno, arg-\u003earg_type,\n+\t\t\t\t\t\t\t\tbtf_vmlinux, arg-\u003ebtf_id,\n+\t\t\t\t\t\t\t\t\u0026meta, env-\u003einsn_idx);\n \t\t\tif (err)\n \t\t\t\treturn err;\n \t\t} else {\n@@ -10908,7 +11373,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn\n \n \tmemset(\u0026meta, 0, sizeof(meta));\n \n-\terr = check_func_proto(fn, \u0026meta);\n+\terr = check_func_proto(env, fn, \u0026meta);\n \tif (err) {\n \t\tverifier_bug(env, \"incorrect func proto %s#%d\", func_id_name(func_id), func_id);\n \t\treturn err;\n@@ -10929,13 +11394,11 @@ 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.func_name = func_id_name(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, insn_idx);\n-\t\tif (err)\n-\t\t\treturn err;\n-\t}\n+\terr = check_func_args(env, \u0026meta, insn_idx);\n+\tif (err)\n+\t\treturn err;\n \n \terr = record_func_map(env, \u0026meta, func_id, insn_idx);\n \tif (err)\n@@ -11758,6 +12221,49 @@ static bool btf_type_is_scalar_struct(struct bpf_verifier_env *env,\n \treturn btf_struct_is_composed_of(env, btf, t, BTF_MEMBER_SCALAR);\n }\n \n+static int resolve_func_arg_type(struct bpf_verifier_env *env,\n+\t\t\t\t struct bpf_reg_state *reg, u32 arg,\n+\t\t\t\t struct bpf_call_arg_meta *meta,\n+\t\t\t\t enum bpf_arg_type *arg_type, u32 *arg_size)\n+{\n+\targno_t argno = argno_from_arg(arg + 1);\n+\tconst struct btf_param *args;\n+\tconst struct btf_type *ref_t, *resolve_ret;\n+\tconst struct btf *btf;\n+\tconst char *ref_tname;\n+\tu32 ref_id;\n+\n+\tif (base_type(*arg_type) == ARG_PTR_TO_MAP_VALUE)\n+\t\treturn resolve_map_arg_type(env, meta, arg_type);\n+\n+\tif (base_type(*arg_type) == ARG_PTR_TO_BTF_ID) {\n+\t\tif (!meta-\u003ebtf || arg_type_is_release(*arg_type) ||\n+\t\t base_type(reg-\u003etype) == PTR_TO_BTF_ID ||\n+\t\t reg2btf_ids[base_type(reg-\u003etype)])\n+\t\t\treturn 0;\n+\n+\t\targs = btf_params(meta-\u003efunc_proto);\n+\t\tref_id = *meta-\u003efn-\u003earg_btf_id[arg];\n+\t\tbtf = is_kfunc_arg_map(meta-\u003ebtf, \u0026args[arg]) ? btf_vmlinux : meta-\u003ebtf;\n+\t\tref_t = btf_type_skip_modifiers(btf, ref_id, \u0026ref_id);\n+\t\tref_tname = btf_name_by_offset(btf, ref_t-\u003ename_off);\n+\n+\t\tif (!btf_type_is_scalar_struct(env, btf, ref_t))\n+\t\t\treturn 0;\n+\n+\t\tresolve_ret = btf_resolve_size(btf, ref_t, arg_size);\n+\t\tif (IS_ERR(resolve_ret)) {\n+\t\t\tverbose(env, \"%s reference type('%s %s') size cannot be determined: %ld\\n\",\n+\t\t\t\treg_arg_name(env, argno), btf_type_str(ref_t), ref_tname,\n+\t\t\t\tPTR_ERR(resolve_ret));\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\t*arg_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE | (*arg_type \u0026 PTR_MAYBE_NULL);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static void btf_member_path_str(const struct btf *btf, const struct btf_member_path *path,\n \t\t\t\tchar *buf, size_t buf_sz)\n {\n@@ -11777,34 +12283,6 @@ static void btf_member_path_str(const struct btf *btf, const struct btf_member_p\n \t}\n }\n \n-enum kfunc_ptr_arg_type {\n-\tKF_ARG_CONST_MEM_SIZE,\n-\tKF_ARG_MEM_SIZE,\n-\tKF_ARG_CONST,\n-\tKF_ARG_CONST_ALLOC_SIZE_OR_ZERO,\n-\tKF_ARG_ANYTHING,\n-\tKF_ARG_PTR_TO_CTX,\n-\tKF_ARG_PTR_TO_ALLOC_BTF_ID, /* Allocated object */\n-\tKF_ARG_PTR_TO_REFCOUNTED_KPTR, /* Refcounted local kptr */\n-\tKF_ARG_PTR_TO_DYNPTR,\n-\tKF_ARG_PTR_TO_ITER,\n-\tKF_ARG_PTR_TO_LIST_HEAD,\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_CALLBACK,\n-\tKF_ARG_PTR_TO_RB_ROOT,\n-\tKF_ARG_PTR_TO_RB_NODE,\n-\tKF_ARG_PTR_TO_CONST_STR,\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_PTR_TO_ARENA,\n-};\n-\n enum special_kfunc_type {\n \tKF_bpf_obj_new_impl,\n \tKF_bpf_obj_new,\n@@ -11872,7 +12350,10 @@ enum special_kfunc_type {\n \tKF_bpf_task_work_schedule_resume,\n \tKF_bpf_arena_alloc_pages,\n \tKF_bpf_arena_free_pages,\n+\tKF_bpf_arena_reserve_pages,\n \tKF_bpf_session_is_return,\n+\tKF_bpf_stream_vprintk,\n+\tKF_bpf_stream_print_stack,\n };\n \n BTF_ID_LIST(special_kfunc_list)\n@@ -11962,11 +12443,29 @@ BTF_ID(func, bpf_task_work_schedule_signal)\n BTF_ID(func, bpf_task_work_schedule_resume)\n BTF_ID(func, bpf_arena_alloc_pages)\n BTF_ID(func, bpf_arena_free_pages)\n+BTF_ID(func, bpf_arena_reserve_pages)\n #ifdef CONFIG_BPF_EVENTS\n BTF_ID(func, bpf_session_is_return)\n #else\n BTF_ID_UNUSED\n #endif\n+BTF_ID(func, bpf_stream_vprintk)\n+BTF_ID(func, bpf_stream_print_stack)\n+\n+static bool is_bpf_cast_to_kern_ctx_kfunc(const struct bpf_call_arg_meta *meta)\n+{\n+\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_cast_to_kern_ctx]);\n+}\n+\n+static bool is_bpf_dynptr_clone_kfunc(const struct bpf_call_arg_meta *meta)\n+{\n+\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_clone]);\n+}\n+\n+static bool is_bpf_iter_css_task_new_kfunc(const struct bpf_call_arg_meta *meta)\n+{\n+\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_iter_css_task_new]);\n+}\n \n static bool is_bpf_obj_new_kfunc(u32 func_id)\n {\n@@ -12029,52 +12528,63 @@ static bool is_kfunc_ret_null(struct bpf_call_arg_meta *meta)\n \n static bool is_kfunc_bpf_rcu_read_lock(struct bpf_call_arg_meta *meta)\n {\n-\treturn meta-\u003efunc_id == special_kfunc_list[KF_bpf_rcu_read_lock];\n+\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_rcu_read_lock]);\n }\n \n static bool is_kfunc_bpf_rcu_read_unlock(struct bpf_call_arg_meta *meta)\n {\n-\treturn meta-\u003efunc_id == special_kfunc_list[KF_bpf_rcu_read_unlock];\n+\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_rcu_read_unlock]);\n }\n \n static bool is_kfunc_bpf_preempt_disable(struct bpf_call_arg_meta *meta)\n {\n-\treturn meta-\u003efunc_id == special_kfunc_list[KF_bpf_preempt_disable];\n+\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_preempt_disable]);\n }\n \n static bool is_kfunc_bpf_preempt_enable(struct bpf_call_arg_meta *meta)\n {\n-\treturn meta-\u003efunc_id == special_kfunc_list[KF_bpf_preempt_enable];\n+\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_preempt_enable]);\n }\n \n bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta)\n {\n-\treturn meta-\u003efunc_id == special_kfunc_list[KF_bpf_xdp_pull_data];\n+\treturn is_kfunc_call(meta, special_kfunc_list[KF_bpf_xdp_pull_data]);\n }\n \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)\n+\t\t const struct btf_param *args, int arg, int nargs,\n+\t\t struct bpf_func_proto *proto)\n {\n-\tconst struct btf_type *t, *ref_t = NULL;\n+\tconst struct btf_type *t, *ref_t = NULL, *resolve_ret;\n+\tconst u32 *ref_id_ptr = NULL;\n \targno_t argno = argno_from_arg(arg + 1);\n \tconst char *ref_tname = NULL;\n+\tu32 ref_id, type_size;\n \tint arg_type;\n \n+\tproto-\u003earg_btf_id[arg] = NULL;\n+\n+\tif (is_kfunc_arg_prog_aux(meta-\u003ebtf, \u0026args[arg]))\n+\t\treturn ARG_PTR_TO_PROG_AUX;\n+\n+\tif (is_kfunc_arg_ignore(meta-\u003ebtf, \u0026args[arg]) || is_kfunc_arg_implicit(meta, arg))\n+\t\treturn ARG_IGNORE;\n+\n \tt = btf_type_skip_modifiers(meta-\u003ebtf, args[arg].type, NULL);\n \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;\n+\t\t\treturn ARG_CONST_SCALAR;\n \t\tif (is_kfunc_arg_const_mem_size(meta-\u003ebtf, \u0026args[arg]))\n-\t\t\treturn KF_ARG_CONST_MEM_SIZE;\n+\t\t\treturn 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\t\treturn 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\t\treturn ARG_CONST_ALLOC_SIZE_OR_ZERO;\n+\t\treturn ARG_SCALAR;\n \t}\n \n \tif (!btf_type_is_ptr(t)) {\n@@ -12082,54 +12592,69 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,\n \t\t\treg_arg_name(env, argno), btf_type_str(t));\n \t\treturn -EINVAL;\n \t}\n-\tref_t = btf_type_skip_modifiers(meta-\u003ebtf, t-\u003etype, NULL);\n+\t/* Keep a pointer to the BTF field containing the resolved referent ID. */\n+\tref_id_ptr = \u0026t-\u003etype;\n+\tref_t = btf_type_skip_modifiers(meta-\u003ebtf, *ref_id_ptr, \u0026ref_id);\n+\twhile (*ref_id_ptr != ref_id)\n+\t\tref_id_ptr = \u0026btf_type_by_id(meta-\u003ebtf, *ref_id_ptr)-\u003etype;\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 * arguments, we resolve it to a known bpf_arg_type.\n \t */\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+\tif (is_kfunc_call(meta, special_kfunc_list[KF_bpf_cast_to_kern_ctx]) ||\n+\t is_kfunc_call(meta, special_kfunc_list[KF_bpf_session_is_return]) ||\n+\t is_kfunc_call(meta, special_kfunc_list[KF_bpf_session_cookie]))\n+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = ARG_PTR_TO_REFCOUNTED_KPTR;\n+\telse if (is_kfunc_arg_dynptr(meta-\u003ebtf, \u0026args[arg])) {\n+\t\targ_type = ARG_PTR_TO_DYNPTR;\n+\n+\t\tif (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_skb]))\n+\t\t\targ_type |= DYNPTR_TYPE_SKB;\n+\t\telse if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_xdp]))\n+\t\t\targ_type |= DYNPTR_TYPE_XDP;\n+\t\telse if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_skb_meta]))\n+\t\t\targ_type |= DYNPTR_TYPE_SKB_META;\n+\t\telse if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_file]) ||\n+\t\t\t is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_file_discard]))\n+\t\t\t/* OBJ_RELEASE for the latter comes from KF_RELEASE below */\n+\t\t\targ_type |= DYNPTR_TYPE_FILE;\n+\t} else if (is_kfunc_arg_iter(meta, arg, \u0026args[arg]))\n+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = 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+\t\targ_type = ARG_PTR_TO_FUNC;\n \telse if (is_kfunc_arg_arena(meta-\u003ebtf, \u0026args[arg])) {\n \t\tif (!bpf_jit_supports_arena_args()) {\n \t\t\tverbose(env, \"JIT does not support kfunc %s() with arena pointer arguments\\n\",\n@@ -12152,7 +12677,7 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,\n \t\t * whether the JIT rebases it to the arena base or preserves NULL.\n \t\t * The common nullable path below records that verifier property.\n \t\t */\n-\t\targ_type = KF_ARG_PTR_TO_ARENA;\n+\t\targ_type = ARG_PTR_TO_ARENA;\n \t} else if (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@@ -12162,10 +12687,10 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,\n \t\t\t\treg_arg_name(env, argno), btf_type_str(ref_t), ref_tname);\n \t\t\treturn -EINVAL;\n \t\t}\n-\t\targ_type = KF_ARG_PTR_TO_MEM;\n+\t\targ_type = ARG_PTR_TO_MEM;\n \t} else if (btf_type_is_struct(ref_t))\n-\t\t/* A pointer to a struct without a size argument is classified as KF_ARG_PTR_TO_BTF_ID */\n-\t\targ_type = KF_ARG_PTR_TO_BTF_ID;\n+\t\t/* A pointer to a struct without a size argument is classified as ARG_PTR_TO_BTF_ID */\n+\t\targ_type = ARG_PTR_TO_BTF_ID;\n \telse {\n \t\t/*\n \t\t * Otherwise this is a fixed-size memory buffer supported by\n@@ -12178,19 +12703,53 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,\n \t\t\t\treg_arg_name(env, argno), btf_type_str(ref_t), ref_tname);\n \t\t\treturn -EINVAL;\n \t\t}\n-\t\targ_type = KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;\n+\t\tresolve_ret = btf_resolve_size(meta-\u003ebtf, ref_t, \u0026type_size);\n+\t\tif (IS_ERR(resolve_ret)) {\n+\t\t\tverbose(env,\n+\t\t\t\t\"%s reference type('%s %s') size cannot be determined: %ld\\n\",\n+\t\t\t\treg_arg_name(env, argno), btf_type_str(ref_t),\n+\t\t\t\tref_tname, PTR_ERR(resolve_ret));\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tproto-\u003earg_size[arg] = type_size;\n+\t\targ_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE;\n \t}\n \n+\tif (is_kfunc_arg_uninit(meta-\u003ebtf, \u0026args[arg]))\n+\t\targ_type |= MEM_UNINIT;\n+\n \tif (is_kfunc_arg_nullable(meta-\u003ebtf, \u0026args[arg]))\n \t\targ_type |= PTR_MAYBE_NULL;\n \n+\t/*\n+\t * Only the first argument of a KF_RELEASE kfunc releases anything, and\n+\t * bpf_fetch_kfunc_arg_meta() only ever records BPF_REG_1 for it.\n+\t */\n+\tif (is_kfunc_release(meta) \u0026\u0026 arg == 0)\n+\t\targ_type |= OBJ_RELEASE;\n+\n+\tif (base_type(arg_type) == ARG_PTR_TO_BTF_ID) {\n+\t\t/* A __map argument names a vmlinux type rather than one from\n+\t\t * the kfunc's own BTF.\n+\t\t */\n+\t\tif (is_kfunc_arg_map(meta-\u003ebtf, \u0026args[arg]))\n+\t\t\tproto-\u003earg_btf_id[arg] = reg2btf_ids[CONST_PTR_TO_MAP];\n+\t\telse\n+\t\t\tproto-\u003earg_btf_id[arg] = ref_id_ptr;\n+\n+\t\t/* A KF_RCU kfunc accepts an RCU-protected pointer where it would\n+\t\t * otherwise demand a referenced or trusted one.\n+\t\t */\n+\t\tif (is_kfunc_rcu(meta))\n+\t\t\targ_type |= MEM_RCU;\n+\t}\n+\n \treturn arg_type;\n }\n \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@@ -12209,47 +12768,38 @@ static int gen_kfunc_arg_proto(struct bpf_verifier_env *env, struct bpf_call_arg\n \t}\n \n \tfor (i = 0; i \u003c nargs; i++) {\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-\t\targ_type = get_kfunc_arg_type(env, meta, args, i, nargs);\n+\t\targ_type = get_kfunc_arg_type(env, meta, args, i, nargs, proto);\n \t\tif (arg_type \u003c 0)\n \t\t\treturn arg_type;\n \n \t\tproto-\u003earg_type[i] = arg_type;\n \t}\n \n-\treturn 0;\n+\treturn check_arg_prog_aux(env, proto) ? 0 : -EINVAL;\n }\n \n-static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,\n-\t\t\t\t\tstruct bpf_reg_state *reg,\n-\t\t\t\t\tconst struct btf_type *ref_t,\n-\t\t\t\t\tconst char *ref_tname, u32 ref_id,\n-\t\t\t\t\tstruct bpf_call_arg_meta *meta,\n-\t\t\t\t\tint arg, argno_t argno)\n+static int process_arg_ptr_to_btf_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n+\t\t\t\t argno_t argno, enum bpf_arg_type arg_type,\n+\t\t\t\t const struct btf *arg_btf, u32 arg_btf_id,\n+\t\t\t\t struct bpf_call_arg_meta *meta, int insn_idx)\n {\n-\tconst struct btf_type *reg_ref_t;\n-\tbool strict_type_match = false;\n+\tbool taking_projection, struct_same, strict_type_match = false;\n+\tconst struct btf_type *arg_t, *reg_t;\n+\tconst char *arg_tname, *reg_tname;\n \tconst struct btf *reg_btf;\n-\tconst char *reg_ref_tname;\n-\tbool taking_projection;\n-\tbool struct_same;\n-\tu32 reg_ref_id;\n+\tu32 reg_btf_id;\n \n \tif (base_type(reg-\u003etype) == PTR_TO_BTF_ID) {\n \t\treg_btf = reg-\u003ebtf;\n-\t\treg_ref_id = reg-\u003ebtf_id;\n+\t\treg_btf_id = reg-\u003ebtf_id;\n \t} else {\n \t\treg_btf = btf_vmlinux;\n-\t\treg_ref_id = *reg2btf_ids[base_type(reg-\u003etype)];\n+\t\treg_btf_id = *reg2btf_ids[base_type(reg-\u003etype)];\n \t}\n \n-\t/* Enforce strict type matching for calls to kfuncs that are acquiring\n-\t * or releasing a reference, or are no-cast aliases. We do _not_\n-\t * enforce strict matching for kfuncs by default,\n+\t/*\n+\t * Enforce strict type matching for arguments that release a reference,\n+\t * or are no-cast aliases. We do _not_ enforce strict matching by default,\n \t * as we want to enable BPF programs to pass types that are bitwise\n \t * equivalent without forcing them to explicitly cast with something\n \t * like bpf_cast_to_kern_ctx().\n@@ -12271,27 +12821,30 @@ static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,\n \t * btf_struct_ids_match() to walk the struct at the 0th offset, and\n \t * resolve types.\n \t */\n-\tif ((is_kfunc_release(meta) \u0026\u0026 reg_is_referenced(env, reg)) ||\n-\t btf_type_ids_nocast_alias(\u0026env-\u003elog, reg_btf, reg_ref_id, meta-\u003ebtf, ref_id))\n+\tif ((arg_type_is_release(arg_type) \u0026\u0026 !is_helper_call(meta, BPF_FUNC_sk_release)) ||\n+\t (meta-\u003ebtf \u0026\u0026 btf_type_ids_nocast_alias(\u0026env-\u003elog, reg_btf, reg_btf_id,\n+\t\t\t\t\t\t arg_btf, arg_btf_id)))\n \t\tstrict_type_match = true;\n \n-\tWARN_ON_ONCE(is_kfunc_release(meta) \u0026\u0026 !tnum_is_const(reg-\u003evar_off));\n+\targ_t = btf_type_skip_modifiers(arg_btf, arg_btf_id, \u0026arg_btf_id);\n+\targ_tname = btf_name_by_offset(arg_btf, arg_t-\u003ename_off);\n+\treg_t = btf_type_skip_modifiers(reg_btf, reg_btf_id, \u0026reg_btf_id);\n+\treg_tname = btf_name_by_offset(reg_btf, reg_t-\u003ename_off);\n+\n+\tstruct_same = btf_struct_ids_match(\u0026env-\u003elog, reg_btf, reg_btf_id,\n+\t\t\t\t\t reg-\u003evar_off.value, arg_btf, arg_btf_id,\n+\t\t\t\t\t strict_type_match, !type_is_alloc(reg-\u003etype));\n \n-\treg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id, \u0026reg_ref_id);\n-\treg_ref_tname = btf_name_by_offset(reg_btf, reg_ref_t-\u003ename_off);\n-\tstruct_same = btf_struct_ids_match(\u0026env-\u003elog, reg_btf, reg_ref_id, reg-\u003evar_off.value,\n-\t\t\t\t\t meta-\u003ebtf, ref_id, strict_type_match,\n-\t\t\t\t\t !type_is_alloc(reg-\u003etype));\n \t/* If kfunc is accepting a projection type (ie. __sk_buff), it cannot\n \t * actually use it -- it must cast to the underlying type. So we allow\n \t * caller to pass in the underlying type.\n \t */\n-\ttaking_projection = btf_is_projection_of(ref_tname, reg_ref_tname);\n+\ttaking_projection = meta-\u003ebtf \u0026\u0026 btf_is_projection_of(arg_tname, reg_tname);\n \tif (!taking_projection \u0026\u0026 !struct_same) {\n-\t\tverbose(env, \"kernel function %s %s expected pointer to %s %s but %s has a pointer to %s %s\\n\",\n+\t\tverbose(env, \"%s %s expected pointer to %s %s but %s has a pointer to %s %s\\n\",\n \t\t\tmeta-\u003efunc_name, reg_arg_name(env, argno),\n-\t\t\tbtf_type_str(ref_t), ref_tname, reg_arg_name(env, argno),\n-\t\t\tbtf_type_str(reg_ref_t), reg_ref_tname);\n+\t\t\tbtf_type_str(arg_t), arg_tname,\n+\t\t\treg_arg_name(env, argno), btf_type_str(reg_t), reg_tname);\n \t\treturn -EINVAL;\n \t}\n \treturn 0;\n@@ -12303,15 +12856,15 @@ static int process_irq_flag(struct bpf_verifier_env *env, struct bpf_reg_state *\n \tint err, spi, kfunc_class = IRQ_NATIVE_KFUNC;\n \tbool irq_save;\n \n-\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_local_irq_save] ||\n-\t meta-\u003efunc_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave]) {\n+\tif (is_kfunc_call(meta, special_kfunc_list[KF_bpf_local_irq_save]) ||\n+\t is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave])) {\n \t\tirq_save = true;\n-\t\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave])\n+\t\tif (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave]))\n \t\t\tkfunc_class = IRQ_LOCK_KFUNC;\n-\t} else if (meta-\u003efunc_id == special_kfunc_list[KF_bpf_local_irq_restore] ||\n-\t\t meta-\u003efunc_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]) {\n+\t} else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_local_irq_restore]) ||\n+\t\t is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore])) {\n \t\tirq_save = false;\n-\t\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore])\n+\t\tif (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]))\n \t\t\tkfunc_class = IRQ_LOCK_KFUNC;\n \t} else {\n \t\tverifier_bug(env, \"unknown irq flags kfunc\");\n@@ -12504,12 +13057,20 @@ static bool is_bpf_rbtree_api_kfunc(u32 btf_id)\n \t btf_id == special_kfunc_list[KF_bpf_rbtree_right];\n }\n \n-static bool is_bpf_res_spin_lock_kfunc(u32 btf_id)\n+static int get_bpf_res_spin_lock_kfunc_flags(const struct bpf_call_arg_meta *meta)\n {\n-\treturn btf_id == special_kfunc_list[KF_bpf_res_spin_lock] ||\n-\t btf_id == special_kfunc_list[KF_bpf_res_spin_unlock] ||\n-\t btf_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave] ||\n-\t btf_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore];\n+\tint flags = PROCESS_RES_LOCK;\n+\n+\tif (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock]) ||\n+\t is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave]))\n+\t\tflags |= PROCESS_SPIN_LOCK;\n+\telse if (!is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock]) \u0026\u0026\n+\t\t !is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]))\n+\t\treturn 0;\n+\tif (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave]) ||\n+\t is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]))\n+\t\tflags |= PROCESS_LOCK_IRQ;\n+\treturn flags;\n }\n \n static bool kfunc_spin_allowed(struct bpf_verifier_env *env, s32 func_id, s16 offset)\n@@ -12786,697 +13347,6 @@ static bool check_css_task_iter_allowlist(struct bpf_verifier_env *env)\n \t}\n }\n \n-static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,\n-\t\t\t int insn_idx)\n-{\n-\tconst char *func_name = meta-\u003efunc_name, *ref_tname;\n-\tstruct bpf_func_state *caller = cur_func(env);\n-\tstruct bpf_reg_state *regs = cur_regs(env);\n-\tconst struct btf *btf = meta-\u003ebtf;\n-\tconst struct btf_param *args;\n-\tstruct btf_record *rec;\n-\tu32 i, nargs;\n-\tint ret;\n-\n-\targs = (const struct btf_param *)(meta-\u003efunc_proto + 1);\n-\tnargs = btf_type_vlen(meta-\u003efunc_proto);\n-\n-\tret = check_outgoing_stack_args(env, caller, nargs, func_name, btf, args);\n-\tif (ret)\n-\t\treturn ret;\n-\n-\t/* Check that BTF function arguments match actual types that the\n-\t * verifier sees.\n-\t */\n-\tfor (i = 0; i \u003c nargs; i++) {\n-\t\tstruct bpf_reg_state *reg = get_func_arg_reg(caller, regs, i);\n-\t\tconst struct btf_type *t, *ref_t, *resolve_ret;\n-\t\tenum bpf_arg_type arg_type = ARG_DONTCARE;\n-\t\targno_t argno = argno_from_arg(i + 1);\n-\t\tint regno = reg_from_argno(argno);\n-\t\tbool btf_id_fixed_off_ok = true;\n-\t\tu32 ref_id = args[i].type, type_size;\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-\t\t\tif (meta-\u003earg_prog) {\n-\t\t\t\tverifier_bug(env, \"Only 1 prog-\u003eaux argument supported per-kfunc\");\n-\t\t\t\treturn -EFAULT;\n-\t\t\t}\n-\t\t\tif (regno \u003c 0) {\n-\t\t\t\tverbose(env, \"%s prog-\u003eaux cannot be a stack argument\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tmeta-\u003earg_prog = true;\n-\t\t\tcur_aux(env)-\u003earg_prog = regno;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (is_kfunc_arg_ignore(btf, \u0026args[i]) || is_kfunc_arg_implicit(meta, i))\n-\t\t\tcontinue;\n-\n-\t\tt = btf_type_skip_modifiers(btf, args[i].type, NULL);\n-\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\tif (btf_type_is_ptr(t) \u0026\u0026\n-\t\t (bpf_register_is_null(reg) || type_may_be_null(reg-\u003etype)) \u0026\u0026\n-\t\t !type_may_be_null(kf_arg_type)) {\n-\t\t\tconst char *expected_type;\n-\n-\t\t\texpected_type = bpf_diag_fmt_btf_type(env, btf, args[i].type);\n-\t\t\tverbose(env, \"Possibly NULL pointer passed to trusted %s\\n\",\n-\t\t\t\treg_arg_name(env, argno));\n-\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t \"Add a NULL check and call the kfunc only on the non-NULL path.\",\n-\t\t\t\t\t \"the pointer may be NULL, but this kfunc requires a non-NULL value of type %s\",\n-\t\t\t\t\t expected_type);\n-\t\t\treturn -EACCES;\n-\t\t}\n-\n-\t\tif (regno == meta-\u003erelease_regno \u0026\u0026 !is_kfunc_arg_dynptr(meta-\u003ebtf, \u0026args[i]) \u0026\u0026\n-\t\t !reg_is_referenced(env, reg) \u0026\u0026 !bpf_register_is_null(reg)) {\n-\t\t\tconst char *expected_type;\n-\n-\t\t\texpected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);\n-\t\t\tverbose(env, \"release kfunc %s expects referenced PTR_TO_BTF_ID passed to %s\\n\",\n-\t\t\t\tfunc_name, reg_arg_name(env, argno));\n-\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t \"Pass the resource-owning pointer returned by the matching acquire kfunc, and avoid calling the release kfunc after ownership has already been transferred or released.\",\n-\t\t\t\t\t \"release kfuncs require a resource-owning value of type %s returned by a matching acquire kfunc\",\n-\t\t\t\t\t expected_type);\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\n-\t\tif (reg_is_referenced(env, reg))\n-\t\t\tupdate_ref_obj(\u0026meta-\u003eref_obj, reg);\n-\n-\t\tif (bpf_register_is_null(reg) \u0026\u0026 type_may_be_null(kf_arg_type))\n-\t\t\tcontinue;\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:\n-\t\tcase KF_ARG_CONST_MEM_SIZE:\n-\t\tcase KF_ARG_MEM_SIZE:\n-\t\tcase KF_ARG_ANYTHING:\n-\t\tcase KF_ARG_CONST_ALLOC_SIZE_OR_ZERO:\n-\t\tcase KF_ARG_PTR_TO_ALLOC_BTF_ID:\n-\t\tcase KF_ARG_PTR_TO_BTF_ID:\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_CALLBACK:\n-\t\tcase KF_ARG_PTR_TO_CONST_STR:\n-\t\tcase KF_ARG_PTR_TO_WORKQUEUE:\n-\t\tcase KF_ARG_PTR_TO_TIMER:\n-\t\tcase KF_ARG_PTR_TO_TASK_WORK:\n-\t\tcase KF_ARG_PTR_TO_IRQ_FLAG:\n-\t\tcase KF_ARG_PTR_TO_RES_SPIN_LOCK:\n-\t\tcase KF_ARG_PTR_TO_ARENA:\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_DYNPTR:\n-\t\t\targ_type = ARG_PTR_TO_DYNPTR;\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_CTX:\n-\t\t\targ_type = ARG_PTR_TO_CTX;\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_REFCOUNTED_KPTR:\n-\t\t\targ_type = ARG_PTR_TO_BTF_ID;\n-\t\t\tbtf_id_fixed_off_ok = false;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tverifier_bug(env, \"unknown kfunc arg type %d\", kf_arg_type);\n-\t\t\treturn -EFAULT;\n-\t\t}\n-\n-\t\tif (regno == meta-\u003erelease_regno)\n-\t\t\targ_type |= OBJ_RELEASE;\n-\t\tret = __check_func_arg_reg_off(env, reg, argno, arg_type,\n-\t\t\t\t\t btf_id_fixed_off_ok);\n-\t\tif (ret \u003c 0)\n-\t\t\treturn ret;\n-\n-\t\tswitch (base_type(kf_arg_type)) {\n-\t\tcase KF_ARG_CONST:\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\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass an integer scalar value for this argument, not a pointer or resource object.\",\n-\t\t\t\t\t\t \"the kfunc expects an integer scalar, but %s is %s\",\n-\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\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\tif (ret == -EINVAL)\n-\t\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t\t \"Pass a compile-time constant or a value the verifier can prove is constant at this call.\",\n-\t\t\t\t\t\t\t \"the kfunc requires this scalar argument to be a verifier-known constant, but %s is variable on this path\",\n-\t\t\t\t\t\t\t reg_arg_name(env, argno));\n-\t\t\t\treturn ret;\n-\t\t\t}\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\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass an integer scalar value for this argument, not a pointer or resource object.\",\n-\t\t\t\t\t\t \"the kfunc expects an integer scalar, but %s is %s\",\n-\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\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\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass an integer scalar value for this argument, not a pointer or resource object.\",\n-\t\t\t\t\t\t \"the kfunc expects an integer scalar, but %s is %s\",\n-\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\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\tif (ret == -EINVAL)\n-\t\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t\t \"Pass a verifier-known constant size for this kfunc buffer argument.\",\n-\t\t\t\t\t\t\t \"the kfunc uses this argument as a return-buffer size, but %s is invalid or variable on this path\",\n-\t\t\t\t\t\t\t reg_arg_name(env, argno));\n-\t\t\t\treturn ret;\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-\t\t\t\t\treg_arg_name(env, argno), reg_type_str(env, reg-\u003etype));\n-\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass the original program context pointer or preserve it before modifying registers.\",\n-\t\t\t\t\t\t \"the kfunc expects a context pointer, but %s is %s\",\n-\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\n-\t\t\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) {\n-\t\t\t\tret = get_kern_ctx_btf_id(\u0026env-\u003elog, resolve_prog_type(env-\u003eprog));\n-\t\t\t\tif (ret \u003c 0)\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\tmeta-\u003eret_btf_id = ret;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_ARENA:\n-\t\t\tif (reg-\u003etype != PTR_TO_ARENA \u0026\u0026 reg-\u003etype != SCALAR_VALUE) {\n-\t\t\t\tverbose(env, \"%s is not a pointer to arena or scalar\\n\",\n-\t\t\t\t\treg_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_ALLOC_BTF_ID:\n-\t\t\tif (reg-\u003etype == (PTR_TO_BTF_ID | MEM_ALLOC)) {\n-\t\t\t\tif (!is_bpf_obj_drop_kfunc(meta-\u003efunc_id)) {\n-\t\t\t\t\tverbose(env, \"%s expected for bpf_obj_drop()\\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} else if (reg-\u003etype == (PTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU)) {\n-\t\t\t\tif (!is_bpf_percpu_obj_drop_kfunc(meta-\u003efunc_id)) {\n-\t\t\t\t\tverbose(env, \"%s expected for bpf_percpu_obj_drop()\\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} else {\n-\t\t\t\tverbose(env, \"%s expected pointer to allocated object\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass a pointer returned by the matching BPF object allocation path.\",\n-\t\t\t\t\t\t \"the kfunc expects an allocated object pointer, but %s is %s\",\n-\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tif (!reg_is_referenced(env, reg)) {\n-\t\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n-\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass the owned object pointer before it is released or transferred.\",\n-\t\t\t\t\t\t \"the allocated object pointer in %s must still carry verifier-tracked ownership, but this pointer no longer owns a live resource\",\n-\t\t\t\t\t\t reg_arg_name(env, argno));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tif (meta-\u003ebtf == btf_vmlinux) {\n-\t\t\t\tmeta-\u003earg_btf = reg-\u003ebtf;\n-\t\t\t\tmeta-\u003earg_btf_id = reg-\u003ebtf_id;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_DYNPTR:\n-\t\t{\n-\t\t\tenum bpf_arg_type dynptr_arg_type = ARG_PTR_TO_DYNPTR;\n-\n-\t\t\tif (is_kfunc_arg_uninit(btf, \u0026args[i]))\n-\t\t\t\tdynptr_arg_type |= MEM_UNINIT;\n-\n-\t\t\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {\n-\t\t\t\tdynptr_arg_type |= DYNPTR_TYPE_SKB;\n-\t\t\t} else if (meta-\u003efunc_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) {\n-\t\t\t\tdynptr_arg_type |= DYNPTR_TYPE_XDP;\n-\t\t\t} else if (meta-\u003efunc_id == special_kfunc_list[KF_bpf_dynptr_from_skb_meta]) {\n-\t\t\t\tdynptr_arg_type |= DYNPTR_TYPE_SKB_META;\n-\t\t\t} else if (meta-\u003efunc_id == special_kfunc_list[KF_bpf_dynptr_from_file]) {\n-\t\t\t\tdynptr_arg_type |= DYNPTR_TYPE_FILE;\n-\t\t\t} else if (meta-\u003efunc_id == special_kfunc_list[KF_bpf_dynptr_file_discard]) {\n-\t\t\t\tdynptr_arg_type |= DYNPTR_TYPE_FILE | OBJ_RELEASE;\n-\t\t\t} else if (meta-\u003efunc_id == special_kfunc_list[KF_bpf_dynptr_clone] \u0026\u0026\n-\t\t\t\t (dynptr_arg_type \u0026 MEM_UNINIT)) {\n-\t\t\t\tenum bpf_dynptr_type parent_type = meta-\u003edynptr.type;\n-\n-\t\t\t\tif (parent_type == BPF_DYNPTR_TYPE_INVALID) {\n-\t\t\t\t\tverifier_bug(env, \"no dynptr type for parent of clone\");\n-\t\t\t\t\treturn -EFAULT;\n-\t\t\t\t}\n-\n-\t\t\t\tdynptr_arg_type |= (unsigned int)get_dynptr_type_flag(parent_type);\n-\t\t\t}\n-\n-\t\t\tret = process_dynptr_func(env, reg, argno, insn_idx, func_name,\n-\t\t\t\t\t\t dynptr_arg_type, \u0026meta-\u003eref_obj, \u0026meta-\u003edynptr);\n-\t\t\tif (ret \u003c 0)\n-\t\t\t\treturn ret;\n-\t\t\tbreak;\n-\t\t}\n-\t\tcase KF_ARG_PTR_TO_ITER:\n-\t\t\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_iter_css_task_new]) {\n-\t\t\t\tif (!check_css_task_iter_allowlist(env)) {\n-\t\t\t\t\tverbose(env, \"css_task_iter is only allowed in bpf_lsm, bpf_iter and sleepable progs\\n\");\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tret = process_iter_arg(env, reg, argno, insn_idx, 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_LIST_HEAD:\n-\t\t\tif (reg-\u003etype != PTR_TO_MAP_VALUE \u0026\u0026\n-\t\t\t reg-\u003etype != (PTR_TO_BTF_ID | MEM_ALLOC)) {\n-\t\t\t\tverbose(env, \"%s expected pointer to map value or allocated object\\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 (reg-\u003etype == (PTR_TO_BTF_ID | MEM_ALLOC) \u0026\u0026\n-\t\t\t !reg_is_referenced(env, reg)) {\n-\t\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tret = process_kf_arg_ptr_to_list_head(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_RB_ROOT:\n-\t\t\tif (reg-\u003etype != PTR_TO_MAP_VALUE \u0026\u0026\n-\t\t\t reg-\u003etype != (PTR_TO_BTF_ID | MEM_ALLOC)) {\n-\t\t\t\tverbose(env, \"%s expected pointer to map value or allocated object\\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 (reg-\u003etype == (PTR_TO_BTF_ID | MEM_ALLOC) \u0026\u0026\n-\t\t\t !reg_is_referenced(env, reg)) {\n-\t\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tret = process_kf_arg_ptr_to_rbtree_root(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_LIST_NODE:\n-\t\t\tif (is_kfunc_arg_nonown_allowed(btf, \u0026args[i]) \u0026\u0026\n-\t\t\t type_is_non_owning_ref(reg-\u003etype) \u0026\u0026 !reg_is_referenced(env, reg)) {\n-\t\t\t\t/* Allow bpf_list_front/back return value for\n-\t\t\t\t * __nonown_allowed list-node arguments.\n-\t\t\t\t */\n-\t\t\t\tgoto check_ok;\n-\t\t\t}\n-\t\t\tif (reg-\u003etype != (PTR_TO_BTF_ID | MEM_ALLOC)) {\n-\t\t\t\tverbose(env, \"%s expected pointer to allocated object\\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 (!reg_is_referenced(env, reg)) {\n-\t\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-check_ok:\n-\t\t\tret = process_kf_arg_ptr_to_list_node(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_RB_NODE:\n-\t\t\tif (is_bpf_rbtree_add_kfunc(meta-\u003efunc_id)) {\n-\t\t\t\tif (reg-\u003etype != (PTR_TO_BTF_ID | MEM_ALLOC)) {\n-\t\t\t\t\tverbose(env, \"%s expected pointer to allocated object\\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 (!reg_is_referenced(env, reg)) {\n-\t\t\t\t\tverbose(env, \"allocated object must be referenced\\n\");\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t}\n-\t\t\t} else {\n-\t\t\t\tif (!type_is_non_owning_ref(reg-\u003etype) \u0026\u0026\n-\t\t\t\t !reg_is_referenced(env, reg)) {\n-\t\t\t\t\tverbose(env, \"%s can only take non-owning or refcounted bpf_rb_node pointer\\n\", func_name);\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t}\n-\t\t\t\tif (in_rbtree_lock_required_cb(env)) {\n-\t\t\t\t\tverbose(env, \"%s not allowed in rbtree cb\\n\", func_name);\n-\t\t\t\t\treturn -EINVAL;\n-\t\t\t\t}\n-\t\t\t}\n-\n-\t\t\tret = process_kf_arg_ptr_to_rbtree_node(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_MAP_PTR:\n-\t\t\tif (base_type(reg-\u003etype) != CONST_PTR_TO_MAP ||\n-\t\t\t type_may_be_null(reg-\u003etype)) {\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_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_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-\t\t\t\tif (!is_trusted_reg(env, reg) ||\n-\t\t\t\t bpf_type_has_unsafe_modifiers(reg-\u003etype)) {\n-\t\t\t\t\tif (!is_kfunc_rcu(meta)) {\n-\t\t\t\t\t\tconst char *expected_type;\n-\n-\t\t\t\t\t\texpected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);\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\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t\t\t \"Pass a pointer acquired from a verifier-tracked source, or call this kfunc only inside the required protection if it accepts RCU pointers.\",\n-\t\t\t\t\t\t\t\t \"the kfunc requires a trusted or resource-owning pointer to %s, but %s is %s\",\n-\t\t\t\t\t\t\t\t expected_type,\n-\t\t\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\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\tconst char *expected_type;\n-\n-\t\t\t\t\t\texpected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);\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\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t\t\t \"Use this kfunc with a pointer that is valid in an RCU read lock region.\",\n-\t\t\t\t\t\t\t\t \"the kfunc requires an RCU-protected pointer to %s, but %s is %s\",\n-\t\t\t\t\t\t\t\t expected_type,\n-\t\t\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\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)) {\n-\t\t\t\tenum bpf_reg_type reg2btf_type = lookup_reg2btf_ids(ref_id);\n-\t\t\t\tconst char *expected_type;\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\texpected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);\n-\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass a verifier-tracked pointer to the expected kernel object type, not a pointer to stack storage or another memory buffer.\",\n-\t\t\t\t\t\t \"the kfunc expects a pointer to %s, but this argument is %s and cannot be used as that kernel object pointer\",\n-\t\t\t\t\t\t expected_type,\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\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\tbool known_memory;\n-\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,\n-\t\t\t\t\t\t meta, \u0026known_memory);\n-\t\t\t\tif (ret \u003c 0) {\n-\t\t\t\t\tconst char *expected_type;\n-\n-\t\t\t\t\texpected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);\n-\t\t\t\t\tif (known_memory)\n-\t\t\t\t\t\tbpf_diag_call_arg_fmt(\n-\t\t\t\t\t\t\tenv, insn_idx, argno, func_name,\n-\t\t\t\t\t\t\t\"Pass memory with at least the required number of accessible bytes and suitable read and write access.\",\n-\t\t\t\t\t\t\t\"the kfunc expects %u bytes of memory for %s, but the verifier cannot prove that %s provides a readable and writable range of that size\",\n-\t\t\t\t\t\t\ttype_size, expected_type,\n-\t\t\t\t\t\t\tbpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\t\telse\n-\t\t\t\t\t\tbpf_diag_call_arg_fmt(\n-\t\t\t\t\t\t\tenv, insn_idx, argno, func_name,\n-\t\t\t\t\t\t\t\"Pass stack, map, context, or other verifier-known memory of the expected type and size, not an integer cast to a pointer.\",\n-\t\t\t\t\t\t\t\"the kfunc expects %u bytes of memory for %s, but it is %s and not verifier-known memory\",\n-\t\t\t\t\t\t\ttype_size, expected_type,\n-\t\t\t\t\t\t\tbpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\t\treturn ret;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tbreak;\n-\t\tcase KF_ARG_CONST_MEM_SIZE:\n-\t\t\tret = process_const_arg(env, reg, argno, meta);\n-\t\t\tif (ret \u003c 0) {\n-\t\t\t\tif (ret == -EINVAL)\n-\t\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t\t \"Pass a compile-time constant or a value the verifier can prove is constant at this call.\",\n-\t\t\t\t\t\t\t \"the kfunc requires this memory size to be a verifier-known constant, but %s is variable on this path\",\n-\t\t\t\t\t\t\t reg_arg_name(env, argno));\n-\t\t\t\treturn ret;\n-\t\t\t}\n-\t\t\tfallthrough;\n-\t\tcase KF_ARG_MEM_SIZE:\n-\t\t{\n-\t\t\tstruct bpf_reg_state *buff_reg = get_func_arg_reg(caller, regs, i - 1);\n-\t\t\tstruct bpf_reg_state *size_reg = reg;\n-\t\t\targno_t buff_argno = argno_from_arg(i);\n-\t\t\tenum bpf_mem_size_failure failure;\n-\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\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass an integer scalar length for this memory argument.\",\n-\t\t\t\t\t\t \"the kfunc expects a scalar memory size, but %s is %s\",\n-\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\n-\t\t\tif (bpf_register_is_null(buff_reg))\n-\t\t\t\tbreak;\n-\n-\t\t\tret = check_mem_size_reg(env, buff_reg, size_reg, buff_argno, argno,\n-\t\t\t\t\t\t BPF_READ | BPF_WRITE, true, meta, \u0026failure);\n-\t\t\tif (ret \u003c 0) {\n-\t\t\t\tconst char *buff_arg, *size_arg;\n-\n-\t\t\t\tbuff_arg = bpf_diag_arg_name(env, buff_argno);\n-\t\t\t\tsize_arg = bpf_diag_arg_name(env, argno);\n-\t\t\t\tverbose(env, \"%s and \", reg_arg_name(env, buff_argno));\n-\t\t\t\tverbose(env, \"%s memory, len pair leads to invalid memory access\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\tif (failure == BPF_MEM_SIZE_FAIL_MEMORY) {\n-\t\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, buff_argno, func_name,\n-\t\t\t\t\t\t\t \"Pass a stack, map, context, or other verifier-known memory pointer, and keep the paired length within that object.\",\n-\t\t\t\t\t\t\t \"it is the memory pointer in a memory/length pair with %s, but %s does not describe verifier-readable memory for the requested length\",\n-\t\t\t\t\t\t\t size_arg, buff_arg);\n-\t\t\t\t} else if (failure == BPF_MEM_SIZE_FAIL_SIZE) {\n-\t\t\t\t\tif (reg_smin(size_reg) \u003c 0)\n-\t\t\t\t\t\tbpf_diag_call_arg_fmt(\n-\t\t\t\t\t\t\tenv, insn_idx, argno, func_name,\n-\t\t\t\t\t\t\t\"Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.\",\n-\t\t\t\t\t\t\t\"the memory size in %s may be negative because its signed minimum is %lld\",\n-\t\t\t\t\t\t\tsize_arg, reg_smin(size_reg));\n-\t\t\t\t\telse\n-\t\t\t\t\t\tbpf_diag_call_arg_fmt(\n-\t\t\t\t\t\t\tenv, insn_idx, argno, func_name,\n-\t\t\t\t\t\t\t\"Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.\",\n-\t\t\t\t\t\t\t\"the memory size in %s may reach %llu bytes, but variable memory accesses must stay below %u bytes\",\n-\t\t\t\t\t\t\tsize_arg, reg_umax(size_reg), BPF_MAX_VAR_SIZ);\n-\t\t\t\t}\n-\t\t\t\treturn ret;\n-\t\t\t}\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-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tmeta-\u003esubprogno = reg-\u003esubprogno;\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_REFCOUNTED_KPTR:\n-\t\t\tif (!type_is_ptr_alloc_obj(reg-\u003etype)) {\n-\t\t\t\tverbose(env, \"%s is neither owning or non-owning ref\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass an owning or non-owning pointer to a BPF-managed object containing a bpf_refcount field.\",\n-\t\t\t\t\t\t \"the kfunc expects a pointer to a BPF-managed refcounted object, but %s is %s\",\n-\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tif (!type_is_non_owning_ref(reg-\u003etype))\n-\t\t\t\tmeta-\u003earg_owning_ref = true;\n-\n-\t\t\trec = reg_btf_record(reg);\n-\t\t\tif (!rec) {\n-\t\t\t\tverifier_bug(env, \"Couldn't find btf_record\");\n-\t\t\t\treturn -EFAULT;\n-\t\t\t}\n-\n-\t\t\tif (rec-\u003erefcount_off \u003c 0) {\n-\t\t\t\tverbose(env, \"%s doesn't point to a type with bpf_refcount field\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\n-\t\t\tmeta-\u003earg_btf = reg-\u003ebtf;\n-\t\t\tmeta-\u003earg_btf_id = reg-\u003ebtf_id;\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_CONST_STR:\n-\t\t\tif (reg-\u003etype != PTR_TO_MAP_VALUE) {\n-\t\t\t\tverbose(env, \"%s doesn't point to a const string\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass a constant string pointer that the verifier recognizes, such as a string stored in a read-only map value.\",\n-\t\t\t\t\t\t \"the kfunc expects a pointer to a constant string stored in verifier-known memory, but %s is %s\",\n-\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tret = check_arg_const_str(env, reg, argno);\n-\t\t\tif (ret)\n-\t\t\t\treturn ret;\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_WORKQUEUE:\n-\t\t\tif (reg-\u003etype != PTR_TO_MAP_VALUE) {\n-\t\t\t\tverbose(env, \"%s doesn't point to a map value\\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 = check_map_field_pointer(env, reg, argno, BPF_WORKQUEUE, \u0026meta-\u003emap);\n-\t\t\tif (ret \u003c 0)\n-\t\t\t\treturn ret;\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_TIMER:\n-\t\t\tif (reg-\u003etype != PTR_TO_MAP_VALUE) {\n-\t\t\t\tverbose(env, \"%s doesn't point to a map value\\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_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-\t\tcase KF_ARG_PTR_TO_TASK_WORK:\n-\t\t\tif (reg-\u003etype != PTR_TO_MAP_VALUE) {\n-\t\t\t\tverbose(env, \"%s doesn't point to a map value\\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 = check_map_field_pointer(env, reg, argno, BPF_TASK_WORK, \u0026meta-\u003emap);\n-\t\t\tif (ret \u003c 0)\n-\t\t\t\treturn ret;\n-\t\t\tbreak;\n-\t\tcase KF_ARG_PTR_TO_IRQ_FLAG:\n-\t\t\tif (reg-\u003etype != PTR_TO_STACK) {\n-\t\t\t\tverbose(env, \"%s doesn't point to an irq flag on stack\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\tbpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,\n-\t\t\t\t\t\t \"Pass the same stack slot used by bpf_local_irq_save() or bpf_res_spin_lock_irqsave().\",\n-\t\t\t\t\t\t \"the kfunc expects a stack pointer to an IRQ flag slot, but %s is %s\",\n-\t\t\t\t\t\t reg_arg_name(env, argno),\n-\t\t\t\t\t\t bpf_diag_reg_type_plain(env, reg-\u003etype));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t\tret = process_irq_flag(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_RES_SPIN_LOCK:\n-\t\t{\n-\t\t\tint flags = PROCESS_RES_LOCK;\n-\n-\t\t\tif (reg-\u003etype != PTR_TO_MAP_VALUE \u0026\u0026 reg-\u003etype != (PTR_TO_BTF_ID | MEM_ALLOC)) {\n-\t\t\t\tverbose(env, \"%s doesn't point to map value or allocated object\\n\",\n-\t\t\t\t\treg_arg_name(env, argno));\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\n-\t\t\tif (!is_bpf_res_spin_lock_kfunc(meta-\u003efunc_id))\n-\t\t\t\treturn -EFAULT;\n-\t\t\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_res_spin_lock] ||\n-\t\t\t meta-\u003efunc_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave])\n-\t\t\t\tflags |= PROCESS_SPIN_LOCK;\n-\t\t\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave] ||\n-\t\t\t meta-\u003efunc_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore])\n-\t\t\t\tflags |= PROCESS_LOCK_IRQ;\n-\t\t\tret = process_spin_lock(env, reg, argno, flags);\n-\t\t\tif (ret \u003c 0)\n-\t\t\t\treturn ret;\n-\t\t\tbreak;\n-\t\t}\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n \n int bpf_fetch_kfunc_arg_meta(struct bpf_verifier_env *env,\n \t\t\t s32 func_id,\n@@ -13808,12 +13678,12 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg\n \t\tstruct btf_field *field = meta-\u003earg_rbtree_root.field;\n \n \t\tmark_reg_graph_node(regs, BPF_REG_0, \u0026field-\u003egraph_root);\n-\t} else if (meta-\u003efunc_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) {\n+\t} else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_cast_to_kern_ctx])) {\n \t\tmark_reg_known_zero(env, regs, BPF_REG_0);\n \t\tregs[BPF_REG_0].type = PTR_TO_BTF_ID | PTR_TRUSTED;\n \t\tregs[BPF_REG_0].btf = desc_btf;\n \t\tregs[BPF_REG_0].btf_id = meta-\u003eret_btf_id;\n-\t} else if (meta-\u003efunc_id == special_kfunc_list[KF_bpf_rdonly_cast]) {\n+\t} else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_rdonly_cast])) {\n \t\tret_t = btf_type_by_id(desc_btf, meta-\u003earg_constant.value);\n \t\tif (!ret_t) {\n \t\t\tverbose(env, \"Unknown type ID %lld passed to kfunc bpf_rdonly_cast\\n\",\n@@ -13833,8 +13703,8 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg\n \t\t\t\t\"kfunc bpf_rdonly_cast type ID argument must be of a struct or void\\n\");\n \t\t\treturn -EINVAL;\n \t\t}\n-\t} else if (meta-\u003efunc_id == special_kfunc_list[KF_bpf_dynptr_slice] ||\n-\t\t meta-\u003efunc_id == special_kfunc_list[KF_bpf_dynptr_slice_rdwr]) {\n+\t} else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_slice]) ||\n+\t\t is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_slice_rdwr])) {\n \t\tenum bpf_type_flag type_flag = get_dynptr_type_flag(meta-\u003edynptr.type);\n \n \t\tmark_reg_known_zero(env, regs, BPF_REG_0);\n@@ -13849,7 +13719,7 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg\n \t\t/* PTR_MAYBE_NULL will be added when is_kfunc_ret_null is checked */\n \t\tregs[BPF_REG_0].type = PTR_TO_MEM | type_flag;\n \n-\t\tif (meta-\u003efunc_id == special_kfunc_list[KF_bpf_dynptr_slice]) {\n+\t\tif (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_slice])) {\n \t\t\tregs[BPF_REG_0].type |= MEM_RDONLY;\n \t\t} else {\n \t\t\t/* this will set env-\u003eseen_direct_write to true */\n@@ -13969,7 +13839,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\n \t\tinsn_aux-\u003enon_sleepable = true;\n \n \t/* Check the arguments */\n-\terr = check_kfunc_args(env, \u0026meta, insn_idx);\n+\terr = check_func_args(env, \u0026meta, insn_idx);\n \tif (err \u003c 0)\n \t\treturn err;\n \n@@ -17823,7 +17693,7 @@ bool bpf_get_call_summary(struct bpf_verifier_env *env, struct bpf_insn *call,\n \t\tcs-\u003eis_void = fn-\u003eret_type == RET_VOID;\n \t\tcs-\u003enum_params = 0;\n \t\tfor (i = 0; i \u003c ARRAY_SIZE(fn-\u003earg_type); ++i) {\n-\t\t\tif (fn-\u003earg_type[i] == ARG_DONTCARE)\n+\t\t\tif (fn-\u003earg_type[i] == ARG_UNUSED)\n \t\t\t\tbreak;\n \t\t\tcs-\u003enum_params++;\n \t\t}\n@@ -19619,7 +19489,7 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)\n \t\t\t}\n \n \t\t\t/* Also ensure the callback only has a single scalar argument. */\n-\t\t\tif (sub-\u003earg_cnt != 1 || sub-\u003eargs[0].arg_type != ARG_ANYTHING) {\n+\t\t\tif (sub-\u003earg_cnt != 1 || sub-\u003eargs[0].arg_type != ARG_SCALAR) {\n \t\t\t\tverbose(env, \"exception cb only supports single integer argument\\n\");\n \t\t\t\tret = -EINVAL;\n \t\t\t\tgoto out;\n@@ -19632,7 +19502,7 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)\n \t\t\tif (arg-\u003earg_type == ARG_PTR_TO_CTX) {\n \t\t\t\treg-\u003etype = PTR_TO_CTX;\n \t\t\t\tmark_reg_known_zero(env, regs, i);\n-\t\t\t} else if (arg-\u003earg_type == ARG_ANYTHING) {\n+\t\t\t} else if (arg-\u003earg_type == ARG_SCALAR) {\n \t\t\t\treg-\u003etype = SCALAR_VALUE;\n \t\t\t\tmark_reg_unknown(env, regs, i);\n \t\t\t} else if (arg-\u003earg_type == ARG_PTR_TO_DYNPTR) {\ndiff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c\nindex 29260951aa871..e414858581d04 100644\n--- a/kernel/trace/bpf_trace.c\n+++ b/kernel/trace/bpf_trace.c\n@@ -195,7 +195,7 @@ static const struct bpf_func_proto bpf_override_return_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n #endif\n \n@@ -222,7 +222,7 @@ const struct bpf_func_proto bpf_probe_read_user_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n static __always_inline int\n@@ -259,7 +259,7 @@ const struct bpf_func_proto bpf_probe_read_user_str_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_probe_read_kernel, void *, dst, u32, size,\n@@ -274,7 +274,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n static __always_inline int\n@@ -309,7 +309,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_str_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n #ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE\n@@ -329,7 +329,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_probe_read_compat_str, void *, dst, u32, size,\n@@ -348,7 +348,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_str_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg2_type\t= ARG_MEM_SIZE_OR_ZERO,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n #endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */\n \n@@ -381,7 +381,7 @@ static const struct bpf_func_proto bpf_probe_write_user_proto = {\n \t.func\t\t= bpf_probe_write_user,\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n \t.arg2_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg3_type\t= ARG_MEM_SIZE,\n };\n@@ -560,7 +560,7 @@ static const struct bpf_func_proto bpf_seq_printf_btf_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n static __always_inline int\n@@ -606,7 +606,7 @@ const struct bpf_func_proto bpf_perf_event_read_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_perf_event_read_value, struct bpf_map *, map, u64, flags,\n@@ -631,7 +631,7 @@ static const struct bpf_func_proto bpf_perf_event_read_value_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg4_type\t= ARG_MEM_SIZE,\n };\n@@ -728,7 +728,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n@@ -914,7 +914,7 @@ const struct bpf_func_proto bpf_send_signal_proto = {\n \t.func\t\t= bpf_send_signal,\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_1(bpf_send_signal_thread, u32, sig)\n@@ -926,7 +926,7 @@ const struct bpf_func_proto bpf_send_signal_thread_proto = {\n \t.func\t\t= bpf_send_signal_thread,\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_d_path, const struct path *, path, char *, buf, u32, sz)\n@@ -1056,7 +1056,7 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = {\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_MEM_SIZE,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_1(bpf_get_func_ip_tracing, void *, ctx)\n@@ -1236,7 +1236,7 @@ static const struct bpf_func_proto bpf_get_func_arg_proto = {\n \t.func\t\t= get_func_arg,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,\n \t.arg3_size\t= sizeof(u64),\n };\n@@ -1419,7 +1419,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_tp = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n@@ -1444,7 +1444,7 @@ static const struct bpf_func_proto bpf_get_stackid_proto_tp = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_get_stack_tp, void *, tp_buff, void *, buf, u32, size,\n@@ -1463,7 +1463,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_tp = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n static const struct bpf_func_proto *\n@@ -1567,7 +1567,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type = ARG_ANYTHING,\n+\t.arg4_type = ARG_SCALAR,\n };\n \n static const struct bpf_func_proto *\n@@ -1644,7 +1644,7 @@ static const struct bpf_func_proto bpf_perf_event_output_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_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n@@ -1676,7 +1676,7 @@ static const struct bpf_func_proto bpf_get_stackid_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_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_get_stack_raw_tp, struct bpf_raw_tracepoint_args *, args,\n@@ -1702,7 +1702,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n static const struct bpf_func_proto *\ndiff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c\nindex 1d295a8769fad..ad0f8f2222226 100644\n--- a/net/core/bpf_sk_storage.c\n+++ b/net/core/bpf_sk_storage.c\n@@ -333,7 +333,7 @@ const struct bpf_func_proto bpf_sk_storage_get_proto = {\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n \t.arg2_type\t= ARG_PTR_TO_BTF_ID_SOCK_COMMON,\n \t.arg3_type\t= ARG_PTR_TO_MAP_VALUE_OR_NULL,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n const struct bpf_func_proto bpf_sk_storage_get_cg_sock_proto = {\n@@ -343,7 +343,7 @@ const struct bpf_func_proto bpf_sk_storage_get_cg_sock_proto = {\n \t.arg1_type\t= ARG_CONST_MAP_PTR,\n \t.arg2_type\t= ARG_PTR_TO_CTX, /* context is 'struct sock' */\n \t.arg3_type\t= ARG_PTR_TO_MAP_VALUE_OR_NULL,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n const struct bpf_func_proto bpf_sk_storage_delete_proto = {\n@@ -408,7 +408,7 @@ const struct bpf_func_proto bpf_sk_storage_get_tracing_proto = {\n \t.arg2_type\t= ARG_PTR_TO_BTF_ID_OR_NULL,\n \t.arg2_btf_id\t= \u0026btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],\n \t.arg3_type\t= ARG_PTR_TO_MAP_VALUE_OR_NULL,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n \t.allowed\t= bpf_sk_storage_tracing_allowed,\n };\n \ndiff --git a/net/core/filter.c b/net/core/filter.c\nindex 61940e7535523..89f8755989c5c 100644\n--- a/net/core/filter.c\n+++ b/net/core/filter.c\n@@ -1746,10 +1746,10 @@ static const struct bpf_func_proto bpf_skb_store_bytes_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg4_type\t= ARG_MEM_SIZE,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n int __bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from,\n@@ -1783,7 +1783,7 @@ static const struct bpf_func_proto bpf_skb_load_bytes_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg4_type\t= ARG_MEM_SIZE,\n };\n@@ -1822,7 +1822,7 @@ static const struct bpf_func_proto bpf_flow_dissector_load_bytes_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg4_type\t= ARG_MEM_SIZE,\n };\n@@ -1866,10 +1866,10 @@ static const struct bpf_func_proto bpf_skb_load_bytes_relative_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg4_type\t= ARG_MEM_SIZE,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_skb_pull_data, struct sk_buff *, skb, u32, len)\n@@ -1891,7 +1891,7 @@ static const struct bpf_func_proto bpf_skb_pull_data_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_1(bpf_sk_fullsock, struct sock *, sk)\n@@ -1931,7 +1931,7 @@ static const struct bpf_func_proto sk_skb_pull_data_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_l3_csum_replace, struct sk_buff *, skb, u32, offset,\n@@ -1972,10 +1972,10 @@ static const struct bpf_func_proto bpf_l3_csum_replace_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_l4_csum_replace, struct sk_buff *, skb, u32, offset,\n@@ -2026,10 +2026,10 @@ static const struct bpf_func_proto bpf_l4_csum_replace_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_csum_diff, __be32 *, from, u32, from_size,\n@@ -2067,7 +2067,7 @@ static const struct bpf_func_proto bpf_csum_diff_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_csum_update, struct sk_buff *, skb, __wsum, csum)\n@@ -2087,7 +2087,7 @@ static const struct bpf_func_proto bpf_csum_update_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_csum_level, struct sk_buff *, skb, u64, level)\n@@ -2121,7 +2121,7 @@ static const struct bpf_func_proto bpf_csum_level_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n static inline int __bpf_rx_skb(struct net_device *dev, struct sk_buff *skb)\n@@ -2506,8 +2506,8 @@ static const struct bpf_func_proto bpf_clone_redirect_proto = {\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n-\t.arg3_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n+\t.arg3_type = ARG_SCALAR,\n };\n \n static struct net_device *skb_get_peer_dev(struct net_device *dev)\n@@ -2575,8 +2575,8 @@ static const struct bpf_func_proto bpf_redirect_proto = {\n \t.func = bpf_redirect,\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n-\t.arg1_type = ARG_ANYTHING,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg1_type = ARG_SCALAR,\n+\t.arg2_type = ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_redirect_peer, u32, ifindex, u64, flags)\n@@ -2597,8 +2597,8 @@ static const struct bpf_func_proto bpf_redirect_peer_proto = {\n \t.func = bpf_redirect_peer,\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n-\t.arg1_type = ARG_ANYTHING,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg1_type = ARG_SCALAR,\n+\t.arg2_type = ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_redirect_neigh, u32, ifindex, struct bpf_redir_neigh *, params,\n@@ -2625,10 +2625,10 @@ static const struct bpf_func_proto bpf_redirect_neigh_proto = {\n \t.func\t\t= bpf_redirect_neigh,\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n-\t.arg1_type\t= ARG_ANYTHING,\n+\t.arg1_type\t= ARG_SCALAR,\n \t.arg2_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,\n \t.arg3_type = ARG_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_msg_apply_bytes, struct sk_msg *, msg, u32, bytes)\n@@ -2642,7 +2642,7 @@ static const struct bpf_func_proto bpf_msg_apply_bytes_proto = {\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_msg_cork_bytes, struct sk_msg *, msg, u32, bytes)\n@@ -2701,7 +2701,7 @@ static const struct bpf_func_proto bpf_msg_cork_bytes_proto = {\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,\n@@ -2836,9 +2836,9 @@ static const struct bpf_func_proto bpf_msg_pull_data_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,\n@@ -3001,9 +3001,9 @@ static const struct bpf_func_proto bpf_msg_push_data_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n static void sk_msg_shift_left(struct sk_msg *msg, int i)\n@@ -3185,9 +3185,9 @@ static const struct bpf_func_proto bpf_msg_pop_data_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n #ifdef CONFIG_CGROUP_NET_CLASSID\n@@ -3292,7 +3292,7 @@ static const struct bpf_func_proto bpf_set_hash_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_skb_vlan_push, struct sk_buff *, skb, __be16, vlan_proto,\n@@ -3318,8 +3318,8 @@ static const struct bpf_func_proto bpf_skb_vlan_push_proto = {\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n-\t.arg3_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n+\t.arg3_type = ARG_SCALAR,\n };\n \n BPF_CALL_1(bpf_skb_vlan_pop, struct sk_buff *, skb)\n@@ -3532,8 +3532,8 @@ static const struct bpf_func_proto bpf_skb_change_proto_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_skb_change_type, struct sk_buff *, skb, u32, pkt_type)\n@@ -3552,7 +3552,7 @@ static const struct bpf_func_proto bpf_skb_change_type_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n static u32 bpf_skb_net_base_len(const struct sk_buff *skb)\n@@ -3839,9 +3839,9 @@ static const struct bpf_func_proto sk_skb_adjust_room_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,\n@@ -3944,9 +3944,9 @@ static const struct bpf_func_proto bpf_skb_adjust_room_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n static u32 __bpf_skb_min_len(const struct sk_buff *skb)\n@@ -4040,8 +4040,8 @@ static const struct bpf_func_proto bpf_skb_change_tail_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(sk_skb_change_tail, struct sk_buff *, skb, u32, new_len,\n@@ -4055,8 +4055,8 @@ static const struct bpf_func_proto sk_skb_change_tail_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n static inline int __bpf_skb_change_head(struct sk_buff *skb, u32 head_room,\n@@ -4107,8 +4107,8 @@ static const struct bpf_func_proto bpf_skb_change_head_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(sk_skb_change_head, struct sk_buff *, skb, u32, head_room,\n@@ -4122,8 +4122,8 @@ static const struct bpf_func_proto sk_skb_change_head_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_1(bpf_xdp_get_buff_len, struct xdp_buff*, xdp)\n@@ -4178,7 +4178,7 @@ static const struct bpf_func_proto bpf_xdp_adjust_head_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off,\n@@ -4282,7 +4282,7 @@ static const struct bpf_func_proto bpf_xdp_load_bytes_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg4_type\t= ARG_MEM_SIZE,\n };\n@@ -4314,7 +4314,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg4_type\t= ARG_MEM_SIZE,\n };\n@@ -4453,7 +4453,7 @@ static const struct bpf_func_proto bpf_xdp_adjust_tail_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_2(bpf_xdp_adjust_meta, struct xdp_buff *, xdp, int, offset)\n@@ -4480,7 +4480,7 @@ static const struct bpf_func_proto bpf_xdp_adjust_meta_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n /**\n@@ -4825,8 +4825,8 @@ static const struct bpf_func_proto bpf_xdp_redirect_proto = {\n \t.func = bpf_xdp_redirect,\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n-\t.arg1_type = ARG_ANYTHING,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg1_type = ARG_SCALAR,\n+\t.arg2_type = ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_xdp_redirect_map, struct bpf_map *, map, u64, key,\n@@ -4840,8 +4840,8 @@ static const struct bpf_func_proto bpf_xdp_redirect_map_proto = {\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_CONST_MAP_PTR,\n-\t.arg2_type = ARG_ANYTHING,\n-\t.arg3_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n+\t.arg3_type = ARG_SCALAR,\n };\n \n static unsigned long bpf_skb_copy(void *dst_buff, const void *skb,\n@@ -4877,7 +4877,7 @@ static const struct bpf_func_proto bpf_skb_event_output_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n@@ -4891,7 +4891,7 @@ const struct bpf_func_proto bpf_skb_output_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026bpf_skb_output_btf_ids[0],\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n@@ -4977,7 +4977,7 @@ static const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = {\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_MEM_SIZE,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_skb_get_tunnel_opt, struct sk_buff *, skb, u8 *, to, u32, size)\n@@ -5094,7 +5094,7 @@ static const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = {\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_MEM_SIZE,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_skb_set_tunnel_opt, struct sk_buff *, skb,\n@@ -5175,7 +5175,7 @@ static const struct bpf_func_proto bpf_skb_under_cgroup_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n #ifdef CONFIG_SOCK_CGROUP_DATA\n@@ -5232,7 +5232,7 @@ static const struct bpf_func_proto bpf_skb_ancestor_cgroup_id_proto = {\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n };\n \n BPF_CALL_1(bpf_sk_cgroup_id, struct sock *, sk)\n@@ -5257,7 +5257,7 @@ static const struct bpf_func_proto bpf_sk_ancestor_cgroup_id_proto = {\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n };\n #endif\n \n@@ -5291,7 +5291,7 @@ static const struct bpf_func_proto bpf_xdp_event_output_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n@@ -5305,7 +5305,7 @@ const struct bpf_func_proto bpf_xdp_output_proto = {\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026bpf_xdp_output_btf_ids[0],\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE_OR_ZERO,\n };\n@@ -5853,8 +5853,8 @@ const struct bpf_func_proto bpf_sk_setsockopt_proto = {\n \t.gpl_only\t= false,\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_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -5870,8 +5870,8 @@ const struct bpf_func_proto bpf_sk_getsockopt_proto = {\n \t.gpl_only\t= false,\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_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -5894,8 +5894,8 @@ const struct bpf_func_proto bpf_sk_setsockopt_nodelay_proto = {\n \t.gpl_only\t= false,\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_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -5911,8 +5911,8 @@ const struct bpf_func_proto bpf_unlocked_sk_setsockopt_proto = {\n \t.gpl_only\t= false,\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_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -5928,8 +5928,8 @@ const struct bpf_func_proto bpf_unlocked_sk_getsockopt_proto = {\n \t.gpl_only\t= false,\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_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -5945,8 +5945,8 @@ static const struct bpf_func_proto bpf_sock_addr_setsockopt_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -5962,8 +5962,8 @@ static const struct bpf_func_proto bpf_sock_addr_getsockopt_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -6007,8 +6007,8 @@ static const struct bpf_func_proto bpf_sock_create_setsockopt_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -6033,8 +6033,8 @@ static const struct bpf_func_proto bpf_sock_create_getsockopt_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -6059,8 +6059,8 @@ static const struct bpf_func_proto bpf_sock_ops_setsockopt_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -6169,8 +6169,8 @@ static const struct bpf_func_proto bpf_sock_ops_getsockopt_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n \t.arg4_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg5_type\t= ARG_MEM_SIZE,\n };\n@@ -6197,7 +6197,7 @@ static const struct bpf_func_proto bpf_sock_ops_cb_flags_set_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_bind, struct bpf_sock_addr_kern *, ctx, struct sockaddr *, addr,\n@@ -6290,10 +6290,10 @@ static const struct bpf_func_proto bpf_skb_get_xfrm_state_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg4_type\t= ARG_MEM_SIZE,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n #endif\n \n@@ -6700,7 +6700,7 @@ static const struct bpf_func_proto bpf_xdp_fib_lookup_proto = {\n \t.arg1_type = ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,\n \t.arg3_type = ARG_MEM_SIZE,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_skb_fib_lookup, struct sk_buff *, skb,\n@@ -6760,7 +6760,7 @@ static const struct bpf_func_proto bpf_skb_fib_lookup_proto = {\n \t.arg1_type = ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,\n \t.arg3_type = ARG_MEM_SIZE,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n static struct net_device *__dev_via_ifindex(struct net_device *dev_curr,\n@@ -6857,11 +6857,11 @@ static const struct bpf_func_proto bpf_skb_check_mtu_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n \t.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_WRITE | MEM_ALIGNED,\n \t.arg3_size\t= sizeof(u32),\n-\t.arg4_type = ARG_ANYTHING,\n-\t.arg5_type = ARG_ANYTHING,\n+\t.arg4_type = ARG_SCALAR,\n+\t.arg5_type = ARG_SCALAR,\n };\n \n static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {\n@@ -6869,11 +6869,11 @@ static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {\n \t.gpl_only\t= true,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n \t.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_WRITE | MEM_ALIGNED,\n \t.arg3_size\t= sizeof(u32),\n-\t.arg4_type = ARG_ANYTHING,\n-\t.arg5_type = ARG_ANYTHING,\n+\t.arg4_type = ARG_SCALAR,\n+\t.arg5_type = ARG_SCALAR,\n };\n \n #if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\n@@ -6955,7 +6955,7 @@ static const struct bpf_func_proto bpf_lwt_in_push_encap_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg4_type\t= ARG_MEM_SIZE\n };\n@@ -6965,7 +6965,7 @@ static const struct bpf_func_proto bpf_lwt_xmit_push_encap_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg4_type\t= ARG_MEM_SIZE\n };\n@@ -7009,7 +7009,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_store_bytes_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg4_type\t= ARG_MEM_SIZE\n };\n@@ -7098,7 +7098,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_action_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg4_type\t= ARG_MEM_SIZE\n };\n@@ -7159,8 +7159,8 @@ static const struct bpf_func_proto bpf_lwt_seg6_adjust_srh_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n #endif /* CONFIG_IPV6_SEG6_BPF */\n \n@@ -7332,8 +7332,8 @@ static const struct bpf_func_proto bpf_skc_lookup_tcp_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_sk_lookup_tcp, struct sk_buff *, skb,\n@@ -7351,8 +7351,8 @@ static const struct bpf_func_proto bpf_sk_lookup_tcp_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_sk_lookup_udp, struct sk_buff *, skb,\n@@ -7370,8 +7370,8 @@ static const struct bpf_func_proto bpf_sk_lookup_udp_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_tc_skc_lookup_tcp, struct sk_buff *, skb,\n@@ -7394,8 +7394,8 @@ static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_tc_sk_lookup_tcp, struct sk_buff *, skb,\n@@ -7418,8 +7418,8 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_tc_sk_lookup_udp, struct sk_buff *, skb,\n@@ -7442,8 +7442,8 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_udp_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_1(bpf_sk_release, struct sock *, sk)\n@@ -7480,8 +7480,8 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_udp_proto = {\n \t.arg1_type = ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg3_type = ARG_MEM_SIZE_OR_ZERO,\n-\t.arg4_type = ARG_ANYTHING,\n-\t.arg5_type = ARG_ANYTHING,\n+\t.arg4_type = ARG_SCALAR,\n+\t.arg5_type = ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_xdp_skc_lookup_tcp, struct xdp_buff *, ctx,\n@@ -7504,8 +7504,8 @@ static const struct bpf_func_proto bpf_xdp_skc_lookup_tcp_proto = {\n \t.arg1_type = ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg3_type = ARG_MEM_SIZE_OR_ZERO,\n-\t.arg4_type = ARG_ANYTHING,\n-\t.arg5_type = ARG_ANYTHING,\n+\t.arg4_type = ARG_SCALAR,\n+\t.arg5_type = ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_xdp_sk_lookup_tcp, struct xdp_buff *, ctx,\n@@ -7528,8 +7528,8 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_tcp_proto = {\n \t.arg1_type = ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,\n \t.arg3_type = ARG_MEM_SIZE_OR_ZERO,\n-\t.arg4_type = ARG_ANYTHING,\n-\t.arg5_type = ARG_ANYTHING,\n+\t.arg4_type = ARG_SCALAR,\n+\t.arg5_type = ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_sock_addr_skc_lookup_tcp, struct bpf_sock_addr_kern *, ctx,\n@@ -7548,8 +7548,8 @@ static const struct bpf_func_proto bpf_sock_addr_skc_lookup_tcp_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_sock_addr_sk_lookup_tcp, struct bpf_sock_addr_kern *, ctx,\n@@ -7567,8 +7567,8 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_tcp_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_5(bpf_sock_addr_sk_lookup_udp, struct bpf_sock_addr_kern *, ctx,\n@@ -7586,8 +7586,8 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_udp_proto = {\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_MEM_SIZE_OR_ZERO,\n-\t.arg4_type\t= ARG_ANYTHING,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n bool bpf_tcp_sock_is_valid_access(int off, int size, enum bpf_access_type type,\n@@ -8006,7 +8006,7 @@ static const struct bpf_func_proto bpf_sk_assign_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n static const u8 *bpf_search_tcp_opt(const u8 *op, const u8 *opend,\n@@ -8131,7 +8131,7 @@ static const struct bpf_func_proto bpf_sock_ops_load_hdr_opt_proto = {\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_MEM_SIZE,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_sock_ops_store_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,\n@@ -8209,7 +8209,7 @@ static const struct bpf_func_proto bpf_sock_ops_store_hdr_opt_proto = {\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_MEM_SIZE,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_sock_ops_reserve_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,\n@@ -8234,8 +8234,8 @@ static const struct bpf_func_proto bpf_sock_ops_reserve_hdr_opt_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_3(bpf_skb_set_tstamp, struct sk_buff *, skb,\n@@ -8275,8 +8275,8 @@ static const struct bpf_func_proto bpf_skb_set_tstamp_proto = {\n \t.gpl_only = false,\n \t.ret_type = RET_INTEGER,\n \t.arg1_type = ARG_PTR_TO_CTX,\n-\t.arg2_type = ARG_ANYTHING,\n-\t.arg3_type = ARG_ANYTHING,\n+\t.arg2_type = ARG_SCALAR,\n+\t.arg3_type = ARG_SCALAR,\n };\n \n #ifdef CONFIG_SYN_COOKIES\n@@ -11787,7 +11787,7 @@ static const struct bpf_func_proto sk_select_reuseport_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_CONST_MAP_PTR,\n \t.arg3_type = ARG_PTR_TO_MAP_KEY,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(sk_reuseport_load_bytes,\n@@ -11802,7 +11802,7 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg4_type\t= ARG_MEM_SIZE,\n };\n@@ -11820,10 +11820,10 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_relative_proto = {\n \t.gpl_only\t= false,\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n \t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n \t.arg4_type\t= ARG_MEM_SIZE,\n-\t.arg5_type\t= ARG_ANYTHING,\n+\t.arg5_type\t= ARG_SCALAR,\n };\n \n static const struct bpf_func_proto *\n@@ -12010,7 +12010,7 @@ static const struct bpf_func_proto bpf_sk_lookup_assign_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_SOCKET_OR_NULL,\n-\t.arg3_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_SCALAR,\n };\n \n static const struct bpf_func_proto *\ndiff --git a/net/core/sock_map.c b/net/core/sock_map.c\nindex ca49bc7f8687c..03d95aac8b606 100644\n--- a/net/core/sock_map.c\n+++ b/net/core/sock_map.c\n@@ -641,7 +641,7 @@ const struct bpf_func_proto bpf_sock_map_update_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n \t.arg3_type\t= ARG_PTR_TO_MAP_KEY,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_sk_redirect_map, struct sk_buff *, skb,\n@@ -668,8 +668,8 @@ const struct bpf_func_proto bpf_sk_redirect_map_proto = {\n \t.ret_type = RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_CONST_MAP_PTR,\n-\t.arg3_type = ARG_ANYTHING,\n-\t.arg4_type = ARG_ANYTHING,\n+\t.arg3_type = ARG_SCALAR,\n+\t.arg4_type = ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_msg_redirect_map, struct sk_msg *, msg,\n@@ -699,8 +699,8 @@ const struct bpf_func_proto bpf_msg_redirect_map_proto = {\n \t.ret_type = RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_CONST_MAP_PTR,\n-\t.arg3_type = ARG_ANYTHING,\n-\t.arg4_type = ARG_ANYTHING,\n+\t.arg3_type = ARG_SCALAR,\n+\t.arg4_type = ARG_SCALAR,\n };\n \n struct sock_map_seq_info {\n@@ -1247,7 +1247,7 @@ const struct bpf_func_proto bpf_sock_hash_update_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type\t= ARG_CONST_MAP_PTR,\n \t.arg3_type\t= ARG_PTR_TO_MAP_KEY,\n-\t.arg4_type\t= ARG_ANYTHING,\n+\t.arg4_type\t= ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_sk_redirect_hash, struct sk_buff *, skb,\n@@ -1275,7 +1275,7 @@ const struct bpf_func_proto bpf_sk_redirect_hash_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_CONST_MAP_PTR,\n \t.arg3_type = ARG_PTR_TO_MAP_KEY,\n-\t.arg4_type = ARG_ANYTHING,\n+\t.arg4_type = ARG_SCALAR,\n };\n \n BPF_CALL_4(bpf_msg_redirect_hash, struct sk_msg *, msg,\n@@ -1306,7 +1306,7 @@ const struct bpf_func_proto bpf_msg_redirect_hash_proto = {\n \t.arg1_type\t= ARG_PTR_TO_CTX,\n \t.arg2_type = ARG_CONST_MAP_PTR,\n \t.arg3_type = ARG_PTR_TO_MAP_KEY,\n-\t.arg4_type = ARG_ANYTHING,\n+\t.arg4_type = ARG_SCALAR,\n };\n \n struct sock_hash_seq_info {\ndiff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c\nindex 791e15063237c..3684c0434da17 100644\n--- a/net/ipv4/bpf_tcp_ca.c\n+++ b/net/ipv4/bpf_tcp_ca.c\n@@ -132,7 +132,7 @@ static const struct bpf_func_proto bpf_tcp_send_ack_proto = {\n \t.ret_type\t= RET_INTEGER,\n \t.arg1_type\t= ARG_PTR_TO_BTF_ID,\n \t.arg1_btf_id\t= \u0026tcp_sock_id,\n-\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg2_type\t= ARG_SCALAR,\n };\n \n static u32 prog_ops_moff(const struct bpf_prog *prog)\ndiff --git a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c\nindex 14d4c1793aed5..d74a9db54c9a3 100644\n--- a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c\n+++ b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c\n@@ -13,13 +13,13 @@ struct {\n \tconst char *prog_name;\n \tconst char *err_msg;\n } test_bpf_nf_fail_tests[] = {\n-\t{ \"alloc_release\", \"kernel function bpf_ct_release R1 expected pointer to STRUCT nf_conn but\" },\n-\t{ \"insert_insert\", \"kernel function bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but\" },\n-\t{ \"lookup_insert\", \"kernel function bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but\" },\n-\t{ \"set_timeout_after_insert\", \"kernel function bpf_ct_set_timeout R1 expected pointer to STRUCT nf_conn___init but\" },\n-\t{ \"set_status_after_insert\", \"kernel function bpf_ct_set_status R1 expected pointer to STRUCT nf_conn___init but\" },\n-\t{ \"change_timeout_after_alloc\", \"kernel function bpf_ct_change_timeout R1 expected pointer to STRUCT nf_conn but\" },\n-\t{ \"change_status_after_alloc\", \"kernel function bpf_ct_change_status R1 expected pointer to STRUCT nf_conn but\" },\n+\t{ \"alloc_release\", \"bpf_ct_release R1 expected pointer to STRUCT nf_conn but\" },\n+\t{ \"insert_insert\", \"bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but\" },\n+\t{ \"lookup_insert\", \"bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but\" },\n+\t{ \"set_timeout_after_insert\", \"bpf_ct_set_timeout R1 expected pointer to STRUCT nf_conn___init but\" },\n+\t{ \"set_status_after_insert\", \"bpf_ct_set_status R1 expected pointer to STRUCT nf_conn___init but\" },\n+\t{ \"change_timeout_after_alloc\", \"bpf_ct_change_timeout R1 expected pointer to STRUCT nf_conn but\" },\n+\t{ \"change_status_after_alloc\", \"bpf_ct_change_status R1 expected pointer to STRUCT nf_conn but\" },\n \t{ \"write_not_allowlisted_field\", \"no write support to nf_conn at off\" },\n \t{ \"lookup_null_bpf_tuple\", \"Possibly NULL pointer passed to trusted R2\" },\n \t{ \"lookup_null_bpf_opts\", \"Possibly NULL pointer passed to trusted R4\" },\ndiff --git a/tools/testing/selftests/bpf/prog_tests/cb_refs.c b/tools/testing/selftests/bpf/prog_tests/cb_refs.c\nindex 78566b817fd70..504d395d59622 100644\n--- a/tools/testing/selftests/bpf/prog_tests/cb_refs.c\n+++ b/tools/testing/selftests/bpf/prog_tests/cb_refs.c\n@@ -11,8 +11,8 @@ struct {\n \tconst char *prog_name;\n \tconst char *err_msg;\n } cb_refs_tests[] = {\n-\t{ \"underflow_prog\", \"release kfunc bpf_kfunc_call_test_release expects referenced PTR_TO_BTF_ID passed to R1\" },\n-\t{ \"leak_prog\", \"Possibly NULL pointer passed to helper R2\" },\n+\t{ \"underflow_prog\", \"R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_\" },\n+\t{ \"leak_prog\", \"Unreleased reference id=4 alloc_insn=33\" },\n \t{ \"nested_cb\", \"Unreleased reference id=4 alloc_insn=2\" }, /* alloc_insn=2{4,5} */\n \t{ \"non_cb_transfer_ref\", \"Unreleased reference id=4 alloc_insn=1\" }, /* alloc_insn=1{1,2} */\n };\ndiff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c\nindex 2b39cc1b09f9a..0063e60d6f2f5 100644\n--- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c\n+++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c\n@@ -70,7 +70,7 @@ static struct kfunc_test_params kfunc_tests[] = {\n \tTC_FAIL(kfunc_call_test_get_mem_fail_oversized, 0, \"allocation size exceeds u32 max\"),\n \tTC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, \"is not a const\"),\n \tTC_FAIL(kfunc_call_test_mem_acquire_fail, 0, \"acquire kernel function does not return PTR_TO_BTF_ID\"),\n-\tTC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, \"R1 expected pointer to ctx, but got scalar\"),\n+\tTC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, \"R1 type=scalar expected=ctx\"),\n \tTC_FAIL(kfunc_call_test_spin_lock_unsafe, 0, \"function calls are not allowed while holding a lock\"),\n \n \t/* success cases */\ndiff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c\nindex f7f94ccebce27..b973814482481 100644\n--- a/tools/testing/selftests/bpf/prog_tests/verifier.c\n+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c\n@@ -54,6 +54,7 @@\n #include \"verifier_iterating_callbacks.skel.h\"\n #include \"verifier_jeq_infer_not_null.skel.h\"\n #include \"verifier_jit_convergence.skel.h\"\n+#include \"verifier_kfunc_packet_access.skel.h\"\n #include \"verifier_ld_ind.skel.h\"\n #include \"verifier_ldsx.skel.h\"\n #include \"verifier_leak_ptr.skel.h\"\n@@ -218,6 +219,7 @@ void test_verifier_int_ptr(void) { RUN(verifier_int_ptr); }\n void test_verifier_iterating_callbacks(void) { RUN(verifier_iterating_callbacks); }\n void test_verifier_jeq_infer_not_null(void) { RUN(verifier_jeq_infer_not_null); }\n void test_verifier_jit_convergence(void) { RUN(verifier_jit_convergence); }\n+void test_verifier_kfunc_packet_access(void) { RUN_TESTS(verifier_kfunc_packet_access); }\n void test_verifier_load_acquire(void) { RUN(verifier_load_acquire); }\n void test_verifier_ld_ind(void) { RUN(verifier_ld_ind); }\n void test_verifier_ldsx(void) { RUN(verifier_ldsx); }\ndiff --git a/tools/testing/selftests/bpf/progs/arena_kfunc.c b/tools/testing/selftests/bpf/progs/arena_kfunc.c\nindex 50609f3b0564a..6578cf12fa27d 100644\n--- a/tools/testing/selftests/bpf/progs/arena_kfunc.c\n+++ b/tools/testing/selftests/bpf/progs/arena_kfunc.c\n@@ -205,7 +205,7 @@ int arena_arg_no_arena(void *ctx)\n SEC(\"syscall\")\n __arch_x86_64\n __arch_arm64\n-__failure __msg(\"is not a pointer to arena or scalar\")\n+__failure __msg(\"R1 type=fp expected=arena, scalar\")\n int arena_arg_bad_reg(void *ctx)\n {\n \tu64 buf = 0;\ndiff --git a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c\nindex efe7bcae70f85..ede6a17d7da30 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 is fp expected STRUCT cgroup\")\n+__failure __msg(\"R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_\")\n int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path)\n {\n \tstruct cgroup *acquired, *stack_cgrp = (struct cgroup *)\u0026path;\n@@ -154,7 +154,7 @@ int BPF_PROG(cgrp_kfunc_xchg_unreleased, struct cgroup *cgrp, const char *path)\n }\n \n SEC(\"tp_btf/cgroup_mkdir\")\n-__failure __msg(\"release kfunc bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"release function bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1\")\n int BPF_PROG(cgrp_kfunc_rcu_get_release, struct cgroup *cgrp, const char *path)\n {\n \tstruct cgroup *kptr;\n@@ -191,7 +191,7 @@ int BPF_PROG(cgrp_kfunc_release_untrusted, struct cgroup *cgrp, const char *path\n }\n \n SEC(\"tp_btf/cgroup_mkdir\")\n-__failure __msg(\"release kfunc bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_\")\n int BPF_PROG(cgrp_kfunc_release_fp, struct cgroup *cgrp, const char *path)\n {\n \tstruct cgroup *acquired = (struct cgroup *)\u0026path;\n@@ -237,7 +237,7 @@ int BPF_PROG(cgrp_kfunc_release_null, struct cgroup *cgrp, const char *path)\n }\n \n SEC(\"tp_btf/cgroup_mkdir\")\n-__failure __msg(\"release kfunc bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"release function bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1\")\n int BPF_PROG(cgrp_kfunc_release_unacquired, struct cgroup *cgrp, const char *path)\n {\n \t/* Cannot release trusted cgroup pointer which was not acquired. */\ndiff --git a/tools/testing/selftests/bpf/progs/cpumask_failure.c b/tools/testing/selftests/bpf/progs/cpumask_failure.c\nindex 4628feb53d861..c89c88db39d14 100644\n--- a/tools/testing/selftests/bpf/progs/cpumask_failure.c\n+++ b/tools/testing/selftests/bpf/progs/cpumask_failure.c\n@@ -183,7 +183,7 @@ int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone\n }\n \n SEC(\"tp_btf/task_newtask\")\n-__failure __msg(\"Possibly NULL pointer passed to helper R2\")\n+__failure __msg(\"release function bpf_kptr_xchg expects referenced PTR_TO_BTF_ID passed to R2\")\n int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags)\n {\n \tstruct bpf_cpumask *prev, *curr;\n@@ -243,7 +243,7 @@ int BPF_PROG(test_populate_invalid_destination, struct task_struct *task, u64 cl\n }\n \n SEC(\"tp_btf/task_newtask\")\n-__failure __msg(\"leads to invalid memory access\")\n+__failure __msg(\"R2 type=scalar expected=fp\")\n int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_flags)\n {\n \tvoid *garbage = (void *)0x123456;\ndiff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c\nindex a4a007866a332..53df6d248e267 100644\n--- a/tools/testing/selftests/bpf/progs/irq.c\n+++ b/tools/testing/selftests/bpf/progs/irq.c\n@@ -15,7 +15,7 @@ struct bpf_res_spin_lock lockA __hidden SEC(\".data.A\");\n struct bpf_res_spin_lock lockB __hidden SEC(\".data.B\");\n \n SEC(\"?tc\")\n-__failure __msg(\"R1 doesn't point to an irq flag on stack\")\n+__failure __msg(\"R1 type=map_value expected=fp\")\n int irq_save_bad_arg(struct __sk_buff *ctx)\n {\n \tbpf_local_irq_save(\u0026global_flags);\n@@ -23,7 +23,7 @@ int irq_save_bad_arg(struct __sk_buff *ctx)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"R1 doesn't point to an irq flag on stack\")\n+__failure __msg(\"R1 type=map_value expected=fp\")\n int irq_restore_bad_arg(struct __sk_buff *ctx)\n {\n \tbpf_local_irq_restore(\u0026global_flags);\ndiff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c\nindex 62d7df9e80beb..e4d099c533aa7 100644\n--- a/tools/testing/selftests/bpf/progs/iters.c\n+++ b/tools/testing/selftests/bpf/progs/iters.c\n@@ -1688,7 +1688,7 @@ int iter_subprog_check_stacksafe(const void *ctx)\n struct bpf_iter_num global_it;\n \n SEC(\"raw_tp\")\n-__failure __msg(\"R1 expected pointer to an iterator on stack\")\n+__failure __msg(\"R1 type=map_value expected=fp\")\n int iter_new_bad_arg(const void *ctx)\n {\n \tbpf_iter_num_new(\u0026global_it, 0, 1);\n@@ -1696,7 +1696,7 @@ int iter_new_bad_arg(const void *ctx)\n }\n \n SEC(\"raw_tp\")\n-__failure __msg(\"R1 expected pointer to an iterator on stack\")\n+__failure __msg(\"R1 type=map_value expected=fp\")\n int iter_next_bad_arg(const void *ctx)\n {\n \tbpf_iter_num_next(\u0026global_it);\n@@ -1704,7 +1704,7 @@ int iter_next_bad_arg(const void *ctx)\n }\n \n SEC(\"raw_tp\")\n-__failure __msg(\"R1 expected pointer to an iterator on stack\")\n+__failure __msg(\"R1 type=map_value expected=fp\")\n int iter_destroy_bad_arg(const void *ctx)\n {\n \tbpf_iter_num_destroy(\u0026global_it);\ndiff --git a/tools/testing/selftests/bpf/progs/iters_testmod.c b/tools/testing/selftests/bpf/progs/iters_testmod.c\nindex 76012dbbdb413..f65cc9766633e 100644\n--- a/tools/testing/selftests/bpf/progs/iters_testmod.c\n+++ b/tools/testing/selftests/bpf/progs/iters_testmod.c\n@@ -105,8 +105,7 @@ int iter_next_rcu_not_trusted(const void *ctx)\n }\n \n SEC(\"raw_tp/sys_enter\")\n-__failure __msg(\"R1 cannot write into rdonly_mem\")\n-/* Message should not be 'R1 cannot write into rdonly_trusted_mem' */\n+__failure __msg(\"R1 type=rdonly_mem expected=fp\")\n int iter_next_ptr_mem_not_trusted(const void *ctx)\n {\n \tstruct bpf_iter_num num_it;\n@@ -135,7 +134,7 @@ int iter_ret_rcu_test_protected(const void *ctx)\n }\n \n SEC(\"?fentry.s/\" SYS_PREFIX \"sys_getpgid\")\n-__failure __msg(\"R1 type=rcu_ptr_or_null_ expected=\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n int iter_ret_rcu_test_type(const void *ctx)\n {\n \tstruct task_struct *p;\n@@ -158,7 +157,7 @@ int iter_ret_rcu_test_protected_nostruct(const void *ctx)\n }\n \n SEC(\"?fentry.s/\" SYS_PREFIX \"sys_getpgid\")\n-__failure __msg(\"R1 type=rdonly_rcu_mem_or_null expected=\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n int iter_ret_rcu_test_type_nostruct(const void *ctx)\n {\n \tvoid *p;\ndiff --git a/tools/testing/selftests/bpf/progs/map_kptr_fail.c b/tools/testing/selftests/bpf/progs/map_kptr_fail.c\nindex 5e25ca806060c..4b64f1dc7b81b 100644\n--- a/tools/testing/selftests/bpf/progs/map_kptr_fail.c\n+++ b/tools/testing/selftests/bpf/progs/map_kptr_fail.c\n@@ -149,7 +149,7 @@ int reject_bad_type_match(struct __sk_buff *ctx)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"R1 type=untrusted_ptr_or_null_ expected=percpu_ptr_\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n int marked_as_untrusted_or_null(struct __sk_buff *ctx)\n {\n \tstruct map_value *v;\n@@ -217,7 +217,7 @@ int reject_kptr_xchg_on_unref(struct __sk_buff *ctx)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"R1 type=rcu_ptr_or_null_ expected=percpu_ptr_\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n int mark_ref_as_untrusted_or_null(struct __sk_buff *ctx)\n {\n \tstruct map_value *v;\n@@ -252,7 +252,7 @@ int reject_untrusted_store_to_ref(struct __sk_buff *ctx)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"release helper bpf_kptr_xchg expects referenced PTR_TO_BTF_ID passed to R2\")\n+__failure __msg(\"release function bpf_kptr_xchg expects referenced PTR_TO_BTF_ID passed to R2\")\n int reject_untrusted_xchg(struct __sk_buff *ctx)\n {\n \tstruct prog_test_ref_kfunc *p;\n@@ -291,7 +291,7 @@ int reject_bad_type_xchg(struct __sk_buff *ctx)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"invalid kptr access, R2 type=trusted_ptr_prog_test_ref_kfunc\")\n+__failure __msg(\"R2 must have zero offset when passed to release func\")\n int reject_member_of_ref_xchg(struct __sk_buff *ctx)\n {\n \tstruct prog_test_ref_kfunc *ref_ptr;\n@@ -364,7 +364,7 @@ int kptr_xchg_ref_state(struct __sk_buff *ctx)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"Possibly NULL pointer passed to helper R2\")\n+__success\n int kptr_xchg_possibly_null(struct __sk_buff *ctx)\n {\n \tstruct prog_test_ref_kfunc *p;\ndiff --git a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c\nindex 3e0d4f687aaad..23019023511af 100644\n--- a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c\n+++ b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c\n@@ -118,8 +118,7 @@ int atomic_rmw_not_ok(void *ctx)\n \n SEC(\"socket\")\n __failure\n-__msg(\"invalid access to memory, mem_size=0 off=0 size=4\")\n-__msg(\"R1 min value is outside of the allowed memory range\")\n+__msg(\"R1 type=rdonly_untrusted_mem expected=fp\")\n int kfunc_param_not_ok(void *ctx)\n {\n \tint *p;\ndiff --git a/tools/testing/selftests/bpf/progs/rbtree_fail.c b/tools/testing/selftests/bpf/progs/rbtree_fail.c\nindex 555379952dcc2..80494e00ede3a 100644\n--- a/tools/testing/selftests/bpf/progs/rbtree_fail.c\n+++ b/tools/testing/selftests/bpf/progs/rbtree_fail.c\n@@ -179,7 +179,7 @@ long rbtree_api_use_unchecked_remove_retval(void *ctx)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"bpf_rbtree_remove can only take non-owning or refcounted bpf_rb_node pointer\")\n+__failure __msg(\"R2 type=scalar expected=ptr_, ptr_, rcu_ptr_\")\n long rbtree_api_add_release_unlock_escape(void *ctx)\n {\n \tstruct node_data *n;\n@@ -203,7 +203,7 @@ long rbtree_api_add_release_unlock_escape(void *ctx)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"bpf_rbtree_remove can only take non-owning or refcounted bpf_rb_node pointer\")\n+__failure __msg(\"R2 type=scalar expected=ptr_, ptr_, rcu_ptr_\")\n long rbtree_api_first_release_unlock_escape(void *ctx)\n {\n \tstruct bpf_rb_node *res;\ndiff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c\nindex eaaed0859f946..8a98e901382d9 100644\n--- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c\n+++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c\n@@ -82,8 +82,8 @@ long refcount_acquire_maybe_null(void *ctx)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"R1 is neither owning or non-owning ref\")\n-__msg(\"expects a pointer to a BPF-managed refcounted object, but R1 is a context pointer\")\n+__failure __msg(\"R1 type=ctx expected=ptr_, ptr_, rcu_ptr_\")\n+__msg(\"type ctx, but this argument accepts ptr_, ptr_, rcu_ptr_\")\n long refcount_acquire_non_object(void *ctx)\n {\n \treturn bpf_refcount_acquire(ctx) != NULL;\ndiff --git a/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c b/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c\nindex 330682a88c161..8fd591bd1f6cf 100644\n--- a/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c\n+++ b/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c\n@@ -24,7 +24,7 @@ struct bpf_spin_lock lock __hidden SEC(\".data.A\");\n struct bpf_res_spin_lock res_lock __hidden SEC(\".data.B\");\n \n SEC(\"?tc\")\n-__failure __msg(\"point to map value or allocated object\")\n+__failure __msg(\"R1 type=untrusted_ptr_ expected=map_value, ptr_\")\n int res_spin_lock_arg(struct __sk_buff *ctx)\n {\n \tstruct arr_elem *elem;\ndiff --git a/tools/testing/selftests/bpf/progs/stream_fail.c b/tools/testing/selftests/bpf/progs/stream_fail.c\nindex 21428bb1ee597..10ebb4a7f105a 100644\n--- a/tools/testing/selftests/bpf/progs/stream_fail.c\n+++ b/tools/testing/selftests/bpf/progs/stream_fail.c\n@@ -23,7 +23,7 @@ int stream_vprintk_scalar_arg(void *ctx)\n }\n \n SEC(\"syscall\")\n-__failure __msg(\"R2 doesn't point to a const string\")\n+__failure __msg(\"R2 type=ctx expected=map_value\")\n int stream_vprintk_string_arg(void *ctx)\n {\n \tbpf_stream_vprintk(BPF_STDOUT, ctx, NULL, 0);\ndiff --git a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c\nindex f96b0c13ed1a5..12c8ac6099cae 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 is fp expected STRUCT task_struct\")\n+__failure __msg(\"R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_\")\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;\n@@ -179,7 +179,7 @@ int BPF_PROG(task_kfunc_release_untrusted, struct task_struct *task, u64 clone_f\n }\n \n SEC(\"tp_btf/task_newtask\")\n-__failure __msg(\"release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_\")\n int BPF_PROG(task_kfunc_release_fp, struct task_struct *task, u64 clone_flags)\n {\n \tstruct task_struct *acquired = (struct task_struct *)\u0026clone_flags;\n@@ -225,7 +225,7 @@ int BPF_PROG(task_kfunc_release_null, struct task_struct *task, u64 clone_flags)\n }\n \n SEC(\"tp_btf/task_newtask\")\n-__failure __msg(\"release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"release function bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1\")\n int BPF_PROG(task_kfunc_release_unacquired, struct task_struct *task, u64 clone_flags)\n {\n \t/* Cannot release trusted task pointer which was not acquired. */\n@@ -333,7 +333,7 @@ int BPF_PROG(task_access_comm2, struct task_struct *task, u64 clone_flags)\n }\n \n SEC(\"tp_btf/task_newtask\")\n-__failure __msg(\"write into memory\")\n+__failure __msg(\"only read is supported\")\n int BPF_PROG(task_access_comm3, struct task_struct *task, u64 clone_flags)\n {\n \tbpf_probe_read_kernel(task-\u003ecomm, 16, task-\u003ecomm);\n@@ -353,7 +353,7 @@ int BPF_PROG(task_access_comm4, struct task_struct *task, const char *buf, bool\n }\n \n SEC(\"tp_btf/task_newtask\")\n-__failure __msg(\"release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"release function bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1\")\n int BPF_PROG(task_kfunc_release_in_map, struct task_struct *task, u64 clone_flags)\n {\n \tstruct task_struct *local;\ndiff --git a/tools/testing/selftests/bpf/progs/task_work_fail.c b/tools/testing/selftests/bpf/progs/task_work_fail.c\nindex 3186e7b4b24e0..bc56bdaca780b 100644\n--- a/tools/testing/selftests/bpf/progs/task_work_fail.c\n+++ b/tools/testing/selftests/bpf/progs/task_work_fail.c\n@@ -58,7 +58,7 @@ int mismatch_map(struct pt_regs *args)\n }\n \n SEC(\"perf_event\")\n-__failure __msg(\"R2 doesn't point to a map value\")\n+__failure __msg(\"R2 type=fp expected=map_value\")\n int no_map_task_work(struct pt_regs *args)\n {\n \tstruct task_struct *task;\ndiff --git a/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c b/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c\nindex bf48fc43c7ab6..f7a83e5024543 100644\n--- a/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c\n+++ b/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c\n@@ -40,7 +40,7 @@ int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size,\n }\n \n SEC(\"?lsm.s/bpf\")\n-__failure __msg(\"R1 expected pointer to stack or const struct bpf_dynptr\")\n+__failure __msg(\"R1 type=map_value expected=fp, dynptr_ptr\")\n int BPF_PROG(not_ptr_to_stack, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)\n {\n \tstatic struct bpf_dynptr val;\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_ctx.c b/tools/testing/selftests/bpf/progs/verifier_ctx.c\nindex 7856dad3d1f38..9d42ba8244082 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_ctx.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_ctx.c\n@@ -208,7 +208,7 @@ __naked void null_check_7_ctx_bind(void)\n \n SEC(\"cgroup/post_bind4\")\n __description(\"pass ctx or null check, 8: null (bind)\")\n-__failure __msg(\"R1 type=scalar expected=ctx\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n __naked void null_check_8_null_bind(void)\n {\n \tasm volatile (\"\t\t\t\t\t\\\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c\nindex 0bdeb7bc4687a..87604020ba212 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c\n@@ -153,7 +153,7 @@ __weak int subprog_trusted_destroy(struct task_struct *task __arg_trusted)\n \n SEC(\"?tp_btf/task_newtask\")\n __failure __log_level(2)\n-__msg(\"release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__msg(\"release function bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1\")\n int BPF_PROG(trusted_destroy_fail, struct task_struct *task, u64 clone_flags)\n {\n \treturn subprog_trusted_destroy(task);\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 343fc08d97479..d1452ef6f2f9a 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@@ -621,7 +621,7 @@ l0_%=:\texit;\t\t\t\t\t\t\\\n \n SEC(\"tracepoint\")\n __description(\"helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)\")\n-__failure __msg(\"R1 type=scalar expected=fp\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n __naked void ptr_to_mem_or_null_8(void)\n {\n \tasm volatile (\"\t\t\t\t\t\\\n@@ -637,7 +637,7 @@ __naked void ptr_to_mem_or_null_8(void)\n \n SEC(\"tracepoint\")\n __description(\"helper access to variable memory: size \u003e 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)\")\n-__failure __msg(\"R1 type=scalar expected=fp\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n __naked void ptr_to_mem_or_null_9(void)\n {\n \tasm volatile (\"\t\t\t\t\t\\\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c\nindex 71cee3f583243..12786b72c6948 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c\n@@ -258,7 +258,7 @@ l0_%=:\tr0 = 0;\t\t\t\t\t\t\\\n \n SEC(\"tc\")\n __description(\"helper access to packet: test11, cls unsuitable helper 1\")\n-__failure __msg(\"helper access to the packet\")\n+__failure __msg(\"function access to the packet\")\n __naked void test11_cls_unsuitable_helper_1(void)\n {\n \tasm volatile (\"\t\t\t\t\t\\\n@@ -283,7 +283,7 @@ l0_%=:\tr0 = 0;\t\t\t\t\t\t\\\n \n SEC(\"tc\")\n __description(\"helper access to packet: test12, cls unsuitable helper 2\")\n-__failure __msg(\"helper access to the packet\")\n+__failure __msg(\"function access to the packet\")\n __naked void test12_cls_unsuitable_helper_2(void)\n {\n \tasm volatile (\"\t\t\t\t\t\\\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_kfunc_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_kfunc_packet_access.c\nnew file mode 100644\nindex 0000000000000..9ae63c9eab02d\n--- /dev/null\n+++ b/tools/testing/selftests/bpf/progs/verifier_kfunc_packet_access.c\n@@ -0,0 +1,47 @@\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+\n+struct nf_conn *bpf_skb_ct_lookup(struct __sk_buff *skb_ctx,\n+\t\t\t\t struct bpf_sock_tuple *bpf_tuple,\n+\t\t\t\t u32 tuple__sz, struct bpf_ct_opts *opts,\n+\t\t\t\t u32 opts__sz) __ksym;\n+void bpf_ct_release(struct nf_conn *nfct) __ksym;\n+\n+char _license[] SEC(\"license\") = \"GPL\";\n+\n+SEC(\"tc\")\n+__description(\"kfunc packet write requests writable skb\")\n+__success\n+/* bpf_unclone_prologue() */\n+__xlated(\"r6 = *(u8 *)(r1 +{{[0-9]+}})\")\n+__xlated(\"...\")\n+__xlated(\"w6 \u0026= {{1|128}}\")\n+__xlated(\"...\")\n+__xlated(\"if r6 == 0x0 goto\")\n+__xlated(\"r6 = r1\")\n+__xlated(\"r2 ^= r2\")\n+__xlated(\"call\")\n+__xlated(\"if r0 == 0x0 goto\")\n+__xlated(\"w0 = 2\")\n+__xlated(\"...\")\n+__xlated(\"exit\")\n+__xlated(\"r1 = r6\")\n+int kfunc_packet_write(struct __sk_buff *skb)\n+{\n+\tvoid *data_end = (void *)(long)skb-\u003edata_end;\n+\tvoid *data = (void *)(long)skb-\u003edata;\n+\tstruct bpf_sock_tuple tuple = {};\n+\tstruct nf_conn *nfct;\n+\n+\tif (data + sizeof(struct bpf_ct_opts) \u003e data_end)\n+\t\treturn 0;\n+\n+\t/* An invalid tuple size makes bpf_skb_ct_lookup() write opts-\u003eerror. */\n+\tnfct = bpf_skb_ct_lookup(skb, \u0026tuple, 1, data, sizeof(struct bpf_ct_opts));\n+\tif (nfct)\n+\t\tbpf_ct_release(nfct);\n+\treturn 0;\n+}\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_live_stack.c b/tools/testing/selftests/bpf/progs/verifier_live_stack.c\nindex 401152b2b64fc..bc3dfdc1a5363 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_live_stack.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_live_stack.c\n@@ -246,7 +246,7 @@ static __used __naked void read_first_param2(void)\n SEC(\"socket\")\n __flag(BPF_F_TEST_STATE_FREQ)\n __failure\n-__msg(\"R1 type=scalar expected=map_ptr\")\n+__msg(\"Possibly NULL pointer passed to trusted R1\")\n __naked void caller_stack_pruning_callback(void)\n {\n \tasm volatile (\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_map_in_map.c b/tools/testing/selftests/bpf/progs/verifier_map_in_map.c\nindex d3be69a9a7557..621248a02a1f9 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_map_in_map.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_map_in_map.c\n@@ -154,8 +154,7 @@ l0_%=:\tr0 = 0;\t\t\t\t\t\t\\\n \n SEC(\"socket\")\n __description(\"forgot null checking on the inner map pointer\")\n-__failure __msg(\"R1 type=map_ptr_or_null expected=map_ptr\")\n-__msg(\"map_ptr_or_null, but this argument accepts map_ptr\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n __failure_unpriv\n __naked void on_the_inner_map_pointer(void)\n {\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c b/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c\nindex c01abf54923d3..4b1eadddd89cd 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c\n@@ -58,7 +58,7 @@ int mapofmaps_value_as_helper_mem_buf(struct __sk_buff *skb)\n }\n \n SEC(\"?tc\")\n-__failure __msg(\"type=map_ptr_or_null expected=fp\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n int mapofmaps_value_as_helper_fixed_mem(struct __sk_buff *skb)\n {\n \tchar th[sizeof(struct tcphdr)] = {};\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c b/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c\nindex 199ad18f8eb58..799db6f5713b0 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c\n@@ -344,7 +344,7 @@ __naked void potential_reference_to_system_key(void)\n \n SEC(\"tc\")\n __description(\"reference tracking: release reference without check\")\n-__failure __msg(\"type=sock_or_null expected=sock\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n __naked void tracking_release_reference_without_check(void)\n {\n \tasm volatile (\n@@ -363,7 +363,7 @@ __naked void tracking_release_reference_without_check(void)\n \n SEC(\"tc\")\n __description(\"reference tracking: release reference to sock_common without check\")\n-__failure __msg(\"type=sock_common_or_null expected=sock\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n __naked void to_sock_common_without_check(void)\n {\n \tasm volatile (\n@@ -1288,7 +1288,7 @@ l1_%=:\tr1 = r6;\t\t\t\t\t\\\n \n SEC(\"tc\")\n __description(\"reference tracking: bpf_sk_release(listen_sk)\")\n-__failure __msg(\"release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1\")\n __naked void bpf_sk_release_listen_sk(void)\n {\n \tasm volatile (\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_sock.c b/tools/testing/selftests/bpf/progs/verifier_sock.c\nindex 4f2f3209eec81..2a136c917680f 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_sock.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_sock.c\n@@ -110,7 +110,7 @@ l0_%=:\tr0 = *(u32*)(r1 + %[bpf_sock_type]);\t\t\\\n \n SEC(\"cgroup/skb\")\n __description(\"bpf_sk_fullsock(skb-\u003esk): no !skb-\u003esk check\")\n-__failure __msg(\"type=sock_common_or_null expected=sock_common\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n __failure_unpriv\n __naked void sk_no_skb_sk_check_1(void)\n {\n@@ -466,7 +466,7 @@ l1_%=:\tr0 = *(u32*)(r0 + %[bpf_sock_rx_queue_mapping__end]);\\\n \n SEC(\"cgroup/skb\")\n __description(\"bpf_tcp_sock(skb-\u003esk): no !skb-\u003esk check\")\n-__failure __msg(\"type=sock_common_or_null expected=sock_common\")\n+__failure __msg(\"Possibly NULL pointer passed to trusted R1\")\n __failure_unpriv\n __naked void sk_no_skb_sk_check_2(void)\n {\n@@ -603,7 +603,7 @@ l2_%=:\tr0 = *(u32*)(r0 + %[bpf_tcp_sock_snd_cwnd]);\t\\\n \n SEC(\"tc\")\n __description(\"bpf_sk_release(skb-\u003esk)\")\n-__failure __msg(\"release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1\")\n __naked void bpf_sk_release_skb_sk(void)\n {\n \tasm volatile (\"\t\t\t\t\t\\\n@@ -620,7 +620,7 @@ l0_%=:\tr0 = 0;\t\t\t\t\t\t\\\n \n SEC(\"tc\")\n __description(\"bpf_sk_release(bpf_sk_fullsock(skb-\u003esk))\")\n-__failure __msg(\"release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1\")\n __naked void bpf_sk_fullsock_skb_sk(void)\n {\n \tasm volatile (\"\t\t\t\t\t\\\n@@ -644,7 +644,7 @@ l1_%=:\tr1 = r0;\t\t\t\t\t\\\n \n SEC(\"tc\")\n __description(\"bpf_sk_release(bpf_tcp_sock(skb-\u003esk))\")\n-__failure __msg(\"release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1\")\n __naked void bpf_tcp_sock_skb_sk(void)\n {\n \tasm volatile (\"\t\t\t\t\t\\\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c\nindex 8f0c45421f893..b5f456d57669e 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 is fp expected STRUCT task_struct\")\n+__failure __msg(\"R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_\")\n int BPF_PROG(get_task_exe_file_kfunc_fp)\n {\n \tu64 x;\n@@ -80,7 +80,7 @@ int BPF_PROG(get_task_exe_file_kfunc_unreleased)\n }\n \n SEC(\"lsm.s/file_open\")\n-__failure __msg(\"release kfunc bpf_put_file expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"release function bpf_put_file expects referenced PTR_TO_BTF_ID passed to R1\")\n int BPF_PROG(put_file_kfunc_unacquired, struct file *file)\n {\n \t/* Can't release an unacquired pointer. */\n@@ -128,7 +128,7 @@ int BPF_PROG(path_d_path_kfunc_untrusted_from_current)\n }\n \n SEC(\"lsm.s/file_open\")\n-__failure __msg(\"kernel function bpf_path_d_path R1 expected pointer to STRUCT path but R1 has a pointer to STRUCT file\")\n+__failure __msg(\"bpf_path_d_path R1 expected pointer to STRUCT path but R1 has a pointer to STRUCT file\")\n int BPF_PROG(path_d_path_kfunc_type_mismatch, struct file *file)\n {\n \tbpf_path_d_path((struct path *)\u0026file-\u003ef_task_work, buf, sizeof(buf));\ndiff --git a/tools/testing/selftests/bpf/progs/wakeup_source_fail.c b/tools/testing/selftests/bpf/progs/wakeup_source_fail.c\nindex d4d0f1610853a..ec4e0f3ff7920 100644\n--- a/tools/testing/selftests/bpf/progs/wakeup_source_fail.c\n+++ b/tools/testing/selftests/bpf/progs/wakeup_source_fail.c\n@@ -42,7 +42,7 @@ int wakeup_source_access_lock_fields(void *ctx)\n }\n \n SEC(\"syscall\")\n-__failure __msg(\"release kfunc bpf_wakeup_sources_read_unlock expects referenced PTR_TO_BTF_ID passed to R1\")\n+__failure __msg(\"R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_\")\n int wakeup_source_unlock_no_lock(void *ctx)\n {\n \tstruct bpf_ws_lock *lock = (void *)0x1;\ndiff --git a/tools/testing/selftests/bpf/progs/wq_failures.c b/tools/testing/selftests/bpf/progs/wq_failures.c\nindex 32dc8827e128b..bd30217579d4d 100644\n--- a/tools/testing/selftests/bpf/progs/wq_failures.c\n+++ b/tools/testing/selftests/bpf/progs/wq_failures.c\n@@ -48,7 +48,7 @@ __log_level(2)\n __flag(BPF_F_TEST_STATE_FREQ)\n __failure\n __msg(\": (85) call bpf_wq_init#\") /* anchor message */\n-__msg(\"pointer in R2 isn't map pointer\")\n+__msg(\"R2 type=fp expected=map_ptr\")\n long test_wq_init_nomap(void *ctx)\n {\n \tstruct bpf_wq *wq;\n@@ -98,7 +98,7 @@ __failure\n * is a correct bpf_wq pointer.\n */\n __msg(\": (85) call bpf_wq_set_callback#\") /* anchor message */\n-__msg(\"R1 doesn't point to a map value\")\n+__msg(\"R1 type=fp expected=map_value\")\n long test_wrong_wq_pointer(void *ctx)\n {\n \tint key = 0;\ndiff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c\nindex eb6e3baef412a..0930ef8626972 100644\n--- a/tools/testing/selftests/bpf/verifier/calls.c\n+++ b/tools/testing/selftests/bpf/verifier/calls.c\n@@ -76,7 +76,7 @@\n \t},\n \t.prog_type = BPF_PROG_TYPE_SCHED_CLS,\n \t.result = REJECT,\n-\t.errstr = \"R1 expected pointer to ctx, but got fp\",\n+\t.errstr = \"R1 type=fp expected=ctx\",\n \t.fixup_kfunc_btf_id = {\n \t\t{ \"bpf_kfunc_call_test_pass_ctx\", 2 },\n \t},\n@@ -152,7 +152,7 @@\n \t},\n \t.prog_type = BPF_PROG_TYPE_SCHED_CLS,\n \t.result = REJECT,\n-\t.errstr = \"kernel function bpf_kfunc_call_memb1_release R1 expected pointer\",\n+\t.errstr = \"bpf_kfunc_call_memb1_release R1 expected pointer\",\n \t.fixup_kfunc_btf_id = {\n \t\t{ \"bpf_kfunc_call_memb_acquire\", 1 },\n \t\t{ \"bpf_kfunc_call_memb1_release\", 5 },\ndiff --git a/tools/testing/selftests/bpf/verifier/map_kptr.c b/tools/testing/selftests/bpf/verifier/map_kptr.c\nindex 4b39f8472f9b5..345cecc722a38 100644\n--- a/tools/testing/selftests/bpf/verifier/map_kptr.c\n+++ b/tools/testing/selftests/bpf/verifier/map_kptr.c\n@@ -311,7 +311,7 @@\n \t.prog_type = BPF_PROG_TYPE_SCHED_CLS,\n \t.fixup_map_kptr = { 1 },\n \t.result = REJECT,\n-\t.errstr = \"R1 type=rcu_ptr_or_null_ expected=percpu_ptr_\",\n+\t.errstr = \"Possibly NULL pointer passed to trusted R1\",\n },\n {\n \t\"map_kptr: ref: reject off != 0\",\n@@ -342,7 +342,7 @@\n \t.prog_type = BPF_PROG_TYPE_SCHED_CLS,\n \t.fixup_map_kptr = { 1 },\n \t.result = REJECT,\n-\t.errstr = \"invalid kptr access, R2 type=ptr_prog_test_ref_kfunc expected=ptr_prog_test_member\",\n+\t.errstr = \"R2 must have zero offset when passed to release func\",\n },\n {\n \t\"map_kptr: ref: reference state created and released on xchg\",\n"
} |
| 2/1 | 2026/09/06 17:57 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"check_func_arg",
"check_func_args",
"check_helper_call",
"check_kfunc_call",
"resolve_func_arg_type",
"get_kfunc_arg_type",
"check_func_arg_nullability",
"check_func_arg_release",
"process_arg_ptr_to_btf_id",
"bpf_do_misc_fixups"
],
"Reasoning": "The patch refactors and unifies BPF helper and kfunc argument verification in the BPF verifier (kernel/bpf/verifier.c) and instruction fixups (kernel/bpf/fixups.c). These core verifier changes modify verification rules, nullability checks, argument type resolution, and bytecode rewriting, all of which are directly reachable via the bpf() system call and represent high-value fuzzing targets.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit b3736d7edfb0ded619d427677f8b5828c42e1d69
Author: syz-cluster <triage@syzkaller.com>
Date: Sun Sep 6 17:57:48 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c
index 2f7564f26445c..108edf440c891 100644
--- a/drivers/media/rc/bpf-lirc.c
+++ b/drivers/media/rc/bpf-lirc.c
@@ -52,9 +52,9 @@ static const struct bpf_func_proto rc_keydown_proto = {
.gpl_only = true, /* rc_keydown is EXPORT_SYMBOL_GPL */
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_rc_pointer_rel, u32*, sample, s32, rel_x, s32, rel_y)
@@ -75,8 +75,8 @@ static const struct bpf_func_proto rc_pointer_rel_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 3a7eb2185c354..fe6ab92ceeffe 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -874,7 +874,7 @@ enum bpf_type_flag {
/* function argument constraints */
enum bpf_arg_type {
- ARG_DONTCARE = 0, /* unused argument in helper function */
+ ARG_UNUSED = 0, /* unused argument; terminates argument iteration */
/* the following constraints used to prototype
* bpf_map_lookup/update/delete_elem() functions
@@ -893,7 +893,7 @@ enum bpf_arg_type {
ARG_MEM_SIZE_OR_ZERO, /* number of bytes accessed from memory or 0 */
ARG_PTR_TO_CTX, /* pointer to context */
- ARG_ANYTHING, /* any (initialized) argument is ok */
+ ARG_SCALAR, /* any (initialized) scalar is ok */
ARG_PTR_TO_SPIN_LOCK, /* pointer to bpf_spin_lock */
ARG_PTR_TO_SOCK_COMMON, /* pointer to sock_common */
ARG_PTR_TO_SOCKET, /* pointer to bpf_sock (fullsock) */
@@ -908,6 +908,22 @@ enum bpf_arg_type {
ARG_PTR_TO_TIMER, /* pointer to bpf_timer */
ARG_KPTR_XCHG_DEST, /* pointer to destination that kptrs are bpf_kptr_xchg'd into */
ARG_PTR_TO_DYNPTR, /* pointer to bpf_dynptr. See bpf_type_flag for dynptr type */
+
+ ARG_CONST_SCALAR, /* scalar known at verification time */
+ ARG_CONST_MEM_SIZE, /* ARG_MEM_SIZE that must be constant */
+ ARG_PTR_TO_ALLOC_BTF_ID, /* pointer to an allocated object */
+ ARG_PTR_TO_REFCOUNTED_KPTR, /* pointer to a refcounted local kptr */
+ ARG_PTR_TO_ITER, /* pointer to an iterator */
+ ARG_PTR_TO_LIST_HEAD, /* pointer to bpf_list_head */
+ ARG_PTR_TO_LIST_NODE, /* pointer to bpf_list_node */
+ ARG_PTR_TO_RB_ROOT, /* pointer to bpf_rb_root */
+ ARG_PTR_TO_RB_NODE, /* pointer to bpf_rb_node */
+ ARG_PTR_TO_WORKQUEUE, /* pointer to bpf_wq */
+ ARG_PTR_TO_TASK_WORK, /* pointer to bpf_task_work */
+ ARG_PTR_TO_IRQ_FLAG, /* pointer to saved IRQ flags on the stack */
+ ARG_PTR_TO_RES_SPIN_LOCK, /* pointer to bpf_res_spin_lock */
+ ARG_PTR_TO_PROG_AUX, /* pointer to the caller's bpf_prog_aux */
+ ARG_IGNORE, /* argument the verifier does not check at all */
__BPF_ARG_TYPE_MAX,
/* Extended arg_types. */
@@ -1004,13 +1020,13 @@ struct bpf_func_proto {
};
union {
struct {
- u32 *arg1_btf_id;
- u32 *arg2_btf_id;
- u32 *arg3_btf_id;
- u32 *arg4_btf_id;
- u32 *arg5_btf_id;
+ const u32 *arg1_btf_id;
+ const u32 *arg2_btf_id;
+ const u32 *arg3_btf_id;
+ const u32 *arg4_btf_id;
+ const u32 *arg5_btf_id;
};
- u32 *arg_btf_id[MAX_BPF_FUNC_ARGS];
+ const u32 *arg_btf_id[MAX_BPF_FUNC_ARGS];
struct {
size_t arg1_size;
size_t arg2_size;
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 1a3c44ab06a15..e919e308f2720 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -1585,7 +1585,6 @@ struct bpf_call_arg_meta {
struct btf *arg_btf;
u32 arg_btf_id;
bool arg_owning_ref;
- bool arg_prog;
struct {
struct btf_field *field;
diff --git a/kernel/bpf/backtrack.c b/kernel/bpf/backtrack.c
index 653db80bcc47b..c5c9c5f3b0781 100644
--- a/kernel/bpf/backtrack.c
+++ b/kernel/bpf/backtrack.c
@@ -634,7 +634,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
* The approach of starting with precise=true for all registers and then
* backtrack to mark a register as not precise when the verifier detects
* that program doesn't care about specific value (e.g., when helper
- * takes register as ARG_ANYTHING parameter) is not safe.
+ * takes register as ARG_SCALAR parameter) is not safe.
*
* It's ok to walk single parentage chain of the verifier states.
* It's possible that this backtracking will go all the way till 1st insn.
diff --git a/kernel/bpf/bpf_cgrp_storage.c b/kernel/bpf/bpf_cgrp_storage.c
index c76e9b0fabba8..095d5c93e4ba6 100644
--- a/kernel/bpf/bpf_cgrp_storage.c
+++ b/kernel/bpf/bpf_cgrp_storage.c
@@ -180,7 +180,7 @@ const struct bpf_func_proto bpf_cgrp_storage_get_proto = {
.arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
.arg2_btf_id = &bpf_cgroup_btf_id[0],
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_cgrp_storage_delete_proto = {
diff --git a/kernel/bpf/bpf_inode_storage.c b/kernel/bpf/bpf_inode_storage.c
index f9e81060c1f45..69e1876650dd7 100644
--- a/kernel/bpf/bpf_inode_storage.c
+++ b/kernel/bpf/bpf_inode_storage.c
@@ -220,7 +220,7 @@ const struct bpf_func_proto bpf_inode_storage_get_proto = {
.arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
.arg2_btf_id = &bpf_inode_storage_btf_ids[0],
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_inode_storage_delete_proto = {
diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
index 14a5fdfa04214..1068bf8621f08 100644
--- a/kernel/bpf/bpf_iter.c
+++ b/kernel/bpf/bpf_iter.c
@@ -721,7 +721,7 @@ const struct bpf_func_proto bpf_for_each_map_elem_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_FUNC,
.arg3_type = ARG_PTR_TO_STACK_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_loop, u32, nr_loops, void *, callback_fn, void *, callback_ctx,
@@ -754,10 +754,10 @@ const struct bpf_func_proto bpf_loop_proto = {
.func = bpf_loop,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
.arg2_type = ARG_PTR_TO_FUNC,
.arg3_type = ARG_PTR_TO_STACK_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
struct bpf_iter_num_kern {
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index 82c5988417a0c..9ee39c654dc0a 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -163,7 +163,7 @@ static const struct bpf_func_proto bpf_bprm_opts_set_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &bpf_bprm_opts_set_btf_ids[0],
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_ima_inode_hash, struct inode *, inode, void *, dst, u32, size)
diff --git a/kernel/bpf/bpf_task_storage.c b/kernel/bpf/bpf_task_storage.c
index 4b342be29eac7..e002df9d3a143 100644
--- a/kernel/bpf/bpf_task_storage.c
+++ b/kernel/bpf/bpf_task_storage.c
@@ -243,7 +243,7 @@ const struct bpf_func_proto bpf_task_storage_get_proto = {
.arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
.arg2_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_task_storage_delete_proto = {
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 9c2cab08bb794..0bd26b2ec77db 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8222,7 +8222,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
return -EINVAL;
}
if (btf_type_is_int(t) || btf_is_any_enum(t)) {
- sub->args[i].arg_type = ARG_ANYTHING;
+ sub->args[i].arg_type = ARG_SCALAR;
continue;
}
if (!is_global)
@@ -8747,8 +8747,8 @@ const struct bpf_func_proto bpf_btf_find_by_name_kind_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_MEM_SIZE,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BTF_ID_LIST_GLOBAL(btf_tracing_ids, MAX_BTF_TRACING_TYPE)
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 149672c76c49c..aa7da999cdb8a 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -1840,7 +1840,7 @@ const struct bpf_func_proto bpf_get_local_storage_proto = {
.gpl_only = false,
.ret_type = RET_PTR_TO_MAP_VALUE,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_0(bpf_get_retval)
@@ -1870,7 +1870,7 @@ const struct bpf_func_proto bpf_set_retval_proto = {
.func = bpf_set_retval,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
@@ -2331,7 +2331,7 @@ static const struct bpf_func_proto bpf_sysctl_get_name_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static int copy_sysctl_value(char *dst, size_t dst_len, char *src,
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 5db77d7915dfc..404dc6db06915 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -3208,7 +3208,7 @@ const struct bpf_func_proto bpf_tail_call_proto = {
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
/* Stub for JITs that only support cBPF. eBPF programs are interpreted.
diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
index b682fd2be443e..c740ae070e61b 100644
--- a/kernel/bpf/diagnostics.c
+++ b/kernel/bpf/diagnostics.c
@@ -960,6 +960,35 @@ const char *bpf_diag_reg_type_plain(struct bpf_verifier_env *env, enum bpf_reg_t
}
}
+const char *bpf_diag_arg_type_plain(enum bpf_arg_type type)
+{
+ switch (base_type(type)) {
+ case ARG_MEM_SIZE:
+ case ARG_CONST_MEM_SIZE:
+ return "an integer scalar length for this memory argument";
+ case ARG_PTR_TO_CTX:
+ return "the original program context pointer or preserve it before modifying registers";
+ case ARG_SCALAR:
+ case ARG_CONST_SCALAR:
+ case ARG_CONST_ALLOC_SIZE_OR_ZERO:
+ return "an integer scalar value for this argument, not a pointer or resource object";
+ case ARG_PTR_TO_CONST_STR:
+ return "a constant string pointer that the verifier recognizes, such as a string stored in a read-only map value";
+ case ARG_PTR_TO_DYNPTR:
+ return "the address of a stack dynptr object, or use a const dynptr pointer returned by the verifier-supported path";
+ case ARG_PTR_TO_ALLOC_BTF_ID:
+ return "a pointer returned by the matching BPF object allocation path";
+ case ARG_PTR_TO_REFCOUNTED_KPTR:
+ return "an owning or non-owning pointer to a BPF-managed object containing a bpf_refcount field";
+ case ARG_PTR_TO_ITER:
+ return "the address of a stack iterator object for iterator new, next, and destroy calls";
+ case ARG_PTR_TO_IRQ_FLAG:
+ return "the same stack slot used by bpf_local_irq_save() or bpf_res_spin_lock_irqsave()";
+ default:
+ return "a value with one of the accepted pointer or scalar types for this call";
+ }
+}
+
static const char *diag_arg_ordinal(int argno)
{
switch (argno) {
diff --git a/kernel/bpf/diagnostics.h b/kernel/bpf/diagnostics.h
index d1b79945008a8..a4102fb049ece 100644
--- a/kernel/bpf/diagnostics.h
+++ b/kernel/bpf/diagnostics.h
@@ -51,6 +51,7 @@ const char *bpf_diag_vfmt(struct bpf_verifier_env *env, const char *fmt, va_list
const char *bpf_diag_fmt(struct bpf_verifier_env *env, const char *fmt, ...) __printf(2, 3);
const char *bpf_diag_fmt_btf_type(struct bpf_verifier_env *env, const struct btf *btf, u32 type_id);
const char *bpf_diag_reg_type_plain(struct bpf_verifier_env *env, enum bpf_reg_type type);
+const char *bpf_diag_arg_type_plain(enum bpf_arg_type type);
u64 bpf_diag_event_log_save(struct bpf_verifier_env *env);
void bpf_diag_event_log_restore(struct bpf_verifier_env *env, u64 log_pos);
u32 bpf_diag_irq_depth(const struct bpf_verifier_state *state);
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 73fb3ffc18e33..9512f6497d328 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -2015,7 +2015,8 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
goto next_insn;
}
- if (insn->imm == BPF_FUNC_timer_set_callback) {
+ aux = &env->insn_aux_data[i + delta];
+ if (aux->arg_prog) {
/* The verifier will process callback_fn as many times as necessary
* with different maps and the register states prepared by
* set_timer_callback_state will be accurate.
@@ -2030,7 +2031,7 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
* bpf_timer_set_callback-ed will return -EINVAL.
*/
struct bpf_insn ld_addrs[2] = {
- BPF_LD_IMM64(BPF_REG_3, (long)prog->aux),
+ BPF_LD_IMM64(aux->arg_prog, (long)prog->aux),
};
insn_buf[0] = ld_addrs[0];
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index b3cc5c8fc8756..1b731aad54da6 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -71,7 +71,7 @@ const struct bpf_func_proto bpf_map_update_elem_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_MAP_KEY,
.arg3_type = ARG_PTR_TO_MAP_VALUE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_map_delete_elem, struct bpf_map *, map, void *, key)
@@ -101,7 +101,7 @@ const struct bpf_func_proto bpf_map_push_elem_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_MAP_VALUE,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_map_pop_elem, struct bpf_map *, map, void *, value)
@@ -143,7 +143,7 @@ const struct bpf_func_proto bpf_map_lookup_percpu_elem_proto = {
.ret_type = RET_PTR_TO_MAP_VALUE_OR_NULL,
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_MAP_KEY,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_get_prandom_u32_proto = {
@@ -441,7 +441,7 @@ const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto = {
.func = bpf_get_current_ancestor_cgroup_id,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
#endif /* CONFIG_CGROUPS */
@@ -540,7 +540,7 @@ const struct bpf_func_proto bpf_strtol_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_MEM_SIZE,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg4_size = sizeof(s64),
};
@@ -568,7 +568,7 @@ const struct bpf_func_proto bpf_strtoul_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_MEM_SIZE,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg4_size = sizeof(u64),
};
@@ -624,8 +624,8 @@ const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto = {
.func = bpf_get_ns_current_pid_tgid,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
- .arg2_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -651,7 +651,7 @@ const struct bpf_func_proto bpf_event_output_data_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -676,7 +676,7 @@ const struct bpf_func_proto bpf_copy_from_user_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_copy_from_user_task, void *, dst, u32, size,
@@ -707,10 +707,10 @@ const struct bpf_func_proto bpf_copy_from_user_task_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_BTF_ID,
.arg4_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
- .arg5_type = ARG_ANYTHING
+ .arg5_type = ARG_SCALAR
};
BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
@@ -726,7 +726,7 @@ const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
.gpl_only = false,
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY,
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)
@@ -1415,7 +1415,7 @@ static const struct bpf_func_proto bpf_timer_init_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_TIMER,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static int bpf_async_update_prog_callback(struct bpf_async_cb *cb,
@@ -1510,6 +1510,7 @@ static const struct bpf_func_proto bpf_timer_set_callback_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_TIMER,
.arg2_type = ARG_PTR_TO_FUNC,
+ .arg3_type = ARG_PTR_TO_PROG_AUX,
};
static bool defer_timer_wq_op(void)
@@ -1558,8 +1559,8 @@ static const struct bpf_func_proto bpf_timer_start_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_TIMER,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_timer_cancel, struct bpf_async_kern *, async)
@@ -1889,7 +1890,7 @@ static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT | MEM_WRITE,
};
@@ -1945,8 +1946,8 @@ static const struct bpf_func_proto bpf_dynptr_read_proto = {
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
.arg3_type = ARG_PTR_TO_DYNPTR,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
int __bpf_dynptr_write(const struct bpf_dynptr_kern *dst, u64 offset, void *src,
@@ -2002,10 +2003,10 @@ static const struct bpf_func_proto bpf_dynptr_write_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_DYNPTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE_OR_ZERO,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_dynptr_data, const struct bpf_dynptr_kern *, ptr, u64, offset, u64, len)
@@ -2045,7 +2046,7 @@ static const struct bpf_func_proto bpf_dynptr_data_proto = {
.gpl_only = false,
.ret_type = RET_PTR_TO_DYNPTR_MEM_OR_NULL,
.arg1_type = ARG_PTR_TO_DYNPTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_CONST_ALLOC_SIZE_OR_ZERO,
};
@@ -2957,7 +2958,7 @@ const struct bpf_func_proto bpf_current_task_under_cgroup_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
/**
diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c
index 3f1013d805446..63c0aba56a3f3 100644
--- a/kernel/bpf/ringbuf.c
+++ b/kernel/bpf/ringbuf.c
@@ -553,7 +553,7 @@ const struct bpf_func_proto bpf_ringbuf_reserve_proto = {
.ret_type = RET_PTR_TO_RINGBUF_MEM_OR_NULL,
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_CONST_ALLOC_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static void bpf_ringbuf_commit(void *sample, u64 flags, bool discard)
@@ -594,7 +594,7 @@ const struct bpf_func_proto bpf_ringbuf_submit_proto = {
.func = bpf_ringbuf_submit,
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_RINGBUF_MEM | OBJ_RELEASE,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_ringbuf_discard, void *, sample, u64, flags)
@@ -607,7 +607,7 @@ const struct bpf_func_proto bpf_ringbuf_discard_proto = {
.func = bpf_ringbuf_discard,
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_RINGBUF_MEM | OBJ_RELEASE,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_ringbuf_output, struct bpf_map *, map, void *, data, u64, size,
@@ -635,7 +635,7 @@ const struct bpf_func_proto bpf_ringbuf_output_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_ringbuf_query, struct bpf_map *, map, u64, flags)
@@ -664,7 +664,7 @@ const struct bpf_func_proto bpf_ringbuf_query_proto = {
.func = bpf_ringbuf_query,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_ringbuf_reserve_dynptr, struct bpf_map *, map, u32, size, u64, flags,
@@ -702,8 +702,8 @@ const struct bpf_func_proto bpf_ringbuf_reserve_dynptr_proto = {
.func = bpf_ringbuf_reserve_dynptr,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT | MEM_WRITE,
};
@@ -723,7 +723,7 @@ const struct bpf_func_proto bpf_ringbuf_submit_dynptr_proto = {
.func = bpf_ringbuf_submit_dynptr,
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | OBJ_RELEASE,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_ringbuf_discard_dynptr, struct bpf_dynptr_kern *, ptr, u64, flags)
@@ -742,7 +742,7 @@ const struct bpf_func_proto bpf_ringbuf_discard_dynptr_proto = {
.func = bpf_ringbuf_discard_dynptr,
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | OBJ_RELEASE,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
static int __bpf_user_ringbuf_peek(struct bpf_ringbuf *rb, void **sample, u32 *size)
@@ -876,5 +876,5 @@ const struct bpf_func_proto bpf_user_ringbuf_drain_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_FUNC,
.arg3_type = ARG_PTR_TO_STACK_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index a839041e0d008..272678b825005 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -665,7 +665,7 @@ const struct bpf_func_proto bpf_get_stackid_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static __u64 count_kernel_ip(const struct perf_callchain_entry *trace)
@@ -739,7 +739,7 @@ const struct bpf_func_proto bpf_get_stackid_proto_pe = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static u32 callchain_store(const struct perf_callchain_entry *trace, u32 trace_nr,
@@ -863,7 +863,7 @@ const struct bpf_func_proto bpf_get_stack_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_get_stack_sleepable, struct pt_regs *, regs, void *, buf, u32, size,
@@ -879,7 +879,7 @@ const struct bpf_func_proto bpf_get_stack_sleepable_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static long __bpf_get_task_stack(struct task_struct *task, void *buf, u32 size,
@@ -916,7 +916,7 @@ const struct bpf_func_proto bpf_get_task_stack_proto = {
.arg1_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_get_task_stack_sleepable, struct task_struct *, task, void *, buf,
@@ -933,7 +933,7 @@ const struct bpf_func_proto bpf_get_task_stack_sleepable_proto = {
.arg1_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static int __bpf_get_stack_pe(const struct perf_callchain_entry *trace, u32 trace_nr,
@@ -1015,7 +1015,7 @@ const struct bpf_func_proto bpf_get_stack_proto_pe = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
/* Called from eBPF program */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 6874ba1424af0..6950517f6364b 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -6569,7 +6569,7 @@ static const struct bpf_func_proto bpf_sys_bpf_proto = {
.func = bpf_sys_bpf,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE,
};
@@ -6594,7 +6594,7 @@ static const struct bpf_func_proto bpf_sys_close_proto = {
.func = bpf_sys_close,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flags, u64 *, res)
@@ -6619,7 +6619,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg4_size = sizeof(u64),
};
diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
index 13e1aabe6f886..91b166acb3b5c 100644
--- a/kernel/bpf/task_iter.c
+++ b/kernel/bpf/task_iter.c
@@ -824,10 +824,10 @@ const struct bpf_func_proto bpf_find_vma_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_FUNC,
.arg4_type = ARG_PTR_TO_STACK_OR_NULL,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
static inline void bpf_iter_mmput_async(struct mm_struct *mm)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5b51e7ee1a3f9..54656fb31bbe7 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -951,8 +951,12 @@ static enum bpf_dynptr_type dynptr_reg_type(struct bpf_verifier_env *env, struct
static bool is_dynptr_type_expected(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
enum bpf_arg_type arg_type)
{
- /* ARG_PTR_TO_DYNPTR takes any type of dynptr */
- if (arg_type == ARG_PTR_TO_DYNPTR)
+ /*
+ * ARG_PTR_TO_DYNPTR without a type flag takes any type of dynptr.
+ * Test the flags rather than the whole arg_type, which may carry
+ * unrelated ones such as PTR_MAYBE_NULL.
+ */
+ if (!(arg_type & DYNPTR_TYPE_FLAG_MASK))
return true;
return dynptr_reg_type(env, reg) == arg_to_dynptr_type(arg_type);
@@ -4845,7 +4849,7 @@ static int check_map_access(struct bpf_verifier_env *env, struct bpf_reg_state *
}
static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
- const struct bpf_func_proto *fn,
+ const struct bpf_call_arg_meta *meta,
enum bpf_access_type t)
{
enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
@@ -4869,10 +4873,11 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
case BPF_PROG_TYPE_LWT_XMIT:
case BPF_PROG_TYPE_SK_SKB:
case BPF_PROG_TYPE_SK_MSG:
- if (fn)
- return fn->pkt_access;
+ if (meta && !meta->btf && meta->func_id)
+ return meta->fn->pkt_access;
- env->seen_direct_write = true;
+ if (t == BPF_WRITE)
+ env->seen_direct_write = true;
return true;
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
@@ -5130,18 +5135,6 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = {
[CONST_PTR_TO_MAP] = btf_bpf_map_id,
};
-static enum bpf_reg_type lookup_reg2btf_ids(u32 ref_id)
-{
- enum bpf_reg_type type;
-
- for (type = 0; type < __BPF_REG_TYPE_MAX; type++) {
- if (reg2btf_ids[type] && *reg2btf_ids[type] == ref_id)
- 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. */
@@ -7056,6 +7049,10 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, struct bpf_reg_
switch (base_type(reg->type)) {
case PTR_TO_PACKET:
case PTR_TO_PACKET_META:
+ if (!may_access_direct_pkt_data(env, meta, access_type)) {
+ verbose(env, "function access to the packet is not allowed\n");
+ return -EACCES;
+ }
return check_packet_access(env, reg, argno, 0, access_size,
zero_size_allowed);
case PTR_TO_MAP_KEY:
@@ -7172,7 +7169,7 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,
* the memory that the helper could just partially fill up.
*/
if (!tnum_is_const(size_reg->var_off))
- meta = NULL;
+ meta->arg_raw_mem.regno = 0;
if (reg_smin(size_reg) < 0) {
verbose(env, "%s min value is negative, either use unsigned or 'var &= const'\n",
@@ -7618,11 +7615,11 @@ __printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u
/*
* Validate dynptr arguments for helper, kfunc and subprog.
*
- * @dynptr is both input and output. It is populated when the argument is
- * tagged with MEM_UNINIT (i.e., the dynptr argument that will be constructed)
- * and consumed when the argument is expecting to be an initialized dynptr.
- * @parent_id is used to track the referenced parent object (e.g., file or skb in
- * qdisc program) when constructing a dynptr.
+ * @meta carries the dynptr and referenced-object state. The dynptr is populated
+ * when the argument is tagged with MEM_UNINIT (i.e., the dynptr argument that
+ * will be constructed) and consumed when the argument is expected to be an
+ * initialized dynptr. The reference tracks the parent object (e.g., file or skb
+ * in qdisc program) when constructing a dynptr.
*
* There are two register types representing a bpf_dynptr, one is PTR_TO_STACK
* which points to a stack slot, and the other is CONST_PTR_TO_DYNPTR.
@@ -7639,9 +7636,8 @@ __printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u
* and checked dynamically during runtime.
*/
static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
- argno_t argno, int insn_idx, const char *call_name,
- enum bpf_arg_type arg_type,
- struct ref_obj_desc *ref_obj, struct bpf_dynptr_desc *dynptr)
+ argno_t argno, int insn_idx, enum bpf_arg_type arg_type,
+ struct bpf_call_arg_meta *meta)
{
int spi, err = 0;
@@ -7650,7 +7646,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
"%s expected pointer to stack or const struct bpf_dynptr\n",
reg_arg_name(env, argno));
bpf_diag_call_arg_fmt(
- env, insn_idx, argno, call_name,
+ env, insn_idx, argno, meta->func_name,
"Pass the address of a stack dynptr object, or use a const dynptr pointer returned by the verifier-supported path.",
"a dynptr argument must be a pointer to a dynptr stack slot or a verifier-provided const struct bpf_dynptr, but %s is %s",
reg_arg_name(env, argno), bpf_diag_reg_type_plain(env, reg->type));
@@ -7678,7 +7674,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
verbose(env, "Dynptr has to be an uninitialized dynptr\n");
bpf_diag_res(
env, insn_idx, "dynptr is already initialized",
- "This kfunc constructs a dynptr and requires an uninitialized dynptr stack slot, but the selected slot already holds dynptr state.",
+ "This function constructs a dynptr and requires an uninitialized dynptr stack slot, but the selected slot already holds dynptr state.",
"Use a fresh stack dynptr slot, or release/destroy the existing dynptr before reusing the slot.");
return -EINVAL;
}
@@ -7691,7 +7687,8 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
return err;
}
- err = mark_stack_slots_dynptr(env, reg, arg_type, insn_idx, ref_obj, dynptr);
+ err = mark_stack_slots_dynptr(env, reg, arg_type, insn_idx,
+ &meta->ref_obj, &meta->dynptr);
} else /* OBJ_RELEASE and None case from above */ {
/* For the reg->type == PTR_TO_STACK case, bpf_dynptr is never const */
if (reg->type == CONST_PTR_TO_DYNPTR && (arg_type & OBJ_RELEASE)) {
@@ -7721,7 +7718,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
verbose(env, "Expected a dynptr of type %s as %s\n",
dynptr_type_str(expected_type), reg_arg_name(env, argno));
bpf_diag_call_arg_fmt(
- env, insn_idx, argno, call_name,
+ env, insn_idx, argno, meta->func_name,
"Use a dynptr constructor that matches this operation, or call an operation that accepts the dynptr's current type.",
"the dynptr is initialized with backing object type %s, but this operation expects dynptr type %s",
dynptr_type_str(actual_type), dynptr_type_str(expected_type));
@@ -7740,11 +7737,9 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
reg = &state->stack[spi].spilled_ptr;
}
- if (dynptr) {
- dynptr->type = reg->dynptr.type;
- dynptr->id = reg->id;
- dynptr->parent_id = reg->parent_id;
- }
+ meta->dynptr.type = reg->dynptr.type;
+ meta->dynptr.id = reg->id;
+ meta->dynptr.parent_id = reg->parent_id;
}
return err;
}
@@ -7808,8 +7803,8 @@ static int process_iter_arg(struct bpf_verifier_env *env, struct bpf_reg_state *
reg_arg_name(env, argno));
bpf_diag_call_arg(
env, insn_idx, argno, meta->func_name,
- "the kfunc expects a recognized iterator state pointer, but this argument does not match a valid iterator type",
- "Pass the exact iterator state type expected by this kfunc.");
+ "the function expects a recognized iterator state pointer, but this argument does not match a valid iterator type",
+ "Pass the exact iterator state type expected by this function.");
return -EINVAL;
}
t = btf_type_by_id(meta->btf, btf_id);
@@ -8133,9 +8128,43 @@ static bool arg_type_is_dynptr(enum bpf_arg_type type)
return base_type(type) == ARG_PTR_TO_DYNPTR;
}
+/*
+ * An argument that only ever takes a scalar, so a zero register passed to it
+ * is a value rather than a NULL pointer.
+ */
+static bool arg_type_is_scalar(enum bpf_arg_type type)
+{
+ switch (base_type(type)) {
+ case ARG_SCALAR:
+ case ARG_CONST_SCALAR:
+ case ARG_MEM_SIZE:
+ case ARG_MEM_SIZE_OR_ZERO:
+ case ARG_CONST_MEM_SIZE:
+ case ARG_CONST_ALLOC_SIZE_OR_ZERO:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * A kfunc is named by a BTF ID, which can take the same numeric value as an
+ * enum bpf_func_id. Only test meta->func_id against a BPF_FUNC_* once the call
+ * is known to be to a helper; meta->btf is set only for a kfunc.
+ */
+static bool is_helper_call(const struct bpf_call_arg_meta *meta, enum bpf_func_id func_id)
+{
+ return !meta->btf && meta->func_id == func_id;
+}
+
+static bool is_kfunc_call(const struct bpf_call_arg_meta *meta, u32 btf_id)
+{
+ return meta->btf && meta->func_id == btf_id;
+}
+
static int resolve_map_arg_type(struct bpf_verifier_env *env,
- const struct bpf_call_arg_meta *meta,
- enum bpf_arg_type *arg_type)
+ const struct bpf_call_arg_meta *meta,
+ enum bpf_arg_type *arg_type)
{
if (!meta->map.ptr) {
/* kernel subsystem misconfigured verifier */
@@ -8154,7 +8183,7 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,
}
break;
case BPF_MAP_TYPE_BLOOM_FILTER:
- if (meta->func_id == BPF_FUNC_map_peek_elem)
+ if (is_helper_call(meta, BPF_FUNC_map_peek_elem))
*arg_type = ARG_PTR_TO_MAP_VALUE;
break;
default:
@@ -8163,6 +8192,48 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,
return 0;
}
+static int resolve_func_arg_type(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg, u32 arg,
+ struct bpf_call_arg_meta *meta,
+ enum bpf_arg_type *arg_type, u32 *arg_size);
+static int process_arg_ptr_to_btf_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+ argno_t argno, enum bpf_arg_type arg_type,
+ const struct btf *arg_btf, u32 arg_btf_id,
+ struct bpf_call_arg_meta *meta, int insn_idx);
+static bool is_kfunc_arg_nonown_allowed(const struct btf *btf,
+ const struct btf_param *arg);
+static bool is_kfunc_arg_scalar_with_name(const struct btf *btf,
+ const struct btf_param *arg,
+ const char *name);
+static bool is_bpf_cast_to_kern_ctx_kfunc(const struct bpf_call_arg_meta *meta);
+static bool is_bpf_dynptr_clone_kfunc(const struct bpf_call_arg_meta *meta);
+static bool is_bpf_iter_css_task_new_kfunc(const struct bpf_call_arg_meta *meta);
+static bool is_bpf_obj_drop_kfunc(u32 func_id);
+static bool is_bpf_percpu_obj_drop_kfunc(u32 func_id);
+static bool is_bpf_rbtree_add_kfunc(u32 func_id);
+static int get_bpf_res_spin_lock_kfunc_flags(const struct bpf_call_arg_meta *meta);
+static struct bpf_insn_aux_data *cur_aux(const struct bpf_verifier_env *env);
+static int process_irq_flag(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg, argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static int process_kf_arg_ptr_to_list_head(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg,
+ argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static int process_kf_arg_ptr_to_rbtree_root(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg,
+ argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static int process_kf_arg_ptr_to_list_node(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg,
+ argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static int process_kf_arg_ptr_to_rbtree_node(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg,
+ argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static bool check_css_task_iter_allowlist(struct bpf_verifier_env *env);
+
struct bpf_reg_types {
const enum bpf_reg_type types[10];
u32 *btf_id;
@@ -8206,7 +8277,7 @@ static const struct bpf_reg_types mem_types = {
},
};
-static const struct bpf_reg_types spin_lock_types = {
+static const struct bpf_reg_types map_value_or_alloc_obj_types = {
.types = {
PTR_TO_MAP_VALUE,
PTR_TO_BTF_ID | MEM_ALLOC,
@@ -8235,7 +8306,29 @@ static const struct bpf_reg_types percpu_btf_ptr_types = {
static const struct bpf_reg_types func_ptr_types = { .types = { PTR_TO_FUNC } };
static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK } };
static const struct bpf_reg_types const_str_ptr_types = { .types = { PTR_TO_MAP_VALUE } };
-static const struct bpf_reg_types timer_types = { .types = { PTR_TO_MAP_VALUE } };
+static const struct bpf_reg_types map_value_types = { .types = { PTR_TO_MAP_VALUE } };
+static const struct bpf_reg_types arena_types = {
+ .types = {
+ PTR_TO_ARENA,
+ SCALAR_VALUE,
+ }
+};
+
+static const struct bpf_reg_types alloc_obj_types = {
+ .types = {
+ PTR_TO_BTF_ID | MEM_ALLOC,
+ PTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU,
+ }
+};
+
+static const struct bpf_reg_types alloc_obj_or_non_own_ref_types = {
+ .types = {
+ PTR_TO_BTF_ID | MEM_ALLOC,
+ PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF,
+ PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU,
+ }
+};
+
static const struct bpf_reg_types kptr_xchg_dest_types = {
.types = {
PTR_TO_MAP_VALUE,
@@ -8265,16 +8358,32 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
#endif
[ARG_PTR_TO_SOCKET] = &fullsock_types,
[ARG_PTR_TO_BTF_ID] = &btf_ptr_types,
- [ARG_PTR_TO_SPIN_LOCK] = &spin_lock_types,
+ [ARG_PTR_TO_SPIN_LOCK] = &map_value_or_alloc_obj_types,
[ARG_PTR_TO_MEM] = &mem_types,
[ARG_PTR_TO_RINGBUF_MEM] = &ringbuf_mem_types,
[ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types,
[ARG_PTR_TO_FUNC] = &func_ptr_types,
[ARG_PTR_TO_STACK] = &stack_ptr_types,
[ARG_PTR_TO_CONST_STR] = &const_str_ptr_types,
- [ARG_PTR_TO_TIMER] = &timer_types,
+ [ARG_PTR_TO_TIMER] = &map_value_types,
[ARG_KPTR_XCHG_DEST] = &kptr_xchg_dest_types,
[ARG_PTR_TO_DYNPTR] = &dynptr_types,
+ /* Argument kinds only a kfunc can have. */
+ [ARG_SCALAR] = &scalar_types,
+ [ARG_CONST_SCALAR] = &scalar_types,
+ [ARG_CONST_MEM_SIZE] = &scalar_types,
+ [ARG_PTR_TO_ALLOC_BTF_ID] = &alloc_obj_types,
+ [ARG_PTR_TO_REFCOUNTED_KPTR] = &alloc_obj_or_non_own_ref_types,
+ [ARG_PTR_TO_ITER] = &stack_ptr_types,
+ [ARG_PTR_TO_LIST_HEAD] = &map_value_or_alloc_obj_types,
+ [ARG_PTR_TO_LIST_NODE] = &alloc_obj_or_non_own_ref_types,
+ [ARG_PTR_TO_RB_ROOT] = &map_value_or_alloc_obj_types,
+ [ARG_PTR_TO_RB_NODE] = &alloc_obj_or_non_own_ref_types,
+ [ARG_PTR_TO_RES_SPIN_LOCK] = &map_value_or_alloc_obj_types,
+ [ARG_PTR_TO_WORKQUEUE] = &map_value_types,
+ [ARG_PTR_TO_TASK_WORK] = &map_value_types,
+ [ARG_PTR_TO_IRQ_FLAG] = &stack_ptr_types,
+ [ARG_PTR_TO_ARENA] = &arena_types,
};
static void bpf_diag_call_arg(struct bpf_verifier_env *env, u32 insn_idx, argno_t argno,
@@ -8314,6 +8423,71 @@ __printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u
bpf_diag_call_arg(env, insn_idx, argno, call_name, reason, suggestion);
}
+static int check_func_arg_nullability(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg, argno_t argno,
+ enum bpf_arg_type arg_type,
+ struct bpf_call_arg_meta *meta, int insn_idx)
+{
+ const char *expected_type = "pointer";
+
+ if (arg_type_is_scalar(arg_type) || type_may_be_null(arg_type) ||
+ (!bpf_register_is_null(reg) && !type_may_be_null(reg->type)))
+ return 0;
+
+ if (meta->btf) {
+ u32 arg_btf_id;
+
+ arg_btf_id = btf_params(meta->func_proto)[arg_idx_from_argno(argno)].type;
+ expected_type = bpf_diag_fmt(env, "value of type %s",
+ bpf_diag_fmt_btf_type(env, meta->btf, arg_btf_id));
+ }
+
+ verbose(env, "Possibly NULL pointer passed to trusted %s\n",
+ reg_arg_name(env, argno));
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Add a NULL check and make the call only on the non-NULL path.",
+ "the pointer may be NULL, but this call requires a non-NULL %s",
+ expected_type);
+ return -EACCES;
+}
+
+static int check_func_arg_release(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+ argno_t argno, enum bpf_arg_type arg_type,
+ struct bpf_call_arg_meta *meta, int insn_idx)
+{
+ const char *expected_type = "pointer";
+
+ if (!arg_type_is_release(arg_type))
+ return 0;
+
+ if (arg_type_is_dynptr(arg_type) || reg_is_referenced(env, reg) ||
+ bpf_register_is_null(reg))
+ return 0;
+
+ verbose(env, "release function %s expects referenced PTR_TO_BTF_ID passed to %s\n",
+ meta->func_name, reg_arg_name(env, argno));
+
+ if (meta->btf) {
+ const struct btf_param *btf_arg;
+ const struct btf_type *t;
+ u32 ref_id;
+
+ btf_arg = &btf_params(meta->func_proto)[arg_idx_from_argno(argno)];
+ ref_id = btf_arg->type;
+ t = btf_type_skip_modifiers(meta->btf, btf_arg->type, NULL);
+ if (btf_type_is_ptr(t))
+ btf_type_skip_modifiers(meta->btf, t->type, &ref_id);
+ expected_type = bpf_diag_fmt(env, "value of type %s",
+ bpf_diag_fmt_btf_type(env, meta->btf, ref_id));
+ }
+
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ bpf_diag_fmt(env, "Pass the resource-owning %s returned by the matching acquire call, or avoid the release function after ownership has already been transferred or released.",
+ expected_type),
+ "release functions require a value that owns a live resource returned by a matching acquire function");
+ return -EINVAL;
+}
+
static const char *bpf_diag_expected_reg_types(struct bpf_verifier_env *env,
const enum bpf_reg_type *types, int count)
{
@@ -8335,19 +8509,21 @@ static const char *bpf_diag_expected_reg_types(struct bpf_verifier_env *env,
}
static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *reg, argno_t argno,
- enum bpf_arg_type arg_type, const u32 *arg_btf_id,
- struct bpf_call_arg_meta *meta, const char *call_name)
+ enum bpf_arg_type arg_type, struct bpf_call_arg_meta *meta)
{
enum bpf_reg_type expected, type = reg->type;
const struct bpf_reg_types *compatible;
const char *actual, *accepted;
- int i, j, err;
+ int i, j;
compatible = compatible_reg_types[base_type(arg_type)];
if (!compatible) {
verifier_bug(env, "unsupported arg type %d", arg_type);
return -EFAULT;
}
+ if (meta->btf && base_type(arg_type) == ARG_PTR_TO_BTF_ID &&
+ (base_type(type) == PTR_TO_BTF_ID || reg2btf_ids[base_type(type)]))
+ goto found;
/* ARG_PTR_TO_MEM + RDONLY is compatible with PTR_TO_MEM and PTR_TO_MEM + RDONLY,
* but ARG_PTR_TO_MEM is compatible only with PTR_TO_MEM and NOT with PTR_TO_MEM + RDONLY
@@ -8369,7 +8545,8 @@ static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *re
type &= ~DYNPTR_TYPE_FLAG_MASK;
/* Local kptr types are allowed as the source argument of bpf_kptr_xchg */
- if (meta->func_id == BPF_FUNC_kptr_xchg && type_is_alloc(type) && reg_from_argno(argno) == BPF_REG_2) {
+ if (is_helper_call(meta, BPF_FUNC_kptr_xchg) && type_is_alloc(type) &&
+ reg_from_argno(argno) == BPF_REG_2) {
type &= ~MEM_ALLOC;
type &= ~MEM_PERCPU;
}
@@ -8389,115 +8566,13 @@ static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *re
verbose(env, "%s\n", reg_type_str(env, compatible->types[j]));
actual = bpf_diag_fmt(env, "%s", reg_type_str(env, reg->type));
accepted = bpf_diag_expected_reg_types(env, compatible->types, i);
- bpf_diag_call_arg_fmt(env, env->insn_idx, argno, call_name,
- "Pass a value with one of the accepted pointer or scalar types for this call.",
+ bpf_diag_call_arg_fmt(env, env->insn_idx, argno, meta->func_name,
+ bpf_diag_fmt(env, "Pass %s.", bpf_diag_arg_type_plain(arg_type)),
"it has type %s, but this argument accepts %s",
actual, accepted);
return -EACCES;
found:
- if (base_type(reg->type) != PTR_TO_BTF_ID)
- return 0;
-
- if (compatible == &mem_types) {
- if (!(arg_type & MEM_RDONLY)) {
- verbose(env,
- "%s() may write into memory pointed by %s type=%s\n",
- func_id_name(meta->func_id),
- reg_arg_name(env, argno), reg_type_str(env, reg->type));
- return -EACCES;
- }
- return 0;
- }
-
- switch ((int)reg->type) {
- case PTR_TO_BTF_ID:
- case PTR_TO_BTF_ID | PTR_TRUSTED:
- case PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL:
- case PTR_TO_BTF_ID | MEM_RCU:
- case PTR_TO_BTF_ID | PTR_MAYBE_NULL:
- case PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU:
- {
- /* For bpf_sk_release, it needs to match against first member
- * 'struct sock_common', hence make an exception for it. This
- * allows bpf_sk_release to work for multiple socket types.
- */
- bool strict_type_match = arg_type_is_release(arg_type) &&
- meta->func_id != BPF_FUNC_sk_release;
-
- if (type_may_be_null(reg->type) &&
- (!type_may_be_null(arg_type) || arg_type_is_release(arg_type))) {
- verbose(env, "Possibly NULL pointer passed to helper %s\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg(
- env, env->insn_idx, argno, call_name,
- "the pointer may be NULL, but this call requires a non-NULL pointer",
- "Add a NULL check and make the call only on the non-NULL path.");
- return -EACCES;
- }
-
- if (!arg_btf_id) {
- if (!compatible->btf_id) {
- verifier_bug(env, "missing arg compatible BTF ID");
- return -EFAULT;
- }
- arg_btf_id = compatible->btf_id;
- }
-
- if (meta->func_id == BPF_FUNC_kptr_xchg) {
- if (map_kptr_match_type(env, meta->kptr_field, reg, reg_from_argno(argno)))
- return -EACCES;
- } else {
- if (arg_btf_id == BPF_PTR_POISON) {
- verbose(env, "verifier internal error:");
- verbose(env, "%s has non-overwritten BPF_PTR_POISON type\n",
- reg_arg_name(env, argno));
- return -EACCES;
- }
-
- err = __check_ptr_off_reg(env, reg, argno, true);
- if (err)
- return err;
-
- if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id,
- reg->var_off.value, btf_vmlinux, *arg_btf_id,
- strict_type_match, !type_is_alloc(reg->type))) {
- verbose(env, "%s is of type %s but %s is expected\n",
- reg_arg_name(env, argno),
- btf_type_name(reg->btf, reg->btf_id),
- btf_type_name(btf_vmlinux, *arg_btf_id));
- return -EACCES;
- }
- }
- break;
- }
- case PTR_TO_BTF_ID | MEM_ALLOC:
- case PTR_TO_BTF_ID | MEM_PERCPU | MEM_ALLOC:
- case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF:
- case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU:
- if (meta->func_id != BPF_FUNC_spin_lock && meta->func_id != BPF_FUNC_spin_unlock &&
- meta->func_id != BPF_FUNC_kptr_xchg) {
- verifier_bug(env, "unimplemented handling of MEM_ALLOC");
- return -EFAULT;
- }
- /* Check if local kptr in src arg matches kptr in dst arg */
- if (meta->func_id == BPF_FUNC_kptr_xchg) {
- int regno = reg_from_argno(argno);
-
- if (regno == BPF_REG_2 &&
- map_kptr_match_type(env, meta->kptr_field, reg, regno))
- return -EACCES;
- }
- break;
- case PTR_TO_BTF_ID | MEM_PERCPU:
- case PTR_TO_BTF_ID | MEM_PERCPU | MEM_RCU:
- case PTR_TO_BTF_ID | MEM_PERCPU | PTR_TRUSTED:
- /* Handled by helper specific checks */
- break;
- default:
- verifier_bug(env, "invalid PTR_TO_BTF_ID register for type match");
- return -EFAULT;
- }
return 0;
}
@@ -8518,10 +8593,9 @@ reg_find_field_offset(const struct bpf_reg_state *reg, s32 off, u32 fields)
return field;
}
-static int __check_func_arg_reg_off(struct bpf_verifier_env *env,
- const struct bpf_reg_state *reg, argno_t argno,
- enum bpf_arg_type arg_type,
- bool btf_id_fixed_off_ok)
+static int check_func_arg_reg_off(struct bpf_verifier_env *env,
+ const struct bpf_reg_state *reg, argno_t argno,
+ enum bpf_arg_type arg_type)
{
u32 type = reg->type;
@@ -8577,12 +8651,15 @@ static int __check_func_arg_reg_off(struct bpf_verifier_env *env,
case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF:
case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU:
/* When referenced PTR_TO_BTF_ID is passed to release function,
- * its fixed offset must be 0. In the other cases, fixed offset
- * can be non-zero unless the caller requires otherwise.
- * var_off always must be 0 for PTR_TO_BTF_ID, hence we still
- * need to do checks instead of returning.
+ * its fixed offset must be 0. bpf_refcount_acquire() returns the
+ * pointer it was given while incrementing the refcount at the
+ * refcount field offset, so it needs a zero offset too. In the
+ * other cases, fixed offset can be non-zero. var_off always must
+ * be 0 for PTR_TO_BTF_ID, hence we still need to do checks
+ * instead of returning.
*/
- return __check_ptr_off_reg(env, reg, argno, btf_id_fixed_off_ok);
+ return __check_ptr_off_reg(env, reg, argno,
+ base_type(arg_type) != ARG_PTR_TO_REFCOUNTED_KPTR);
case PTR_TO_CTX:
/*
* Allow fixed and variable offsets for syscall context, but
@@ -8598,13 +8675,6 @@ static int __check_func_arg_reg_off(struct bpf_verifier_env *env,
}
}
-static int check_func_arg_reg_off(struct bpf_verifier_env *env,
- const struct bpf_reg_state *reg, argno_t argno,
- enum bpf_arg_type arg_type)
-{
- return __check_func_arg_reg_off(env, reg, argno, arg_type, true);
-}
-
static int check_arg_const_str(struct bpf_verifier_env *env,
struct bpf_reg_state *reg, argno_t argno)
{
@@ -8770,57 +8840,53 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
struct bpf_call_arg_meta *meta,
int insn_idx)
{
+ const struct btf_param *btf_arg = meta->btf ? &btf_params(meta->func_proto)[arg] : NULL;
const struct bpf_func_proto *fn = meta->fn;
- u32 regno = BPF_REG_1 + arg;
- struct bpf_reg_state *reg = reg_state(env, regno);
+ struct bpf_func_state *caller = cur_func(env);
+ struct bpf_reg_state *regs = cur_regs(env);
+ argno_t argno = argno_from_arg(arg + 1);
+ struct bpf_reg_state *reg = get_func_arg_reg(caller, regs, arg);
enum bpf_arg_type arg_type = fn->arg_type[arg];
- argno_t argno = argno_from_reg(regno);
- enum bpf_reg_type type = reg->type;
- u32 *arg_btf_id = NULL;
+ int regno = reg_from_argno(argno);
+ u32 arg_size = arg_type & MEM_FIXED_SIZE ? fn->arg_size[arg] : 0;
u32 key_size;
int err = 0;
- if (arg_type == ARG_DONTCARE)
+ if (arg_type == ARG_PTR_TO_PROG_AUX) {
+ cur_aux(env)->arg_prog = regno;
+ return 0;
+ }
+ if (arg_type == ARG_IGNORE)
return 0;
- err = check_reg_arg(env, regno, SRC_OP);
- if (err)
- return err;
+ if (regno >= 0) {
+ err = check_reg_arg(env, regno, SRC_OP);
+ if (err)
+ return err;
+ }
- if (arg_type == ARG_ANYTHING) {
- if (is_pointer_value(env, regno)) {
- verbose(env, "R%d leaks addr into helper function\n",
- regno);
+ /* Preserve the legacy helper behavior for privileged pointer leaks. */
+ if (!meta->btf && arg_type == ARG_SCALAR) {
+ if (__is_pointer_value(env->allow_ptr_leaks, reg)) {
+ verbose(env, "%s leaks addr into helper function\n",
+ reg_arg_name(env, argno));
return -EACCES;
}
return 0;
}
- if (type_is_pkt_pointer(type) &&
- !may_access_direct_pkt_data(env, fn, BPF_READ)) {
- verbose(env, "helper access to the packet is not allowed\n");
- return -EACCES;
- }
-
- if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE) {
- err = resolve_map_arg_type(env, meta, &arg_type);
- if (err)
- return err;
- }
+ err = resolve_func_arg_type(env, reg, arg, meta, &arg_type, &arg_size);
+ if (err)
+ return err;
if (bpf_register_is_null(reg) && type_may_be_null(arg_type))
- /* A NULL register has a SCALAR_VALUE type, so skip
- * type checking.
- */
- goto skip_type_check;
+ return 0;
- /* arg_btf_id and arg_size are in a union. */
- if (base_type(arg_type) == ARG_PTR_TO_BTF_ID ||
- base_type(arg_type) == ARG_PTR_TO_SPIN_LOCK)
- arg_btf_id = fn->arg_btf_id[arg];
+ err = check_func_arg_nullability(env, reg, argno, arg_type, meta, insn_idx);
+ if (err)
+ return err;
- err = check_reg_type(env, reg, argno, arg_type, arg_btf_id, meta,
- func_id_name(meta->func_id));
+ err = check_reg_type(env, reg, argno, arg_type, meta);
if (err)
return err;
@@ -8828,22 +8894,27 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
if (err)
return err;
-skip_type_check:
- if (arg_type_is_release(arg_type) && !arg_type_is_dynptr(arg_type) &&
- !reg_is_referenced(env, reg) && !bpf_register_is_null(reg)) {
- verbose(env, "release helper %s expects referenced PTR_TO_BTF_ID passed to %s\n",
- func_id_name(meta->func_id), reg_arg_name(env, argno));
- bpf_diag_call_arg(
- env, insn_idx, argno, func_id_name(meta->func_id),
- "release helpers require a value that owns a live resource returned by a matching acquire helper",
- "Pass the resource-owning pointer returned by the matching acquire helper, and avoid calling the release helper after ownership has already been transferred or released.");
- return -EINVAL;
- }
+ err = check_func_arg_release(env, reg, argno, arg_type, meta, insn_idx);
+ if (err)
+ return err;
if (reg_is_referenced(env, reg))
update_ref_obj(&meta->ref_obj, reg);
switch (base_type(arg_type)) {
+ case ARG_CONST_SCALAR:
+ err = process_const_arg(env, reg, argno, meta);
+ if (err < 0) {
+ if (err == -EINVAL)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass a compile-time constant or a value the verifier can prove is constant at this call.",
+ "the function requires this scalar argument to be a verifier-known constant, but %s is variable on this path",
+ reg_arg_name(env, argno));
+ return err;
+ }
+ break;
+ case ARG_SCALAR:
+ break;
case ARG_CONST_MAP_PTR:
/* bpf_map_xxx(map_ptr) call: remember that map_ptr */
err = process_map_ptr_arg(env, reg, argno, meta);
@@ -8865,7 +8936,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
return -EFAULT;
}
key_size = meta->map.ptr->key_size;
- err = check_helper_mem_access(env, reg, argno, key_size, BPF_READ, false, NULL,
+ err = check_helper_mem_access(env, reg, argno, key_size, BPF_READ, false, meta,
NULL);
if (err)
return err;
@@ -8897,7 +8968,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
* Disable raw mode for bpf_map_peek_elem() on a bloom filter. The helper reads
* the value buffer as an input rather than filling it.
*/
- if (meta->func_id == BPF_FUNC_map_peek_elem &&
+ if (is_helper_call(meta, BPF_FUNC_map_peek_elem) &&
meta->map.ptr->map_type == BPF_MAP_TYPE_BLOOM_FILTER)
meta->arg_raw_mem.regno = 0;
@@ -8905,9 +8976,80 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ,
false, meta, NULL);
break;
+ case ARG_PTR_TO_BTF_ID:
+ case ARG_PTR_TO_BTF_ID_SOCK_COMMON:
+ {
+ const u32 *arg_btf_id = fn->arg_btf_id[arg];
+ const struct btf *arg_btf = meta->btf ?: btf_vmlinux;
+
+ if (!meta->btf) {
+ const struct bpf_reg_types *compatible;
+
+ if (base_type(reg->type) != PTR_TO_BTF_ID)
+ break;
+
+ if (is_helper_call(meta, BPF_FUNC_kptr_xchg))
+ return map_kptr_match_type(env, meta->kptr_field, reg, regno) ?
+ -EACCES : 0;
+
+ if (!arg_btf_id) {
+ compatible = compatible_reg_types[base_type(arg_type)];
+ if (!compatible->btf_id) {
+ verifier_bug(env, "missing arg compatible BTF ID");
+ return -EFAULT;
+ }
+ arg_btf_id = compatible->btf_id;
+ }
+ if (arg_btf_id == BPF_PTR_POISON) {
+ verbose(env, "verifier internal error:");
+ verbose(env, "%s has non-overwritten BPF_PTR_POISON type\n",
+ reg_arg_name(env, argno));
+ return -EACCES;
+ }
+ }
+
+ if (meta->btf && (!is_trusted_reg(env, reg) ||
+ bpf_type_has_unsafe_modifiers(reg->type))) {
+ if (!(arg_type & MEM_RCU)) {
+ const char *actual_type, *arg_name, *expected_type;
+
+ expected_type = bpf_diag_fmt_btf_type(env, arg_btf, *arg_btf_id);
+ verbose(env, "%s must be referenced or trusted\n",
+ reg_arg_name(env, argno));
+ arg_name = reg_arg_name(env, argno);
+ actual_type = bpf_diag_reg_type_plain(env, reg->type);
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass a pointer acquired from a verifier-tracked source, or call this function only inside the required protection if it accepts RCU pointers.",
+ "the function requires a trusted or resource-owning pointer to %s, but %s is %s",
+ expected_type, arg_name, actual_type);
+ return -EINVAL;
+ }
+ if (!is_rcu_reg(reg)) {
+ const char *actual_type, *arg_name, *expected_type;
+
+ expected_type = bpf_diag_fmt_btf_type(env, arg_btf, *arg_btf_id);
+ verbose(env, "%s must be a rcu pointer\n",
+ reg_arg_name(env, argno));
+ arg_name = reg_arg_name(env, argno);
+ actual_type = bpf_diag_reg_type_plain(env, reg->type);
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Use this function with a pointer that is valid in an RCU read lock region.",
+ "the function requires an RCU-protected pointer to %s, but %s is %s",
+ expected_type, arg_name, actual_type);
+ return -EINVAL;
+ }
+ }
+
+ err = process_arg_ptr_to_btf_id(env, reg, argno, arg_type, arg_btf,
+ *arg_btf_id, meta, insn_idx);
+ if (err < 0)
+ return err;
+ break;
+ }
case ARG_PTR_TO_PERCPU_BTF_ID:
if (!reg->btf_id) {
- verbose(env, "Helper has invalid btf_id in R%d\n", regno);
+ verbose(env, "Helper has invalid btf_id in %s\n",
+ reg_arg_name(env, argno));
return -EACCES;
}
meta->ret_btf = reg->btf;
@@ -8918,11 +9060,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
verbose(env, "can't spin_{lock,unlock} in rbtree cb\n");
return -EACCES;
}
- if (meta->func_id == BPF_FUNC_spin_lock) {
+ if (is_helper_call(meta, BPF_FUNC_spin_lock)) {
err = process_spin_lock(env, reg, argno, PROCESS_SPIN_LOCK);
if (err)
return err;
- } else if (meta->func_id == BPF_FUNC_spin_unlock) {
+ } else if (is_helper_call(meta, BPF_FUNC_spin_unlock)) {
err = process_spin_lock(env, reg, argno, 0);
if (err)
return err;
@@ -8936,45 +9078,273 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
if (err)
return err;
break;
+ case ARG_PTR_TO_CTX:
+ if (is_bpf_cast_to_kern_ctx_kfunc(meta)) {
+ err = get_kern_ctx_btf_id(&env->log, resolve_prog_type(env->prog));
+ if (err < 0)
+ return -EINVAL;
+ meta->ret_btf_id = err;
+ }
+ break;
+ case ARG_PTR_TO_ARENA:
+ break;
+ case ARG_PTR_TO_ALLOC_BTF_ID:
+ if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC)) {
+ if (!is_bpf_obj_drop_kfunc(meta->func_id)) {
+ verbose(env, "%s expected for bpf_obj_drop()\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ } else if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU)) {
+ if (!is_bpf_percpu_obj_drop_kfunc(meta->func_id)) {
+ verbose(env, "%s expected for bpf_percpu_obj_drop()\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ }
+ if (!reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass the owned object pointer before it is released or transferred.",
+ "the allocated object pointer in %s must still carry verifier-tracked ownership, but this pointer no longer owns a live resource",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ if (meta->btf == btf_vmlinux) {
+ meta->arg_btf = reg->btf;
+ meta->arg_btf_id = reg->btf_id;
+ }
+ break;
case ARG_PTR_TO_FUNC:
meta->subprogno = reg->subprogno;
break;
case ARG_PTR_TO_MEM:
+ {
+ enum bpf_access_type access_type;
+ bool known_memory;
+
/* 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_mem_reg(env, reg, argno_from_reg(regno), fn->arg_size[arg],
- arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ, meta, NULL);
- if (err)
- return err;
- if (arg_type & MEM_ALIGNED)
- err = check_ptr_alignment(env, reg, 0, fn->arg_size[arg], true);
+ if (!(arg_type & MEM_FIXED_SIZE))
+ break;
+
+ access_type = arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ;
+ if (meta->btf)
+ access_type = BPF_READ | BPF_WRITE;
+
+ err = check_mem_reg(env, reg, argno, arg_size, access_type, meta, &known_memory);
+ if (err < 0) {
+ if (known_memory)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass memory with at least the required number of accessible bytes and suitable read or write access.",
+ "the function expects %u bytes of memory, but the verifier cannot prove that %s provides a range of that size with the required read or write access",
+ arg_size,
+ bpf_diag_reg_type_plain(env, reg->type));
+ else
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass stack, map, context, or other verifier-known memory of the expected type and size, not an integer cast to a pointer.",
+ "the function expects %u bytes of memory, but it is %s and not verifier-known memory",
+ arg_size,
+ bpf_diag_reg_type_plain(env, reg->type));
+ return err;
}
+ if (arg_type & MEM_ALIGNED)
+ err = check_ptr_alignment(env, reg, 0, arg_size, true);
break;
+ }
+ case ARG_CONST_MEM_SIZE:
+ err = process_const_arg(env, reg, argno, meta);
+ if (err < 0) {
+ if (err == -EINVAL)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass a compile-time constant or a value the verifier can prove is constant at this call.",
+ "the function requires this memory size to be a verifier-known constant, but %s is variable on this path",
+ reg_arg_name(env, argno));
+ return err;
+ }
+ fallthrough;
case ARG_MEM_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, NULL);
- break;
case ARG_MEM_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, NULL);
- break;
- case ARG_PTR_TO_DYNPTR:
- err = process_dynptr_func(env, reg, argno, insn_idx, func_id_name(meta->func_id),
- arg_type, &meta->ref_obj, &meta->dynptr);
+ {
+ struct bpf_reg_state *buff_reg = get_func_arg_reg(caller, regs, arg - 1);
+ argno_t buff_argno = argno_from_arg(arg);
+ enum bpf_mem_size_failure failure;
+ u32 access_type;
+ bool zero_size_allowed;
+
+ if (meta->btf && bpf_register_is_null(buff_reg))
+ break;
+
+ access_type = fn->arg_type[arg - 1] & MEM_WRITE ? BPF_WRITE : BPF_READ;
+ if (meta->btf)
+ access_type = BPF_READ | BPF_WRITE;
+ zero_size_allowed = meta->btf || base_type(arg_type) == ARG_MEM_SIZE_OR_ZERO;
+
+ err = check_mem_size_reg(env, buff_reg, reg, buff_argno, argno,
+ access_type, zero_size_allowed, meta, &failure);
+ if (err < 0) {
+ const char *buff_arg, *size_arg;
+
+ buff_arg = bpf_diag_arg_name(env, buff_argno);
+ size_arg = bpf_diag_arg_name(env, argno);
+ verbose(env, "%s and ", reg_arg_name(env, buff_argno));
+ verbose(env, "%s memory, len pair leads to invalid memory access\n",
+ reg_arg_name(env, argno));
+ if (failure == BPF_MEM_SIZE_FAIL_MEMORY) {
+ bpf_diag_call_arg_fmt(env, insn_idx, buff_argno, meta->func_name,
+ "Pass a stack, map, context, or other verifier-known memory pointer, and keep the paired length within that object.",
+ "it is the memory pointer in a memory/length pair with %s, but %s does not provide a verifier-accessible range of the requested length",
+ size_arg, buff_arg);
+ } else if (failure == BPF_MEM_SIZE_FAIL_SIZE) {
+ if (reg_smin(reg) < 0)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.",
+ "the memory size in %s may be negative because its signed minimum is %lld",
+ size_arg, reg_smin(reg));
+ else if (!zero_size_allowed && reg_umin(reg) == 0)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Ensure the memory size is non-zero before this call.",
+ "the memory size in %s may be zero, but the function requires a non-zero size",
+ size_arg);
+ else
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.",
+ "the memory size in %s may reach %llu bytes, but variable memory accesses must stay below %u bytes",
+ size_arg, reg_umax(reg), BPF_MAX_VAR_SIZ);
+ }
+ }
+ break;
+ }
+ case ARG_PTR_TO_DYNPTR: {
+ if (is_bpf_dynptr_clone_kfunc(meta) &&
+ (arg_type & MEM_UNINIT)) {
+ enum bpf_dynptr_type parent_type = meta->dynptr.type;
+
+ if (parent_type == BPF_DYNPTR_TYPE_INVALID) {
+ verifier_bug(env, "no dynptr type for parent of clone");
+ return -EFAULT;
+ }
+
+ arg_type |= (unsigned int)get_dynptr_type_flag(parent_type);
+ }
+
+ err = process_dynptr_func(env, reg, argno, insn_idx, arg_type, meta);
if (err)
return err;
break;
+ }
+ case ARG_PTR_TO_ITER:
+ if (is_bpf_iter_css_task_new_kfunc(meta) &&
+ !check_css_task_iter_allowlist(env)) {
+ verbose(env, "css_task_iter is only allowed in bpf_lsm, bpf_iter and sleepable progs\n");
+ return -EINVAL;
+ }
+ err = process_iter_arg(env, reg, argno, insn_idx, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_LIST_HEAD:
+ if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) &&
+ !reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ return -EINVAL;
+ }
+ err = process_kf_arg_ptr_to_list_head(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_RB_ROOT:
+ if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) &&
+ !reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ return -EINVAL;
+ }
+ err = process_kf_arg_ptr_to_rbtree_root(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_LIST_NODE:
+ if (!(is_kfunc_arg_nonown_allowed(meta->btf, btf_arg) &&
+ type_is_non_owning_ref(reg->type) && !reg_is_referenced(env, reg))) {
+ if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
+ verbose(env, "%s expected pointer to allocated object\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ if (!reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ return -EINVAL;
+ }
+ }
+ err = process_kf_arg_ptr_to_list_node(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_RB_NODE:
+ if (is_bpf_rbtree_add_kfunc(meta->func_id)) {
+ if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
+ verbose(env, "%s expected pointer to allocated object\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ if (!reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ return -EINVAL;
+ }
+ } else {
+ if (!type_is_non_owning_ref(reg->type) &&
+ !reg_is_referenced(env, reg)) {
+ verbose(env, "%s can only take non-owning or refcounted bpf_rb_node pointer\n",
+ meta->func_name);
+ return -EINVAL;
+ }
+ if (in_rbtree_lock_required_cb(env)) {
+ verbose(env, "%s not allowed in rbtree cb\n", meta->func_name);
+ return -EINVAL;
+ }
+ }
+ err = process_kf_arg_ptr_to_rbtree_node(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
case ARG_CONST_ALLOC_SIZE_OR_ZERO:
+ if (meta->btf && is_kfunc_arg_scalar_with_name(meta->btf, btf_arg,
+ "rdonly_buf_size"))
+ meta->r0_rdonly = true;
err = process_const_alloc_mem_size(env, reg, argno, &meta->ret_mem);
- if (err)
+ if (err < 0) {
+ if (meta->btf && err == -EINVAL)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass a verifier-known constant size for this function's buffer argument.",
+ "the function uses this argument as a return-buffer size, but %s is invalid or variable on this path",
+ reg_arg_name(env, argno));
return err;
+ }
+ break;
+ case ARG_PTR_TO_REFCOUNTED_KPTR:
+ {
+ struct btf_record *rec;
+
+ if (!type_is_non_owning_ref(reg->type))
+ meta->arg_owning_ref = true;
+
+ rec = reg_btf_record(reg);
+ if (!rec) {
+ verifier_bug(env, "Couldn't find btf_record");
+ return -EFAULT;
+ }
+
+ if (rec->refcount_off < 0) {
+ verbose(env, "%s doesn't point to a type with bpf_refcount field\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+
+ meta->arg_btf = reg->btf;
+ meta->arg_btf_id = reg->btf_id;
break;
+ }
case ARG_PTR_TO_CONST_STR:
{
err = check_arg_const_str(env, reg, argno);
@@ -8982,6 +9352,33 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
return err;
break;
}
+ case ARG_PTR_TO_WORKQUEUE:
+ err = check_map_field_pointer(env, reg, argno, BPF_WORKQUEUE, &meta->map);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_TASK_WORK:
+ err = check_map_field_pointer(env, reg, argno, BPF_TASK_WORK, &meta->map);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_IRQ_FLAG:
+ err = process_irq_flag(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_RES_SPIN_LOCK:
+ {
+ int flags;
+
+ flags = get_bpf_res_spin_lock_kfunc_flags(meta);
+ if (!flags)
+ return -EFAULT;
+ err = process_spin_lock(env, reg, argno, flags);
+ if (err < 0)
+ return err;
+ break;
+ }
case ARG_KPTR_XCHG_DEST:
err = process_kptr_func(env, regno, meta);
if (err)
@@ -8992,6 +9389,37 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
return err;
}
+static int check_func_args(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
+ int insn_idx)
+{
+ struct bpf_func_state *caller = cur_func(env);
+ const struct btf_param *args = NULL;
+ u32 arg, nargs = MAX_BPF_FUNC_REG_ARGS;
+ int err;
+
+ if (meta->btf) {
+ args = btf_params(meta->func_proto);
+ nargs = btf_type_vlen(meta->func_proto);
+ }
+
+ if (nargs > MAX_BPF_FUNC_REG_ARGS) {
+ err = check_outgoing_stack_args(env, caller, nargs, meta->func_name,
+ meta->btf, args);
+ if (err)
+ return err;
+ }
+
+ for (arg = 0; arg < nargs; arg++) {
+ if (meta->fn->arg_type[arg] == ARG_UNUSED)
+ break;
+ err = check_func_arg(env, arg, meta, insn_idx);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static bool may_update_sockmap(struct bpf_verifier_env *env, int func_id)
{
enum bpf_attach_type eatype = env->prog->expected_attach_type;
@@ -9289,7 +9717,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++) {
- if (fn->arg_type[i] == ARG_DONTCARE)
+ if (fn->arg_type[i] == ARG_UNUSED)
break;
if (!arg_type_is_raw_mem(fn->arg_type[i]))
continue;
@@ -9339,7 +9767,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++) {
- if (fn->arg_type[i] == ARG_DONTCARE)
+ if (fn->arg_type[i] == ARG_UNUSED)
break;
if (base_type(fn->arg_type[i]) == ARG_PTR_TO_BTF_ID)
return !!fn->arg_btf_id[i];
@@ -9362,7 +9790,7 @@ static bool check_mem_arg_rw_flag_ok(const struct bpf_func_proto *fn)
for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
enum bpf_arg_type arg_type = fn->arg_type[i];
- if (arg_type == ARG_DONTCARE)
+ if (arg_type == ARG_UNUSED)
break;
if (base_type(arg_type) != ARG_PTR_TO_MEM)
continue;
@@ -9380,7 +9808,7 @@ static bool check_proto_release_reg(const struct bpf_func_proto *fn, struct bpf_
for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
enum bpf_arg_type arg_type = fn->arg_type[i];
- if (arg_type == ARG_DONTCARE)
+ if (arg_type == ARG_UNUSED)
break;
if (arg_type_is_release(arg_type)) {
if (meta->release_regno)
@@ -9392,9 +9820,42 @@ static bool check_proto_release_reg(const struct bpf_func_proto *fn, struct bpf_
return true;
}
-static int check_func_proto(const struct bpf_func_proto *fn, struct bpf_call_arg_meta *meta)
+static bool check_arg_prog_aux(struct bpf_verifier_env *env,
+ const struct bpf_func_proto *proto)
+{
+ bool seen = false;
+ argno_t argno;
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(proto->arg_type); i++) {
+ if (proto->arg_type[i] == ARG_UNUSED)
+ break;
+ if (proto->arg_type[i] != ARG_PTR_TO_PROG_AUX)
+ continue;
+
+ if (seen) {
+ verifier_bug(env, "Only 1 prog->aux argument supported");
+ return false;
+ }
+
+ argno = argno_from_arg(i + 1);
+ if (reg_from_argno(argno) < 0) {
+ verbose(env, "%s prog->aux cannot be a stack argument\n",
+ reg_arg_name(env, argno));
+ return false;
+ }
+
+ seen = true;
+ }
+
+ return true;
+}
+
+static int check_func_proto(struct bpf_verifier_env *env, const struct bpf_func_proto *fn,
+ struct bpf_call_arg_meta *meta)
{
- return check_raw_mode_ok(fn, meta) &&
+ return check_arg_prog_aux(env, fn) &&
+ check_raw_mode_ok(fn, meta) &&
check_arg_pair_ok(fn) &&
check_mem_arg_rw_flag_ok(fn) &&
check_proto_release_reg(fn, meta) &&
@@ -9713,12 +10174,16 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
struct bpf_subprog_info *sub = subprog_info(env, subprog);
struct bpf_func_state *caller = cur_func(env);
struct bpf_verifier_log *log = &env->log;
- struct ref_obj_desc ref_obj = {};
const struct btf_param *args;
const struct btf_type *func, *func_proto;
+ struct bpf_call_arg_meta meta;
u32 i;
int ret, err;
+ /* Leave btf and func_id zero: this is neither a helper nor a kfunc. */
+ memset(&meta, 0, sizeof(meta));
+ meta.func_name = bpf_subprog_name(env, subprog);
+
ret = btf_prepare_func_args(env, subprog);
if (ret) {
if (bpf_in_stack_arg_cnt(sub) > 0) {
@@ -9747,7 +10212,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
struct bpf_reg_state *reg = get_func_arg_reg(caller, regs, i);
struct bpf_subprog_arg_info *arg = &sub->args[i];
- if (arg->arg_type == ARG_ANYTHING) {
+ if (arg->arg_type == ARG_SCALAR) {
if (reg->type != SCALAR_VALUE) {
bpf_log(log, "%s is not a scalar\n", reg_arg_name(env, argno));
return -EINVAL;
@@ -9771,7 +10236,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
return -EINVAL;
}
} else if (base_type(arg->arg_type) == ARG_PTR_TO_MEM) {
- ret = check_func_arg_reg_off(env, reg, argno, ARG_DONTCARE);
+ ret = check_func_arg_reg_off(env, reg, argno, ARG_PTR_TO_MEM);
if (ret < 0)
return ret;
if (check_mem_reg(env, reg, argno, arg->mem_size, BPF_READ | BPF_WRITE, NULL,
@@ -9802,21 +10267,21 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
return ret;
ret = process_dynptr_func(env, reg, argno, env->insn_idx,
- bpf_subprog_name(env, subprog), arg->arg_type,
- &ref_obj, NULL);
+ arg->arg_type, &meta);
if (ret)
return ret;
} else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) {
- struct bpf_call_arg_meta meta;
int err;
if (bpf_register_is_null(reg) && type_may_be_null(arg->arg_type))
continue;
- memset(&meta, 0, sizeof(meta)); /* leave func_id as zero */
- err = check_reg_type(env, reg, argno, arg->arg_type, &arg->btf_id, &meta,
- bpf_subprog_name(env, subprog));
+ err = check_reg_type(env, reg, argno, arg->arg_type, &meta);
err = err ?: check_func_arg_reg_off(env, reg, argno, arg->arg_type);
+ if (!err && base_type(reg->type) == PTR_TO_BTF_ID)
+ err = process_arg_ptr_to_btf_id(env, reg, argno, arg->arg_type,
+ btf_vmlinux, arg->btf_id,
+ &meta, env->insn_idx);
if (err)
return err;
} else {
@@ -10908,7 +11373,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
memset(&meta, 0, sizeof(meta));
- err = check_func_proto(fn, &meta);
+ err = check_func_proto(env, fn, &meta);
if (err) {
verifier_bug(env, "incorrect func proto %s#%d", func_id_name(func_id), func_id);
return err;
@@ -10929,13 +11394,11 @@ 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.func_name = func_id_name(func_id);
meta.fn = fn;
- /* check args */
- for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
- err = check_func_arg(env, i, &meta, insn_idx);
- if (err)
- return err;
- }
+ err = check_func_args(env, &meta, insn_idx);
+ if (err)
+ return err;
err = record_func_map(env, &meta, func_id, insn_idx);
if (err)
@@ -11758,6 +12221,49 @@ static bool btf_type_is_scalar_struct(struct bpf_verifier_env *env,
return btf_struct_is_composed_of(env, btf, t, BTF_MEMBER_SCALAR);
}
+static int resolve_func_arg_type(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg, u32 arg,
+ struct bpf_call_arg_meta *meta,
+ enum bpf_arg_type *arg_type, u32 *arg_size)
+{
+ argno_t argno = argno_from_arg(arg + 1);
+ const struct btf_param *args;
+ const struct btf_type *ref_t, *resolve_ret;
+ const struct btf *btf;
+ const char *ref_tname;
+ u32 ref_id;
+
+ if (base_type(*arg_type) == ARG_PTR_TO_MAP_VALUE)
+ return resolve_map_arg_type(env, meta, arg_type);
+
+ if (base_type(*arg_type) == ARG_PTR_TO_BTF_ID) {
+ if (!meta->btf || arg_type_is_release(*arg_type) ||
+ base_type(reg->type) == PTR_TO_BTF_ID ||
+ reg2btf_ids[base_type(reg->type)])
+ return 0;
+
+ args = btf_params(meta->func_proto);
+ ref_id = *meta->fn->arg_btf_id[arg];
+ btf = is_kfunc_arg_map(meta->btf, &args[arg]) ? btf_vmlinux : meta->btf;
+ ref_t = btf_type_skip_modifiers(btf, ref_id, &ref_id);
+ ref_tname = btf_name_by_offset(btf, ref_t->name_off);
+
+ if (!btf_type_is_scalar_struct(env, btf, ref_t))
+ return 0;
+
+ resolve_ret = btf_resolve_size(btf, ref_t, arg_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;
+ }
+ *arg_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE | (*arg_type & PTR_MAYBE_NULL);
+ }
+
+ return 0;
+}
+
static void btf_member_path_str(const struct btf *btf, const struct btf_member_path *path,
char *buf, size_t buf_sz)
{
@@ -11777,34 +12283,6 @@ static void btf_member_path_str(const struct btf *btf, const struct btf_member_p
}
}
-enum kfunc_ptr_arg_type {
- KF_ARG_CONST_MEM_SIZE,
- KF_ARG_MEM_SIZE,
- KF_ARG_CONST,
- KF_ARG_CONST_ALLOC_SIZE_OR_ZERO,
- KF_ARG_ANYTHING,
- KF_ARG_PTR_TO_CTX,
- KF_ARG_PTR_TO_ALLOC_BTF_ID, /* Allocated object */
- KF_ARG_PTR_TO_REFCOUNTED_KPTR, /* Refcounted local kptr */
- KF_ARG_PTR_TO_DYNPTR,
- KF_ARG_PTR_TO_ITER,
- KF_ARG_PTR_TO_LIST_HEAD,
- 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_CALLBACK,
- KF_ARG_PTR_TO_RB_ROOT,
- KF_ARG_PTR_TO_RB_NODE,
- KF_ARG_PTR_TO_CONST_STR,
- 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_PTR_TO_ARENA,
-};
-
enum special_kfunc_type {
KF_bpf_obj_new_impl,
KF_bpf_obj_new,
@@ -11872,7 +12350,10 @@ enum special_kfunc_type {
KF_bpf_task_work_schedule_resume,
KF_bpf_arena_alloc_pages,
KF_bpf_arena_free_pages,
+ KF_bpf_arena_reserve_pages,
KF_bpf_session_is_return,
+ KF_bpf_stream_vprintk,
+ KF_bpf_stream_print_stack,
};
BTF_ID_LIST(special_kfunc_list)
@@ -11962,11 +12443,29 @@ BTF_ID(func, bpf_task_work_schedule_signal)
BTF_ID(func, bpf_task_work_schedule_resume)
BTF_ID(func, bpf_arena_alloc_pages)
BTF_ID(func, bpf_arena_free_pages)
+BTF_ID(func, bpf_arena_reserve_pages)
#ifdef CONFIG_BPF_EVENTS
BTF_ID(func, bpf_session_is_return)
#else
BTF_ID_UNUSED
#endif
+BTF_ID(func, bpf_stream_vprintk)
+BTF_ID(func, bpf_stream_print_stack)
+
+static bool is_bpf_cast_to_kern_ctx_kfunc(const struct bpf_call_arg_meta *meta)
+{
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_cast_to_kern_ctx]);
+}
+
+static bool is_bpf_dynptr_clone_kfunc(const struct bpf_call_arg_meta *meta)
+{
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_clone]);
+}
+
+static bool is_bpf_iter_css_task_new_kfunc(const struct bpf_call_arg_meta *meta)
+{
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_iter_css_task_new]);
+}
static bool is_bpf_obj_new_kfunc(u32 func_id)
{
@@ -12029,52 +12528,63 @@ static bool is_kfunc_ret_null(struct bpf_call_arg_meta *meta)
static bool is_kfunc_bpf_rcu_read_lock(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_rcu_read_lock];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_rcu_read_lock]);
}
static bool is_kfunc_bpf_rcu_read_unlock(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_rcu_read_unlock];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_rcu_read_unlock]);
}
static bool is_kfunc_bpf_preempt_disable(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_preempt_disable];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_preempt_disable]);
}
static bool is_kfunc_bpf_preempt_enable(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_preempt_enable];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_preempt_enable]);
}
bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_xdp_pull_data];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_xdp_pull_data]);
}
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)
+ const struct btf_param *args, int arg, int nargs,
+ struct bpf_func_proto *proto)
{
- const struct btf_type *t, *ref_t = NULL;
+ const struct btf_type *t, *ref_t = NULL, *resolve_ret;
+ const u32 *ref_id_ptr = NULL;
argno_t argno = argno_from_arg(arg + 1);
const char *ref_tname = NULL;
+ u32 ref_id, type_size;
int arg_type;
+ proto->arg_btf_id[arg] = NULL;
+
+ if (is_kfunc_arg_prog_aux(meta->btf, &args[arg]))
+ return ARG_PTR_TO_PROG_AUX;
+
+ if (is_kfunc_arg_ignore(meta->btf, &args[arg]) || is_kfunc_arg_implicit(meta, arg))
+ return ARG_IGNORE;
+
t = btf_type_skip_modifiers(meta->btf, args[arg].type, NULL);
/* 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;
+ return ARG_CONST_SCALAR;
if (is_kfunc_arg_const_mem_size(meta->btf, &args[arg]))
- return KF_ARG_CONST_MEM_SIZE;
+ return ARG_CONST_MEM_SIZE;
if (is_kfunc_arg_mem_size(meta->btf, &args[arg]))
- return KF_ARG_MEM_SIZE;
+ return 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;
+ return ARG_CONST_ALLOC_SIZE_OR_ZERO;
+ return ARG_SCALAR;
}
if (!btf_type_is_ptr(t)) {
@@ -12082,54 +12592,69 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
reg_arg_name(env, argno), btf_type_str(t));
return -EINVAL;
}
- ref_t = btf_type_skip_modifiers(meta->btf, t->type, NULL);
+ /* Keep a pointer to the BTF field containing the resolved referent ID. */
+ ref_id_ptr = &t->type;
+ ref_t = btf_type_skip_modifiers(meta->btf, *ref_id_ptr, &ref_id);
+ while (*ref_id_ptr != ref_id)
+ ref_id_ptr = &btf_type_by_id(meta->btf, *ref_id_ptr)->type;
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.
+ * arguments, we resolve it to a known bpf_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])
- arg_type = KF_ARG_PTR_TO_CTX;
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_cast_to_kern_ctx]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_session_is_return]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_session_cookie]))
+ arg_type = 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;
+ arg_type = ARG_PTR_TO_CTX;
else if (is_kfunc_arg_alloc_obj(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_ALLOC_BTF_ID;
+ arg_type = 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;
+ arg_type = ARG_PTR_TO_REFCOUNTED_KPTR;
+ else if (is_kfunc_arg_dynptr(meta->btf, &args[arg])) {
+ arg_type = ARG_PTR_TO_DYNPTR;
+
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_skb]))
+ arg_type |= DYNPTR_TYPE_SKB;
+ else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_xdp]))
+ arg_type |= DYNPTR_TYPE_XDP;
+ else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_skb_meta]))
+ arg_type |= DYNPTR_TYPE_SKB_META;
+ else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_file]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_file_discard]))
+ /* OBJ_RELEASE for the latter comes from KF_RELEASE below */
+ arg_type |= DYNPTR_TYPE_FILE;
+ } else if (is_kfunc_arg_iter(meta, arg, &args[arg]))
+ arg_type = ARG_PTR_TO_ITER;
else if (is_kfunc_arg_list_head(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_LIST_HEAD;
+ arg_type = ARG_PTR_TO_LIST_HEAD;
else if (is_kfunc_arg_list_node(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_LIST_NODE;
+ arg_type = ARG_PTR_TO_LIST_NODE;
else if (is_kfunc_arg_rbtree_root(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_RB_ROOT;
+ arg_type = ARG_PTR_TO_RB_ROOT;
else if (is_kfunc_arg_rbtree_node(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_RB_NODE;
+ arg_type = ARG_PTR_TO_RB_NODE;
else if (is_kfunc_arg_const_str(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_CONST_STR;
+ arg_type = ARG_PTR_TO_CONST_STR;
else if (is_kfunc_arg_const_map(meta->btf, &args[arg]))
- arg_type = KF_ARG_CONST_MAP_PTR;
+ arg_type = ARG_CONST_MAP_PTR;
else if (is_kfunc_arg_map(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_BTF_ID;
+ arg_type = ARG_PTR_TO_BTF_ID;
else if (is_kfunc_arg_wq(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_WORKQUEUE;
+ arg_type = ARG_PTR_TO_WORKQUEUE;
else if (is_kfunc_arg_timer(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_TIMER;
+ arg_type = ARG_PTR_TO_TIMER;
else if (is_kfunc_arg_task_work(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_TASK_WORK;
+ arg_type = ARG_PTR_TO_TASK_WORK;
else if (is_kfunc_arg_irq_flag(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_IRQ_FLAG;
+ arg_type = 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;
+ arg_type = ARG_PTR_TO_RES_SPIN_LOCK;
else if (is_kfunc_arg_callback(env, meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_CALLBACK;
+ arg_type = ARG_PTR_TO_FUNC;
else if (is_kfunc_arg_arena(meta->btf, &args[arg])) {
if (!bpf_jit_supports_arena_args()) {
verbose(env, "JIT does not support kfunc %s() with arena pointer arguments\n",
@@ -12152,7 +12677,7 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
* whether the JIT rebases it to the arena base or preserves NULL.
* The common nullable path below records that verifier property.
*/
- arg_type = KF_ARG_PTR_TO_ARENA;
+ arg_type = ARG_PTR_TO_ARENA;
} 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]))) {
@@ -12162,10 +12687,10 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
reg_arg_name(env, argno), btf_type_str(ref_t), ref_tname);
return -EINVAL;
}
- arg_type = KF_ARG_PTR_TO_MEM;
+ arg_type = ARG_PTR_TO_MEM;
} else if (btf_type_is_struct(ref_t))
- /* 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;
+ /* A pointer to a struct without a size argument is classified as ARG_PTR_TO_BTF_ID */
+ arg_type = ARG_PTR_TO_BTF_ID;
else {
/*
* Otherwise this is a fixed-size memory buffer supported by
@@ -12178,19 +12703,53 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
reg_arg_name(env, argno), btf_type_str(ref_t), ref_tname);
return -EINVAL;
}
- arg_type = KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
+ resolve_ret = btf_resolve_size(meta->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;
+ }
+ proto->arg_size[arg] = type_size;
+ arg_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
}
+ if (is_kfunc_arg_uninit(meta->btf, &args[arg]))
+ arg_type |= MEM_UNINIT;
+
if (is_kfunc_arg_nullable(meta->btf, &args[arg]))
arg_type |= PTR_MAYBE_NULL;
+ /*
+ * Only the first argument of a KF_RELEASE kfunc releases anything, and
+ * bpf_fetch_kfunc_arg_meta() only ever records BPF_REG_1 for it.
+ */
+ if (is_kfunc_release(meta) && arg == 0)
+ arg_type |= OBJ_RELEASE;
+
+ if (base_type(arg_type) == ARG_PTR_TO_BTF_ID) {
+ /* A __map argument names a vmlinux type rather than one from
+ * the kfunc's own BTF.
+ */
+ if (is_kfunc_arg_map(meta->btf, &args[arg]))
+ proto->arg_btf_id[arg] = reg2btf_ids[CONST_PTR_TO_MAP];
+ else
+ proto->arg_btf_id[arg] = ref_id_ptr;
+
+ /* A KF_RCU kfunc accepts an RCU-protected pointer where it would
+ * otherwise demand a referenced or trusted one.
+ */
+ if (is_kfunc_rcu(meta))
+ arg_type |= MEM_RCU;
+ }
+
return arg_type;
}
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;
@@ -12209,47 +12768,38 @@ static int gen_kfunc_arg_proto(struct bpf_verifier_env *env, struct bpf_call_arg
}
for (i = 0; i < nargs; i++) {
- if (is_kfunc_arg_prog_aux(btf, &args[i]) ||
- is_kfunc_arg_ignore(btf, &args[i]) ||
- is_kfunc_arg_implicit(meta, i))
- continue;
-
- arg_type = get_kfunc_arg_type(env, meta, args, i, nargs);
+ arg_type = get_kfunc_arg_type(env, meta, args, i, nargs, proto);
if (arg_type < 0)
return arg_type;
proto->arg_type[i] = arg_type;
}
- return 0;
+ return check_arg_prog_aux(env, proto) ? 0 : -EINVAL;
}
-static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
- struct bpf_reg_state *reg,
- const struct btf_type *ref_t,
- const char *ref_tname, u32 ref_id,
- struct bpf_call_arg_meta *meta,
- int arg, argno_t argno)
+static int process_arg_ptr_to_btf_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+ argno_t argno, enum bpf_arg_type arg_type,
+ const struct btf *arg_btf, u32 arg_btf_id,
+ struct bpf_call_arg_meta *meta, int insn_idx)
{
- const struct btf_type *reg_ref_t;
- bool strict_type_match = false;
+ bool taking_projection, struct_same, strict_type_match = false;
+ const struct btf_type *arg_t, *reg_t;
+ const char *arg_tname, *reg_tname;
const struct btf *reg_btf;
- const char *reg_ref_tname;
- bool taking_projection;
- bool struct_same;
- u32 reg_ref_id;
+ u32 reg_btf_id;
if (base_type(reg->type) == PTR_TO_BTF_ID) {
reg_btf = reg->btf;
- reg_ref_id = reg->btf_id;
+ reg_btf_id = reg->btf_id;
} else {
reg_btf = btf_vmlinux;
- reg_ref_id = *reg2btf_ids[base_type(reg->type)];
+ reg_btf_id = *reg2btf_ids[base_type(reg->type)];
}
- /* Enforce strict type matching for calls to kfuncs that are acquiring
- * or releasing a reference, or are no-cast aliases. We do _not_
- * enforce strict matching for kfuncs by default,
+ /*
+ * Enforce strict type matching for arguments that release a reference,
+ * or are no-cast aliases. We do _not_ enforce strict matching by default,
* as we want to enable BPF programs to pass types that are bitwise
* equivalent without forcing them to explicitly cast with something
* like bpf_cast_to_kern_ctx().
@@ -12271,27 +12821,30 @@ static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
* btf_struct_ids_match() to walk the struct at the 0th offset, and
* resolve types.
*/
- if ((is_kfunc_release(meta) && reg_is_referenced(env, reg)) ||
- btf_type_ids_nocast_alias(&env->log, reg_btf, reg_ref_id, meta->btf, ref_id))
+ if ((arg_type_is_release(arg_type) && !is_helper_call(meta, BPF_FUNC_sk_release)) ||
+ (meta->btf && btf_type_ids_nocast_alias(&env->log, reg_btf, reg_btf_id,
+ arg_btf, arg_btf_id)))
strict_type_match = true;
- WARN_ON_ONCE(is_kfunc_release(meta) && !tnum_is_const(reg->var_off));
+ arg_t = btf_type_skip_modifiers(arg_btf, arg_btf_id, &arg_btf_id);
+ arg_tname = btf_name_by_offset(arg_btf, arg_t->name_off);
+ reg_t = btf_type_skip_modifiers(reg_btf, reg_btf_id, ®_btf_id);
+ reg_tname = btf_name_by_offset(reg_btf, reg_t->name_off);
+
+ struct_same = btf_struct_ids_match(&env->log, reg_btf, reg_btf_id,
+ reg->var_off.value, arg_btf, arg_btf_id,
+ strict_type_match, !type_is_alloc(reg->type));
- reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id, ®_ref_id);
- reg_ref_tname = btf_name_by_offset(reg_btf, reg_ref_t->name_off);
- struct_same = btf_struct_ids_match(&env->log, reg_btf, reg_ref_id, reg->var_off.value,
- meta->btf, ref_id, strict_type_match,
- !type_is_alloc(reg->type));
/* If kfunc is accepting a projection type (ie. __sk_buff), it cannot
* actually use it -- it must cast to the underlying type. So we allow
* caller to pass in the underlying type.
*/
- taking_projection = btf_is_projection_of(ref_tname, reg_ref_tname);
+ taking_projection = meta->btf && btf_is_projection_of(arg_tname, reg_tname);
if (!taking_projection && !struct_same) {
- verbose(env, "kernel function %s %s expected pointer to %s %s but %s has a pointer to %s %s\n",
+ verbose(env, "%s %s expected pointer to %s %s but %s has a pointer to %s %s\n",
meta->func_name, reg_arg_name(env, argno),
- btf_type_str(ref_t), ref_tname, reg_arg_name(env, argno),
- btf_type_str(reg_ref_t), reg_ref_tname);
+ btf_type_str(arg_t), arg_tname,
+ reg_arg_name(env, argno), btf_type_str(reg_t), reg_tname);
return -EINVAL;
}
return 0;
@@ -12303,15 +12856,15 @@ static int process_irq_flag(struct bpf_verifier_env *env, struct bpf_reg_state *
int err, spi, kfunc_class = IRQ_NATIVE_KFUNC;
bool irq_save;
- if (meta->func_id == special_kfunc_list[KF_bpf_local_irq_save] ||
- meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave]) {
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_local_irq_save]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave])) {
irq_save = true;
- if (meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave])
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave]))
kfunc_class = IRQ_LOCK_KFUNC;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_local_irq_restore] ||
- meta->func_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]) {
+ } else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_local_irq_restore]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore])) {
irq_save = false;
- if (meta->func_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore])
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]))
kfunc_class = IRQ_LOCK_KFUNC;
} else {
verifier_bug(env, "unknown irq flags kfunc");
@@ -12504,12 +13057,20 @@ static bool is_bpf_rbtree_api_kfunc(u32 btf_id)
btf_id == special_kfunc_list[KF_bpf_rbtree_right];
}
-static bool is_bpf_res_spin_lock_kfunc(u32 btf_id)
+static int get_bpf_res_spin_lock_kfunc_flags(const struct bpf_call_arg_meta *meta)
{
- return btf_id == special_kfunc_list[KF_bpf_res_spin_lock] ||
- btf_id == special_kfunc_list[KF_bpf_res_spin_unlock] ||
- btf_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave] ||
- btf_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore];
+ int flags = PROCESS_RES_LOCK;
+
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave]))
+ flags |= PROCESS_SPIN_LOCK;
+ else if (!is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock]) &&
+ !is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]))
+ return 0;
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]))
+ flags |= PROCESS_LOCK_IRQ;
+ return flags;
}
static bool kfunc_spin_allowed(struct bpf_verifier_env *env, s32 func_id, s16 offset)
@@ -12786,697 +13347,6 @@ static bool check_css_task_iter_allowlist(struct bpf_verifier_env *env)
}
}
-static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
- int insn_idx)
-{
- const char *func_name = meta->func_name, *ref_tname;
- struct bpf_func_state *caller = cur_func(env);
- struct bpf_reg_state *regs = cur_regs(env);
- const struct btf *btf = meta->btf;
- const struct btf_param *args;
- struct btf_record *rec;
- u32 i, nargs;
- int ret;
-
- args = (const struct btf_param *)(meta->func_proto + 1);
- nargs = btf_type_vlen(meta->func_proto);
-
- ret = check_outgoing_stack_args(env, caller, nargs, func_name, btf, args);
- if (ret)
- return ret;
-
- /* Check that BTF function arguments match actual types that the
- * verifier sees.
- */
- for (i = 0; i < nargs; i++) {
- struct bpf_reg_state *reg = get_func_arg_reg(caller, regs, i);
- const struct btf_type *t, *ref_t, *resolve_ret;
- enum bpf_arg_type arg_type = ARG_DONTCARE;
- argno_t argno = argno_from_arg(i + 1);
- int regno = reg_from_argno(argno);
- bool btf_id_fixed_off_ok = true;
- u32 ref_id = args[i].type, type_size;
- int kf_arg_type = meta->fn->arg_type[i];
-
- if (is_kfunc_arg_prog_aux(btf, &args[i])) {
- /* Reject repeated use bpf_prog_aux */
- if (meta->arg_prog) {
- verifier_bug(env, "Only 1 prog->aux argument supported per-kfunc");
- return -EFAULT;
- }
- if (regno < 0) {
- verbose(env, "%s prog->aux cannot be a stack argument\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- meta->arg_prog = true;
- cur_aux(env)->arg_prog = regno;
- continue;
- }
-
- if (is_kfunc_arg_ignore(btf, &args[i]) || is_kfunc_arg_implicit(meta, i))
- continue;
-
- t = btf_type_skip_modifiers(btf, args[i].type, NULL);
-
- 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);
- }
-
- if (btf_type_is_ptr(t) &&
- (bpf_register_is_null(reg) || type_may_be_null(reg->type)) &&
- !type_may_be_null(kf_arg_type)) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, args[i].type);
- verbose(env, "Possibly NULL pointer passed to trusted %s\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Add a NULL check and call the kfunc only on the non-NULL path.",
- "the pointer may be NULL, but this kfunc requires a non-NULL value of type %s",
- expected_type);
- return -EACCES;
- }
-
- if (regno == meta->release_regno && !is_kfunc_arg_dynptr(meta->btf, &args[i]) &&
- !reg_is_referenced(env, reg) && !bpf_register_is_null(reg)) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- verbose(env, "release kfunc %s expects referenced PTR_TO_BTF_ID passed to %s\n",
- func_name, reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass the resource-owning pointer returned by the matching acquire kfunc, and avoid calling the release kfunc after ownership has already been transferred or released.",
- "release kfuncs require a resource-owning value of type %s returned by a matching acquire kfunc",
- expected_type);
- return -EINVAL;
- }
-
- if (reg_is_referenced(env, reg))
- update_ref_obj(&meta->ref_obj, reg);
-
- if (bpf_register_is_null(reg) && type_may_be_null(kf_arg_type))
- continue;
-
- 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:
- case KF_ARG_CONST_MEM_SIZE:
- case KF_ARG_MEM_SIZE:
- case KF_ARG_ANYTHING:
- case KF_ARG_CONST_ALLOC_SIZE_OR_ZERO:
- case KF_ARG_PTR_TO_ALLOC_BTF_ID:
- case KF_ARG_PTR_TO_BTF_ID:
- 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_CALLBACK:
- case KF_ARG_PTR_TO_CONST_STR:
- case KF_ARG_PTR_TO_WORKQUEUE:
- case KF_ARG_PTR_TO_TIMER:
- case KF_ARG_PTR_TO_TASK_WORK:
- case KF_ARG_PTR_TO_IRQ_FLAG:
- case KF_ARG_PTR_TO_RES_SPIN_LOCK:
- case KF_ARG_PTR_TO_ARENA:
- break;
- case KF_ARG_PTR_TO_DYNPTR:
- arg_type = ARG_PTR_TO_DYNPTR;
- break;
- case KF_ARG_PTR_TO_CTX:
- arg_type = ARG_PTR_TO_CTX;
- break;
- case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
- arg_type = ARG_PTR_TO_BTF_ID;
- btf_id_fixed_off_ok = false;
- break;
- default:
- verifier_bug(env, "unknown kfunc arg type %d", kf_arg_type);
- return -EFAULT;
- }
-
- if (regno == meta->release_regno)
- arg_type |= OBJ_RELEASE;
- ret = __check_func_arg_reg_off(env, reg, argno, arg_type,
- btf_id_fixed_off_ok);
- if (ret < 0)
- return ret;
-
- switch (base_type(kf_arg_type)) {
- case KF_ARG_CONST:
- if (reg->type != SCALAR_VALUE) {
- verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an integer scalar value for this argument, not a pointer or resource object.",
- "the kfunc expects an integer scalar, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
-
- ret = process_const_arg(env, reg, argno, meta);
- if (ret < 0) {
- if (ret == -EINVAL)
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a compile-time constant or a value the verifier can prove is constant at this call.",
- "the kfunc requires this scalar argument to be a verifier-known constant, but %s is variable on this path",
- reg_arg_name(env, argno));
- 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));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an integer scalar value for this argument, not a pointer or resource object.",
- "the kfunc expects an integer scalar, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- 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));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an integer scalar value for this argument, not a pointer or resource object.",
- "the kfunc expects an integer scalar, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- 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) {
- if (ret == -EINVAL)
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a verifier-known constant size for this kfunc buffer argument.",
- "the kfunc uses this argument as a return-buffer size, but %s is invalid or variable on this path",
- reg_arg_name(env, argno));
- return ret;
- }
- break;
- case KF_ARG_PTR_TO_CTX:
- if (reg->type != PTR_TO_CTX) {
- verbose(env, "%s expected pointer to ctx, but got %s\n",
- reg_arg_name(env, argno), reg_type_str(env, reg->type));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass the original program context pointer or preserve it before modifying registers.",
- "the kfunc expects a context pointer, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
-
- if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) {
- ret = get_kern_ctx_btf_id(&env->log, resolve_prog_type(env->prog));
- if (ret < 0)
- return -EINVAL;
- meta->ret_btf_id = ret;
- }
- break;
- case KF_ARG_PTR_TO_ARENA:
- if (reg->type != PTR_TO_ARENA && reg->type != SCALAR_VALUE) {
- verbose(env, "%s is not a pointer to arena or scalar\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- break;
- case KF_ARG_PTR_TO_ALLOC_BTF_ID:
- if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC)) {
- if (!is_bpf_obj_drop_kfunc(meta->func_id)) {
- verbose(env, "%s expected for bpf_obj_drop()\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- } else if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU)) {
- if (!is_bpf_percpu_obj_drop_kfunc(meta->func_id)) {
- verbose(env, "%s expected for bpf_percpu_obj_drop()\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- } else {
- verbose(env, "%s expected pointer to allocated object\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a pointer returned by the matching BPF object allocation path.",
- "the kfunc expects an allocated object pointer, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- if (!reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass the owned object pointer before it is released or transferred.",
- "the allocated object pointer in %s must still carry verifier-tracked ownership, but this pointer no longer owns a live resource",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (meta->btf == btf_vmlinux) {
- meta->arg_btf = reg->btf;
- meta->arg_btf_id = reg->btf_id;
- }
- break;
- case KF_ARG_PTR_TO_DYNPTR:
- {
- enum bpf_arg_type dynptr_arg_type = ARG_PTR_TO_DYNPTR;
-
- if (is_kfunc_arg_uninit(btf, &args[i]))
- dynptr_arg_type |= MEM_UNINIT;
-
- if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {
- dynptr_arg_type |= DYNPTR_TYPE_SKB;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) {
- dynptr_arg_type |= DYNPTR_TYPE_XDP;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb_meta]) {
- dynptr_arg_type |= DYNPTR_TYPE_SKB_META;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_file]) {
- dynptr_arg_type |= DYNPTR_TYPE_FILE;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_file_discard]) {
- dynptr_arg_type |= DYNPTR_TYPE_FILE | OBJ_RELEASE;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_clone] &&
- (dynptr_arg_type & MEM_UNINIT)) {
- enum bpf_dynptr_type parent_type = meta->dynptr.type;
-
- if (parent_type == BPF_DYNPTR_TYPE_INVALID) {
- verifier_bug(env, "no dynptr type for parent of clone");
- return -EFAULT;
- }
-
- dynptr_arg_type |= (unsigned int)get_dynptr_type_flag(parent_type);
- }
-
- ret = process_dynptr_func(env, reg, argno, insn_idx, func_name,
- dynptr_arg_type, &meta->ref_obj, &meta->dynptr);
- if (ret < 0)
- return ret;
- break;
- }
- case KF_ARG_PTR_TO_ITER:
- if (meta->func_id == special_kfunc_list[KF_bpf_iter_css_task_new]) {
- if (!check_css_task_iter_allowlist(env)) {
- verbose(env, "css_task_iter is only allowed in bpf_lsm, bpf_iter and sleepable progs\n");
- return -EINVAL;
- }
- }
- ret = process_iter_arg(env, reg, argno, insn_idx, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_LIST_HEAD:
- if (reg->type != PTR_TO_MAP_VALUE &&
- reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s expected pointer to map value or allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) &&
- !reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- return -EINVAL;
- }
- ret = process_kf_arg_ptr_to_list_head(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_RB_ROOT:
- if (reg->type != PTR_TO_MAP_VALUE &&
- reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s expected pointer to map value or allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) &&
- !reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- return -EINVAL;
- }
- ret = process_kf_arg_ptr_to_rbtree_root(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_LIST_NODE:
- if (is_kfunc_arg_nonown_allowed(btf, &args[i]) &&
- type_is_non_owning_ref(reg->type) && !reg_is_referenced(env, reg)) {
- /* Allow bpf_list_front/back return value for
- * __nonown_allowed list-node arguments.
- */
- goto check_ok;
- }
- if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s expected pointer to allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (!reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- return -EINVAL;
- }
-check_ok:
- ret = process_kf_arg_ptr_to_list_node(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_RB_NODE:
- if (is_bpf_rbtree_add_kfunc(meta->func_id)) {
- if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s expected pointer to allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (!reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- return -EINVAL;
- }
- } else {
- if (!type_is_non_owning_ref(reg->type) &&
- !reg_is_referenced(env, reg)) {
- verbose(env, "%s can only take non-owning or refcounted bpf_rb_node pointer\n", func_name);
- return -EINVAL;
- }
- if (in_rbtree_lock_required_cb(env)) {
- verbose(env, "%s not allowed in rbtree cb\n", func_name);
- return -EINVAL;
- }
- }
-
- ret = process_kf_arg_ptr_to_rbtree_node(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_CONST_MAP_PTR:
- if (base_type(reg->type) != CONST_PTR_TO_MAP ||
- type_may_be_null(reg->type)) {
- verbose(env, "pointer in %s isn't map pointer\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- ret = process_map_ptr_arg(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- 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) ||
- bpf_type_has_unsafe_modifiers(reg->type)) {
- if (!is_kfunc_rcu(meta)) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- verbose(env, "%s must be referenced or trusted\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a pointer acquired from a verifier-tracked source, or call this kfunc only inside the required protection if it accepts RCU pointers.",
- "the kfunc requires a trusted or resource-owning pointer to %s, but %s is %s",
- expected_type,
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- if (!is_rcu_reg(reg)) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- verbose(env, "%s must be a rcu pointer\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Use this kfunc with a pointer that is valid in an RCU read lock region.",
- "the kfunc requires an RCU-protected pointer to %s, but %s is %s",
- expected_type,
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- 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)) {
- enum bpf_reg_type reg2btf_type = lookup_reg2btf_ids(ref_id);
- const char *expected_type;
-
- 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");
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a verifier-tracked pointer to the expected kernel object type, not a pointer to stack storage or another memory buffer.",
- "the kfunc expects a pointer to %s, but this argument is %s and cannot be used as that kernel object pointer",
- expected_type,
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
-
- /*
- * 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) {
- bool known_memory;
-
- 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, &known_memory);
- if (ret < 0) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- if (known_memory)
- bpf_diag_call_arg_fmt(
- env, insn_idx, argno, func_name,
- "Pass memory with at least the required number of accessible bytes and suitable read and write access.",
- "the kfunc expects %u bytes of memory for %s, but the verifier cannot prove that %s provides a readable and writable range of that size",
- type_size, expected_type,
- bpf_diag_reg_type_plain(env, reg->type));
- else
- bpf_diag_call_arg_fmt(
- env, insn_idx, argno, func_name,
- "Pass stack, map, context, or other verifier-known memory of the expected type and size, not an integer cast to a pointer.",
- "the kfunc expects %u bytes of memory for %s, but it is %s and not verifier-known memory",
- type_size, expected_type,
- bpf_diag_reg_type_plain(env, reg->type));
- return ret;
- }
- }
- break;
- case KF_ARG_CONST_MEM_SIZE:
- ret = process_const_arg(env, reg, argno, meta);
- if (ret < 0) {
- if (ret == -EINVAL)
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a compile-time constant or a value the verifier can prove is constant at this call.",
- "the kfunc requires this memory size to be a verifier-known constant, but %s is variable on this path",
- reg_arg_name(env, argno));
- return ret;
- }
- fallthrough;
- case KF_ARG_MEM_SIZE:
- {
- struct bpf_reg_state *buff_reg = get_func_arg_reg(caller, regs, i - 1);
- struct bpf_reg_state *size_reg = reg;
- argno_t buff_argno = argno_from_arg(i);
- enum bpf_mem_size_failure failure;
-
- if (reg->type != SCALAR_VALUE) {
- verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an integer scalar length for this memory argument.",
- "the kfunc expects a scalar memory size, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
-
- if (bpf_register_is_null(buff_reg))
- break;
-
- ret = check_mem_size_reg(env, buff_reg, size_reg, buff_argno, argno,
- BPF_READ | BPF_WRITE, true, meta, &failure);
- if (ret < 0) {
- const char *buff_arg, *size_arg;
-
- buff_arg = bpf_diag_arg_name(env, buff_argno);
- size_arg = bpf_diag_arg_name(env, argno);
- verbose(env, "%s and ", reg_arg_name(env, buff_argno));
- verbose(env, "%s memory, len pair leads to invalid memory access\n",
- reg_arg_name(env, argno));
- if (failure == BPF_MEM_SIZE_FAIL_MEMORY) {
- bpf_diag_call_arg_fmt(env, insn_idx, buff_argno, func_name,
- "Pass a stack, map, context, or other verifier-known memory pointer, and keep the paired length within that object.",
- "it is the memory pointer in a memory/length pair with %s, but %s does not describe verifier-readable memory for the requested length",
- size_arg, buff_arg);
- } else if (failure == BPF_MEM_SIZE_FAIL_SIZE) {
- if (reg_smin(size_reg) < 0)
- bpf_diag_call_arg_fmt(
- env, insn_idx, argno, func_name,
- "Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.",
- "the memory size in %s may be negative because its signed minimum is %lld",
- size_arg, reg_smin(size_reg));
- else
- bpf_diag_call_arg_fmt(
- env, insn_idx, argno, func_name,
- "Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.",
- "the memory size in %s may reach %llu bytes, but variable memory accesses must stay below %u bytes",
- size_arg, reg_umax(size_reg), BPF_MAX_VAR_SIZ);
- }
- return ret;
- }
- 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));
- return -EINVAL;
- }
- meta->subprogno = reg->subprogno;
- break;
- case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
- if (!type_is_ptr_alloc_obj(reg->type)) {
- verbose(env, "%s is neither owning or non-owning ref\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an owning or non-owning pointer to a BPF-managed object containing a bpf_refcount field.",
- "the kfunc expects a pointer to a BPF-managed refcounted object, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- if (!type_is_non_owning_ref(reg->type))
- meta->arg_owning_ref = true;
-
- rec = reg_btf_record(reg);
- if (!rec) {
- verifier_bug(env, "Couldn't find btf_record");
- return -EFAULT;
- }
-
- if (rec->refcount_off < 0) {
- verbose(env, "%s doesn't point to a type with bpf_refcount field\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
-
- meta->arg_btf = reg->btf;
- meta->arg_btf_id = reg->btf_id;
- break;
- case KF_ARG_PTR_TO_CONST_STR:
- if (reg->type != PTR_TO_MAP_VALUE) {
- verbose(env, "%s doesn't point to a const string\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a constant string pointer that the verifier recognizes, such as a string stored in a read-only map value.",
- "the kfunc expects a pointer to a constant string stored in verifier-known memory, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- ret = check_arg_const_str(env, reg, argno);
- if (ret)
- return ret;
- break;
- case KF_ARG_PTR_TO_WORKQUEUE:
- if (reg->type != PTR_TO_MAP_VALUE) {
- verbose(env, "%s doesn't point to a map value\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- ret = check_map_field_pointer(env, reg, argno, BPF_WORKQUEUE, &meta->map);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_TIMER:
- if (reg->type != PTR_TO_MAP_VALUE) {
- verbose(env, "%s doesn't point to a map value\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- ret = process_timer_func(env, reg, argno, &meta->map);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_TASK_WORK:
- if (reg->type != PTR_TO_MAP_VALUE) {
- verbose(env, "%s doesn't point to a map value\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- ret = check_map_field_pointer(env, reg, argno, BPF_TASK_WORK, &meta->map);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_IRQ_FLAG:
- if (reg->type != PTR_TO_STACK) {
- verbose(env, "%s doesn't point to an irq flag on stack\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass the same stack slot used by bpf_local_irq_save() or bpf_res_spin_lock_irqsave().",
- "the kfunc expects a stack pointer to an IRQ flag slot, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- ret = process_irq_flag(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_RES_SPIN_LOCK:
- {
- int flags = PROCESS_RES_LOCK;
-
- if (reg->type != PTR_TO_MAP_VALUE && reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s doesn't point to map value or allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
-
- if (!is_bpf_res_spin_lock_kfunc(meta->func_id))
- return -EFAULT;
- if (meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock] ||
- meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave])
- flags |= PROCESS_SPIN_LOCK;
- if (meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave] ||
- meta->func_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore])
- flags |= PROCESS_LOCK_IRQ;
- ret = process_spin_lock(env, reg, argno, flags);
- if (ret < 0)
- return ret;
- break;
- }
- }
- }
-
- return 0;
-}
int bpf_fetch_kfunc_arg_meta(struct bpf_verifier_env *env,
s32 func_id,
@@ -13808,12 +13678,12 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg
struct btf_field *field = meta->arg_rbtree_root.field;
mark_reg_graph_node(regs, BPF_REG_0, &field->graph_root);
- } else if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) {
+ } else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_cast_to_kern_ctx])) {
mark_reg_known_zero(env, regs, BPF_REG_0);
regs[BPF_REG_0].type = PTR_TO_BTF_ID | PTR_TRUSTED;
regs[BPF_REG_0].btf = desc_btf;
regs[BPF_REG_0].btf_id = meta->ret_btf_id;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_rdonly_cast]) {
+ } else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_rdonly_cast])) {
ret_t = btf_type_by_id(desc_btf, meta->arg_constant.value);
if (!ret_t) {
verbose(env, "Unknown type ID %lld passed to kfunc bpf_rdonly_cast\n",
@@ -13833,8 +13703,8 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg
"kfunc bpf_rdonly_cast type ID argument must be of a struct or void\n");
return -EINVAL;
}
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_slice] ||
- meta->func_id == special_kfunc_list[KF_bpf_dynptr_slice_rdwr]) {
+ } else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_slice]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_slice_rdwr])) {
enum bpf_type_flag type_flag = get_dynptr_type_flag(meta->dynptr.type);
mark_reg_known_zero(env, regs, BPF_REG_0);
@@ -13849,7 +13719,7 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg
/* PTR_MAYBE_NULL will be added when is_kfunc_ret_null is checked */
regs[BPF_REG_0].type = PTR_TO_MEM | type_flag;
- if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_slice]) {
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_slice])) {
regs[BPF_REG_0].type |= MEM_RDONLY;
} else {
/* this will set env->seen_direct_write to true */
@@ -13969,7 +13839,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
insn_aux->non_sleepable = true;
/* Check the arguments */
- err = check_kfunc_args(env, &meta, insn_idx);
+ err = check_func_args(env, &meta, insn_idx);
if (err < 0)
return err;
@@ -17823,7 +17693,7 @@ bool bpf_get_call_summary(struct bpf_verifier_env *env, struct bpf_insn *call,
cs->is_void = fn->ret_type == RET_VOID;
cs->num_params = 0;
for (i = 0; i < ARRAY_SIZE(fn->arg_type); ++i) {
- if (fn->arg_type[i] == ARG_DONTCARE)
+ if (fn->arg_type[i] == ARG_UNUSED)
break;
cs->num_params++;
}
@@ -19619,7 +19489,7 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
}
/* Also ensure the callback only has a single scalar argument. */
- if (sub->arg_cnt != 1 || sub->args[0].arg_type != ARG_ANYTHING) {
+ if (sub->arg_cnt != 1 || sub->args[0].arg_type != ARG_SCALAR) {
verbose(env, "exception cb only supports single integer argument\n");
ret = -EINVAL;
goto out;
@@ -19632,7 +19502,7 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
if (arg->arg_type == ARG_PTR_TO_CTX) {
reg->type = PTR_TO_CTX;
mark_reg_known_zero(env, regs, i);
- } else if (arg->arg_type == ARG_ANYTHING) {
+ } else if (arg->arg_type == ARG_SCALAR) {
reg->type = SCALAR_VALUE;
mark_reg_unknown(env, regs, i);
} else if (arg->arg_type == ARG_PTR_TO_DYNPTR) {
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 29260951aa871..e414858581d04 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -195,7 +195,7 @@ static const struct bpf_func_proto bpf_override_return_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
#endif
@@ -222,7 +222,7 @@ const struct bpf_func_proto bpf_probe_read_user_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static __always_inline int
@@ -259,7 +259,7 @@ const struct bpf_func_proto bpf_probe_read_user_str_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_probe_read_kernel, void *, dst, u32, size,
@@ -274,7 +274,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static __always_inline int
@@ -309,7 +309,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_str_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
@@ -329,7 +329,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_probe_read_compat_str, void *, dst, u32, size,
@@ -348,7 +348,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_str_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
@@ -381,7 +381,7 @@ static const struct bpf_func_proto bpf_probe_write_user_proto = {
.func = bpf_probe_write_user,
.gpl_only = true,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE,
};
@@ -560,7 +560,7 @@ static const struct bpf_func_proto bpf_seq_printf_btf_proto = {
.arg1_btf_id = &btf_seq_file_ids[0],
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static __always_inline int
@@ -606,7 +606,7 @@ const struct bpf_func_proto bpf_perf_event_read_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_perf_event_read_value, struct bpf_map *, map, u64, flags,
@@ -631,7 +631,7 @@ static const struct bpf_func_proto bpf_perf_event_read_value_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -728,7 +728,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -914,7 +914,7 @@ const struct bpf_func_proto bpf_send_signal_proto = {
.func = bpf_send_signal,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_send_signal_thread, u32, sig)
@@ -926,7 +926,7 @@ const struct bpf_func_proto bpf_send_signal_thread_proto = {
.func = bpf_send_signal_thread,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_d_path, const struct path *, path, char *, buf, u32, sz)
@@ -1056,7 +1056,7 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = {
.arg2_type = ARG_MEM_SIZE,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_get_func_ip_tracing, void *, ctx)
@@ -1236,7 +1236,7 @@ static const struct bpf_func_proto bpf_get_func_arg_proto = {
.func = get_func_arg,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg3_size = sizeof(u64),
};
@@ -1419,7 +1419,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_tp = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -1444,7 +1444,7 @@ static const struct bpf_func_proto bpf_get_stackid_proto_tp = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_get_stack_tp, void *, tp_buff, void *, buf, u32, size,
@@ -1463,7 +1463,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_tp = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
@@ -1567,7 +1567,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
@@ -1644,7 +1644,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_raw_tp = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -1676,7 +1676,7 @@ static const struct bpf_func_proto bpf_get_stackid_proto_raw_tp = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_get_stack_raw_tp, struct bpf_raw_tracepoint_args *, args,
@@ -1702,7 +1702,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 1d295a8769fad..ad0f8f2222226 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -333,7 +333,7 @@ const struct bpf_func_proto bpf_sk_storage_get_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_sk_storage_get_cg_sock_proto = {
@@ -343,7 +343,7 @@ const struct bpf_func_proto bpf_sk_storage_get_cg_sock_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_CTX, /* context is 'struct sock' */
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_sk_storage_delete_proto = {
@@ -408,7 +408,7 @@ const struct bpf_func_proto bpf_sk_storage_get_tracing_proto = {
.arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
.arg2_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
.allowed = bpf_sk_storage_tracing_allowed,
};
diff --git a/net/core/filter.c b/net/core/filter.c
index 61940e7535523..89f8755989c5c 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1746,10 +1746,10 @@ static const struct bpf_func_proto bpf_skb_store_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
int __bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from,
@@ -1783,7 +1783,7 @@ static const struct bpf_func_proto bpf_skb_load_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -1822,7 +1822,7 @@ static const struct bpf_func_proto bpf_flow_dissector_load_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -1866,10 +1866,10 @@ static const struct bpf_func_proto bpf_skb_load_bytes_relative_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_skb_pull_data, struct sk_buff *, skb, u32, len)
@@ -1891,7 +1891,7 @@ static const struct bpf_func_proto bpf_skb_pull_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_sk_fullsock, struct sock *, sk)
@@ -1931,7 +1931,7 @@ static const struct bpf_func_proto sk_skb_pull_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_l3_csum_replace, struct sk_buff *, skb, u32, offset,
@@ -1972,10 +1972,10 @@ static const struct bpf_func_proto bpf_l3_csum_replace_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_l4_csum_replace, struct sk_buff *, skb, u32, offset,
@@ -2026,10 +2026,10 @@ static const struct bpf_func_proto bpf_l4_csum_replace_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_csum_diff, __be32 *, from, u32, from_size,
@@ -2067,7 +2067,7 @@ static const struct bpf_func_proto bpf_csum_diff_proto = {
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
.arg3_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE_OR_ZERO,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_csum_update, struct sk_buff *, skb, __wsum, csum)
@@ -2087,7 +2087,7 @@ static const struct bpf_func_proto bpf_csum_update_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_csum_level, struct sk_buff *, skb, u64, level)
@@ -2121,7 +2121,7 @@ static const struct bpf_func_proto bpf_csum_level_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
static inline int __bpf_rx_skb(struct net_device *dev, struct sk_buff *skb)
@@ -2506,8 +2506,8 @@ static const struct bpf_func_proto bpf_clone_redirect_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
static struct net_device *skb_get_peer_dev(struct net_device *dev)
@@ -2575,8 +2575,8 @@ static const struct bpf_func_proto bpf_redirect_proto = {
.func = bpf_redirect,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
- .arg2_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_redirect_peer, u32, ifindex, u64, flags)
@@ -2597,8 +2597,8 @@ static const struct bpf_func_proto bpf_redirect_peer_proto = {
.func = bpf_redirect_peer,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
- .arg2_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_redirect_neigh, u32, ifindex, struct bpf_redir_neigh *, params,
@@ -2625,10 +2625,10 @@ static const struct bpf_func_proto bpf_redirect_neigh_proto = {
.func = bpf_redirect_neigh,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
.arg2_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_msg_apply_bytes, struct sk_msg *, msg, u32, bytes)
@@ -2642,7 +2642,7 @@ static const struct bpf_func_proto bpf_msg_apply_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_msg_cork_bytes, struct sk_msg *, msg, u32, bytes)
@@ -2701,7 +2701,7 @@ static const struct bpf_func_proto bpf_msg_cork_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
@@ -2836,9 +2836,9 @@ static const struct bpf_func_proto bpf_msg_pull_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
@@ -3001,9 +3001,9 @@ static const struct bpf_func_proto bpf_msg_push_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
static void sk_msg_shift_left(struct sk_msg *msg, int i)
@@ -3185,9 +3185,9 @@ static const struct bpf_func_proto bpf_msg_pop_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
#ifdef CONFIG_CGROUP_NET_CLASSID
@@ -3292,7 +3292,7 @@ static const struct bpf_func_proto bpf_set_hash_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_skb_vlan_push, struct sk_buff *, skb, __be16, vlan_proto,
@@ -3318,8 +3318,8 @@ static const struct bpf_func_proto bpf_skb_vlan_push_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_skb_vlan_pop, struct sk_buff *, skb)
@@ -3532,8 +3532,8 @@ static const struct bpf_func_proto bpf_skb_change_proto_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_skb_change_type, struct sk_buff *, skb, u32, pkt_type)
@@ -3552,7 +3552,7 @@ static const struct bpf_func_proto bpf_skb_change_type_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
static u32 bpf_skb_net_base_len(const struct sk_buff *skb)
@@ -3839,9 +3839,9 @@ static const struct bpf_func_proto sk_skb_adjust_room_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
@@ -3944,9 +3944,9 @@ static const struct bpf_func_proto bpf_skb_adjust_room_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
static u32 __bpf_skb_min_len(const struct sk_buff *skb)
@@ -4040,8 +4040,8 @@ static const struct bpf_func_proto bpf_skb_change_tail_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(sk_skb_change_tail, struct sk_buff *, skb, u32, new_len,
@@ -4055,8 +4055,8 @@ static const struct bpf_func_proto sk_skb_change_tail_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
static inline int __bpf_skb_change_head(struct sk_buff *skb, u32 head_room,
@@ -4107,8 +4107,8 @@ static const struct bpf_func_proto bpf_skb_change_head_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(sk_skb_change_head, struct sk_buff *, skb, u32, head_room,
@@ -4122,8 +4122,8 @@ static const struct bpf_func_proto sk_skb_change_head_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_xdp_get_buff_len, struct xdp_buff*, xdp)
@@ -4178,7 +4178,7 @@ static const struct bpf_func_proto bpf_xdp_adjust_head_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off,
@@ -4282,7 +4282,7 @@ static const struct bpf_func_proto bpf_xdp_load_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -4314,7 +4314,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE,
};
@@ -4453,7 +4453,7 @@ static const struct bpf_func_proto bpf_xdp_adjust_tail_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_xdp_adjust_meta, struct xdp_buff *, xdp, int, offset)
@@ -4480,7 +4480,7 @@ static const struct bpf_func_proto bpf_xdp_adjust_meta_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
/**
@@ -4825,8 +4825,8 @@ static const struct bpf_func_proto bpf_xdp_redirect_proto = {
.func = bpf_xdp_redirect,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
- .arg2_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_xdp_redirect_map, struct bpf_map *, map, u64, key,
@@ -4840,8 +4840,8 @@ static const struct bpf_func_proto bpf_xdp_redirect_map_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
static unsigned long bpf_skb_copy(void *dst_buff, const void *skb,
@@ -4877,7 +4877,7 @@ static const struct bpf_func_proto bpf_skb_event_output_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -4891,7 +4891,7 @@ const struct bpf_func_proto bpf_skb_output_proto = {
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &bpf_skb_output_btf_ids[0],
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -4977,7 +4977,7 @@ static const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_skb_get_tunnel_opt, struct sk_buff *, skb, u8 *, to, u32, size)
@@ -5094,7 +5094,7 @@ static const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_skb_set_tunnel_opt, struct sk_buff *, skb,
@@ -5175,7 +5175,7 @@ static const struct bpf_func_proto bpf_skb_under_cgroup_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
#ifdef CONFIG_SOCK_CGROUP_DATA
@@ -5232,7 +5232,7 @@ static const struct bpf_func_proto bpf_skb_ancestor_cgroup_id_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_sk_cgroup_id, struct sock *, sk)
@@ -5257,7 +5257,7 @@ static const struct bpf_func_proto bpf_sk_ancestor_cgroup_id_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
#endif
@@ -5291,7 +5291,7 @@ static const struct bpf_func_proto bpf_xdp_event_output_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -5305,7 +5305,7 @@ const struct bpf_func_proto bpf_xdp_output_proto = {
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &bpf_xdp_output_btf_ids[0],
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -5853,8 +5853,8 @@ const struct bpf_func_proto bpf_sk_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5870,8 +5870,8 @@ const struct bpf_func_proto bpf_sk_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5894,8 +5894,8 @@ const struct bpf_func_proto bpf_sk_setsockopt_nodelay_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5911,8 +5911,8 @@ const struct bpf_func_proto bpf_unlocked_sk_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5928,8 +5928,8 @@ const struct bpf_func_proto bpf_unlocked_sk_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5945,8 +5945,8 @@ static const struct bpf_func_proto bpf_sock_addr_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5962,8 +5962,8 @@ static const struct bpf_func_proto bpf_sock_addr_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6007,8 +6007,8 @@ static const struct bpf_func_proto bpf_sock_create_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6033,8 +6033,8 @@ static const struct bpf_func_proto bpf_sock_create_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6059,8 +6059,8 @@ static const struct bpf_func_proto bpf_sock_ops_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6169,8 +6169,8 @@ static const struct bpf_func_proto bpf_sock_ops_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6197,7 +6197,7 @@ static const struct bpf_func_proto bpf_sock_ops_cb_flags_set_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_bind, struct bpf_sock_addr_kern *, ctx, struct sockaddr *, addr,
@@ -6290,10 +6290,10 @@ static const struct bpf_func_proto bpf_skb_get_xfrm_state_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
#endif
@@ -6700,7 +6700,7 @@ static const struct bpf_func_proto bpf_xdp_fib_lookup_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_skb_fib_lookup, struct sk_buff *, skb,
@@ -6760,7 +6760,7 @@ static const struct bpf_func_proto bpf_skb_fib_lookup_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static struct net_device *__dev_via_ifindex(struct net_device *dev_curr,
@@ -6857,11 +6857,11 @@ static const struct bpf_func_proto bpf_skb_check_mtu_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_WRITE | MEM_ALIGNED,
.arg3_size = sizeof(u32),
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {
@@ -6869,11 +6869,11 @@ static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_WRITE | MEM_ALIGNED,
.arg3_size = sizeof(u32),
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)
@@ -6955,7 +6955,7 @@ static const struct bpf_func_proto bpf_lwt_in_push_encap_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE
};
@@ -6965,7 +6965,7 @@ static const struct bpf_func_proto bpf_lwt_xmit_push_encap_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE
};
@@ -7009,7 +7009,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_store_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE
};
@@ -7098,7 +7098,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_action_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE
};
@@ -7159,8 +7159,8 @@ static const struct bpf_func_proto bpf_lwt_seg6_adjust_srh_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
#endif /* CONFIG_IPV6_SEG6_BPF */
@@ -7332,8 +7332,8 @@ static const struct bpf_func_proto bpf_skc_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sk_lookup_tcp, struct sk_buff *, skb,
@@ -7351,8 +7351,8 @@ static const struct bpf_func_proto bpf_sk_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sk_lookup_udp, struct sk_buff *, skb,
@@ -7370,8 +7370,8 @@ static const struct bpf_func_proto bpf_sk_lookup_udp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_tc_skc_lookup_tcp, struct sk_buff *, skb,
@@ -7394,8 +7394,8 @@ static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_tc_sk_lookup_tcp, struct sk_buff *, skb,
@@ -7418,8 +7418,8 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_tc_sk_lookup_udp, struct sk_buff *, skb,
@@ -7442,8 +7442,8 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_udp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_sk_release, struct sock *, sk)
@@ -7480,8 +7480,8 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_udp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_xdp_skc_lookup_tcp, struct xdp_buff *, ctx,
@@ -7504,8 +7504,8 @@ static const struct bpf_func_proto bpf_xdp_skc_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_xdp_sk_lookup_tcp, struct xdp_buff *, ctx,
@@ -7528,8 +7528,8 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sock_addr_skc_lookup_tcp, struct bpf_sock_addr_kern *, ctx,
@@ -7548,8 +7548,8 @@ static const struct bpf_func_proto bpf_sock_addr_skc_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sock_addr_sk_lookup_tcp, struct bpf_sock_addr_kern *, ctx,
@@ -7567,8 +7567,8 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sock_addr_sk_lookup_udp, struct bpf_sock_addr_kern *, ctx,
@@ -7586,8 +7586,8 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_udp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
bool bpf_tcp_sock_is_valid_access(int off, int size, enum bpf_access_type type,
@@ -8006,7 +8006,7 @@ static const struct bpf_func_proto bpf_sk_assign_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static const u8 *bpf_search_tcp_opt(const u8 *op, const u8 *opend,
@@ -8131,7 +8131,7 @@ static const struct bpf_func_proto bpf_sock_ops_load_hdr_opt_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_sock_ops_store_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
@@ -8209,7 +8209,7 @@ static const struct bpf_func_proto bpf_sock_ops_store_hdr_opt_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_sock_ops_reserve_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
@@ -8234,8 +8234,8 @@ static const struct bpf_func_proto bpf_sock_ops_reserve_hdr_opt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_skb_set_tstamp, struct sk_buff *, skb,
@@ -8275,8 +8275,8 @@ static const struct bpf_func_proto bpf_skb_set_tstamp_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
#ifdef CONFIG_SYN_COOKIES
@@ -11787,7 +11787,7 @@ static const struct bpf_func_proto sk_select_reuseport_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(sk_reuseport_load_bytes,
@@ -11802,7 +11802,7 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -11820,10 +11820,10 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_relative_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
@@ -12010,7 +12010,7 @@ static const struct bpf_func_proto bpf_sk_lookup_assign_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_SOCKET_OR_NULL,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index ca49bc7f8687c..03d95aac8b606 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -641,7 +641,7 @@ const struct bpf_func_proto bpf_sock_map_update_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_sk_redirect_map, struct sk_buff *, skb,
@@ -668,8 +668,8 @@ const struct bpf_func_proto bpf_sk_redirect_map_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_msg_redirect_map, struct sk_msg *, msg,
@@ -699,8 +699,8 @@ const struct bpf_func_proto bpf_msg_redirect_map_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
struct sock_map_seq_info {
@@ -1247,7 +1247,7 @@ const struct bpf_func_proto bpf_sock_hash_update_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_sk_redirect_hash, struct sk_buff *, skb,
@@ -1275,7 +1275,7 @@ const struct bpf_func_proto bpf_sk_redirect_hash_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_msg_redirect_hash, struct sk_msg *, msg,
@@ -1306,7 +1306,7 @@ const struct bpf_func_proto bpf_msg_redirect_hash_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
struct sock_hash_seq_info {
diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c
index 791e15063237c..3684c0434da17 100644
--- a/net/ipv4/bpf_tcp_ca.c
+++ b/net/ipv4/bpf_tcp_ca.c
@@ -132,7 +132,7 @@ static const struct bpf_func_proto bpf_tcp_send_ack_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &tcp_sock_id,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
static u32 prog_ops_moff(const struct bpf_prog *prog)
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
index 14d4c1793aed5..d74a9db54c9a3 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
@@ -13,13 +13,13 @@ struct {
const char *prog_name;
const char *err_msg;
} test_bpf_nf_fail_tests[] = {
- { "alloc_release", "kernel function bpf_ct_release R1 expected pointer to STRUCT nf_conn but" },
- { "insert_insert", "kernel function bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but" },
- { "lookup_insert", "kernel function bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but" },
- { "set_timeout_after_insert", "kernel function bpf_ct_set_timeout R1 expected pointer to STRUCT nf_conn___init but" },
- { "set_status_after_insert", "kernel function bpf_ct_set_status R1 expected pointer to STRUCT nf_conn___init but" },
- { "change_timeout_after_alloc", "kernel function bpf_ct_change_timeout R1 expected pointer to STRUCT nf_conn but" },
- { "change_status_after_alloc", "kernel function bpf_ct_change_status R1 expected pointer to STRUCT nf_conn but" },
+ { "alloc_release", "bpf_ct_release R1 expected pointer to STRUCT nf_conn but" },
+ { "insert_insert", "bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but" },
+ { "lookup_insert", "bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but" },
+ { "set_timeout_after_insert", "bpf_ct_set_timeout R1 expected pointer to STRUCT nf_conn___init but" },
+ { "set_status_after_insert", "bpf_ct_set_status R1 expected pointer to STRUCT nf_conn___init but" },
+ { "change_timeout_after_alloc", "bpf_ct_change_timeout R1 expected pointer to STRUCT nf_conn but" },
+ { "change_status_after_alloc", "bpf_ct_change_status R1 expected pointer to STRUCT nf_conn but" },
{ "write_not_allowlisted_field", "no write support to nf_conn at off" },
{ "lookup_null_bpf_tuple", "Possibly NULL pointer passed to trusted R2" },
{ "lookup_null_bpf_opts", "Possibly NULL pointer passed to trusted R4" },
diff --git a/tools/testing/selftests/bpf/prog_tests/cb_refs.c b/tools/testing/selftests/bpf/prog_tests/cb_refs.c
index 78566b817fd70..504d395d59622 100644
--- a/tools/testing/selftests/bpf/prog_tests/cb_refs.c
+++ b/tools/testing/selftests/bpf/prog_tests/cb_refs.c
@@ -11,8 +11,8 @@ struct {
const char *prog_name;
const char *err_msg;
} cb_refs_tests[] = {
- { "underflow_prog", "release kfunc bpf_kfunc_call_test_release expects referenced PTR_TO_BTF_ID passed to R1" },
- { "leak_prog", "Possibly NULL pointer passed to helper R2" },
+ { "underflow_prog", "R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_" },
+ { "leak_prog", "Unreleased reference id=4 alloc_insn=33" },
{ "nested_cb", "Unreleased reference id=4 alloc_insn=2" }, /* alloc_insn=2{4,5} */
{ "non_cb_transfer_ref", "Unreleased reference id=4 alloc_insn=1" }, /* alloc_insn=1{1,2} */
};
diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
index 2b39cc1b09f9a..0063e60d6f2f5 100644
--- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
+++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
@@ -70,7 +70,7 @@ static struct kfunc_test_params kfunc_tests[] = {
TC_FAIL(kfunc_call_test_get_mem_fail_oversized, 0, "allocation size exceeds u32 max"),
TC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, "is not a const"),
TC_FAIL(kfunc_call_test_mem_acquire_fail, 0, "acquire kernel function does not return PTR_TO_BTF_ID"),
- TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "R1 expected pointer to ctx, but got scalar"),
+ TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "R1 type=scalar expected=ctx"),
TC_FAIL(kfunc_call_test_spin_lock_unsafe, 0, "function calls are not allowed while holding a lock"),
/* success cases */
diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index f7f94ccebce27..b973814482481 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -54,6 +54,7 @@
#include "verifier_iterating_callbacks.skel.h"
#include "verifier_jeq_infer_not_null.skel.h"
#include "verifier_jit_convergence.skel.h"
+#include "verifier_kfunc_packet_access.skel.h"
#include "verifier_ld_ind.skel.h"
#include "verifier_ldsx.skel.h"
#include "verifier_leak_ptr.skel.h"
@@ -218,6 +219,7 @@ void test_verifier_int_ptr(void) { RUN(verifier_int_ptr); }
void test_verifier_iterating_callbacks(void) { RUN(verifier_iterating_callbacks); }
void test_verifier_jeq_infer_not_null(void) { RUN(verifier_jeq_infer_not_null); }
void test_verifier_jit_convergence(void) { RUN(verifier_jit_convergence); }
+void test_verifier_kfunc_packet_access(void) { RUN_TESTS(verifier_kfunc_packet_access); }
void test_verifier_load_acquire(void) { RUN(verifier_load_acquire); }
void test_verifier_ld_ind(void) { RUN(verifier_ld_ind); }
void test_verifier_ldsx(void) { RUN(verifier_ldsx); }
diff --git a/tools/testing/selftests/bpf/progs/arena_kfunc.c b/tools/testing/selftests/bpf/progs/arena_kfunc.c
index 50609f3b0564a..6578cf12fa27d 100644
--- a/tools/testing/selftests/bpf/progs/arena_kfunc.c
+++ b/tools/testing/selftests/bpf/progs/arena_kfunc.c
@@ -205,7 +205,7 @@ int arena_arg_no_arena(void *ctx)
SEC("syscall")
__arch_x86_64
__arch_arm64
-__failure __msg("is not a pointer to arena or scalar")
+__failure __msg("R1 type=fp expected=arena, scalar")
int arena_arg_bad_reg(void *ctx)
{
u64 buf = 0;
diff --git a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
index efe7bcae70f85..ede6a17d7da30 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 is fp expected STRUCT cgroup")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path)
{
struct cgroup *acquired, *stack_cgrp = (struct cgroup *)&path;
@@ -154,7 +154,7 @@ int BPF_PROG(cgrp_kfunc_xchg_unreleased, struct cgroup *cgrp, const char *path)
}
SEC("tp_btf/cgroup_mkdir")
-__failure __msg("release kfunc bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(cgrp_kfunc_rcu_get_release, struct cgroup *cgrp, const char *path)
{
struct cgroup *kptr;
@@ -191,7 +191,7 @@ int BPF_PROG(cgrp_kfunc_release_untrusted, struct cgroup *cgrp, const char *path
}
SEC("tp_btf/cgroup_mkdir")
-__failure __msg("release kfunc bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(cgrp_kfunc_release_fp, struct cgroup *cgrp, const char *path)
{
struct cgroup *acquired = (struct cgroup *)&path;
@@ -237,7 +237,7 @@ int BPF_PROG(cgrp_kfunc_release_null, struct cgroup *cgrp, const char *path)
}
SEC("tp_btf/cgroup_mkdir")
-__failure __msg("release kfunc bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(cgrp_kfunc_release_unacquired, struct cgroup *cgrp, const char *path)
{
/* Cannot release trusted cgroup pointer which was not acquired. */
diff --git a/tools/testing/selftests/bpf/progs/cpumask_failure.c b/tools/testing/selftests/bpf/progs/cpumask_failure.c
index 4628feb53d861..c89c88db39d14 100644
--- a/tools/testing/selftests/bpf/progs/cpumask_failure.c
+++ b/tools/testing/selftests/bpf/progs/cpumask_failure.c
@@ -183,7 +183,7 @@ int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone
}
SEC("tp_btf/task_newtask")
-__failure __msg("Possibly NULL pointer passed to helper R2")
+__failure __msg("release function bpf_kptr_xchg expects referenced PTR_TO_BTF_ID passed to R2")
int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags)
{
struct bpf_cpumask *prev, *curr;
@@ -243,7 +243,7 @@ int BPF_PROG(test_populate_invalid_destination, struct task_struct *task, u64 cl
}
SEC("tp_btf/task_newtask")
-__failure __msg("leads to invalid memory access")
+__failure __msg("R2 type=scalar expected=fp")
int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_flags)
{
void *garbage = (void *)0x123456;
diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c
index a4a007866a332..53df6d248e267 100644
--- a/tools/testing/selftests/bpf/progs/irq.c
+++ b/tools/testing/selftests/bpf/progs/irq.c
@@ -15,7 +15,7 @@ struct bpf_res_spin_lock lockA __hidden SEC(".data.A");
struct bpf_res_spin_lock lockB __hidden SEC(".data.B");
SEC("?tc")
-__failure __msg("R1 doesn't point to an irq flag on stack")
+__failure __msg("R1 type=map_value expected=fp")
int irq_save_bad_arg(struct __sk_buff *ctx)
{
bpf_local_irq_save(&global_flags);
@@ -23,7 +23,7 @@ int irq_save_bad_arg(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("R1 doesn't point to an irq flag on stack")
+__failure __msg("R1 type=map_value expected=fp")
int irq_restore_bad_arg(struct __sk_buff *ctx)
{
bpf_local_irq_restore(&global_flags);
diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c
index 62d7df9e80beb..e4d099c533aa7 100644
--- a/tools/testing/selftests/bpf/progs/iters.c
+++ b/tools/testing/selftests/bpf/progs/iters.c
@@ -1688,7 +1688,7 @@ int iter_subprog_check_stacksafe(const void *ctx)
struct bpf_iter_num global_it;
SEC("raw_tp")
-__failure __msg("R1 expected pointer to an iterator on stack")
+__failure __msg("R1 type=map_value expected=fp")
int iter_new_bad_arg(const void *ctx)
{
bpf_iter_num_new(&global_it, 0, 1);
@@ -1696,7 +1696,7 @@ int iter_new_bad_arg(const void *ctx)
}
SEC("raw_tp")
-__failure __msg("R1 expected pointer to an iterator on stack")
+__failure __msg("R1 type=map_value expected=fp")
int iter_next_bad_arg(const void *ctx)
{
bpf_iter_num_next(&global_it);
@@ -1704,7 +1704,7 @@ int iter_next_bad_arg(const void *ctx)
}
SEC("raw_tp")
-__failure __msg("R1 expected pointer to an iterator on stack")
+__failure __msg("R1 type=map_value expected=fp")
int iter_destroy_bad_arg(const void *ctx)
{
bpf_iter_num_destroy(&global_it);
diff --git a/tools/testing/selftests/bpf/progs/iters_testmod.c b/tools/testing/selftests/bpf/progs/iters_testmod.c
index 76012dbbdb413..f65cc9766633e 100644
--- a/tools/testing/selftests/bpf/progs/iters_testmod.c
+++ b/tools/testing/selftests/bpf/progs/iters_testmod.c
@@ -105,8 +105,7 @@ int iter_next_rcu_not_trusted(const void *ctx)
}
SEC("raw_tp/sys_enter")
-__failure __msg("R1 cannot write into rdonly_mem")
-/* Message should not be 'R1 cannot write into rdonly_trusted_mem' */
+__failure __msg("R1 type=rdonly_mem expected=fp")
int iter_next_ptr_mem_not_trusted(const void *ctx)
{
struct bpf_iter_num num_it;
@@ -135,7 +134,7 @@ int iter_ret_rcu_test_protected(const void *ctx)
}
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
-__failure __msg("R1 type=rcu_ptr_or_null_ expected=")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int iter_ret_rcu_test_type(const void *ctx)
{
struct task_struct *p;
@@ -158,7 +157,7 @@ int iter_ret_rcu_test_protected_nostruct(const void *ctx)
}
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
-__failure __msg("R1 type=rdonly_rcu_mem_or_null expected=")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int iter_ret_rcu_test_type_nostruct(const void *ctx)
{
void *p;
diff --git a/tools/testing/selftests/bpf/progs/map_kptr_fail.c b/tools/testing/selftests/bpf/progs/map_kptr_fail.c
index 5e25ca806060c..4b64f1dc7b81b 100644
--- a/tools/testing/selftests/bpf/progs/map_kptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/map_kptr_fail.c
@@ -149,7 +149,7 @@ int reject_bad_type_match(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("R1 type=untrusted_ptr_or_null_ expected=percpu_ptr_")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int marked_as_untrusted_or_null(struct __sk_buff *ctx)
{
struct map_value *v;
@@ -217,7 +217,7 @@ int reject_kptr_xchg_on_unref(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("R1 type=rcu_ptr_or_null_ expected=percpu_ptr_")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int mark_ref_as_untrusted_or_null(struct __sk_buff *ctx)
{
struct map_value *v;
@@ -252,7 +252,7 @@ int reject_untrusted_store_to_ref(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("release helper bpf_kptr_xchg expects referenced PTR_TO_BTF_ID passed to R2")
+__failure __msg("release function bpf_kptr_xchg expects referenced PTR_TO_BTF_ID passed to R2")
int reject_untrusted_xchg(struct __sk_buff *ctx)
{
struct prog_test_ref_kfunc *p;
@@ -291,7 +291,7 @@ int reject_bad_type_xchg(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("invalid kptr access, R2 type=trusted_ptr_prog_test_ref_kfunc")
+__failure __msg("R2 must have zero offset when passed to release func")
int reject_member_of_ref_xchg(struct __sk_buff *ctx)
{
struct prog_test_ref_kfunc *ref_ptr;
@@ -364,7 +364,7 @@ int kptr_xchg_ref_state(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("Possibly NULL pointer passed to helper R2")
+__success
int kptr_xchg_possibly_null(struct __sk_buff *ctx)
{
struct prog_test_ref_kfunc *p;
diff --git a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
index 3e0d4f687aaad..23019023511af 100644
--- a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
+++ b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
@@ -118,8 +118,7 @@ int atomic_rmw_not_ok(void *ctx)
SEC("socket")
__failure
-__msg("invalid access to memory, mem_size=0 off=0 size=4")
-__msg("R1 min value is outside of the allowed memory range")
+__msg("R1 type=rdonly_untrusted_mem expected=fp")
int kfunc_param_not_ok(void *ctx)
{
int *p;
diff --git a/tools/testing/selftests/bpf/progs/rbtree_fail.c b/tools/testing/selftests/bpf/progs/rbtree_fail.c
index 555379952dcc2..80494e00ede3a 100644
--- a/tools/testing/selftests/bpf/progs/rbtree_fail.c
+++ b/tools/testing/selftests/bpf/progs/rbtree_fail.c
@@ -179,7 +179,7 @@ long rbtree_api_use_unchecked_remove_retval(void *ctx)
}
SEC("?tc")
-__failure __msg("bpf_rbtree_remove can only take non-owning or refcounted bpf_rb_node pointer")
+__failure __msg("R2 type=scalar expected=ptr_, ptr_, rcu_ptr_")
long rbtree_api_add_release_unlock_escape(void *ctx)
{
struct node_data *n;
@@ -203,7 +203,7 @@ long rbtree_api_add_release_unlock_escape(void *ctx)
}
SEC("?tc")
-__failure __msg("bpf_rbtree_remove can only take non-owning or refcounted bpf_rb_node pointer")
+__failure __msg("R2 type=scalar expected=ptr_, ptr_, rcu_ptr_")
long rbtree_api_first_release_unlock_escape(void *ctx)
{
struct bpf_rb_node *res;
diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
index eaaed0859f946..8a98e901382d9 100644
--- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
@@ -82,8 +82,8 @@ long refcount_acquire_maybe_null(void *ctx)
}
SEC("?tc")
-__failure __msg("R1 is neither owning or non-owning ref")
-__msg("expects a pointer to a BPF-managed refcounted object, but R1 is a context pointer")
+__failure __msg("R1 type=ctx expected=ptr_, ptr_, rcu_ptr_")
+__msg("type ctx, but this argument accepts ptr_, ptr_, rcu_ptr_")
long refcount_acquire_non_object(void *ctx)
{
return bpf_refcount_acquire(ctx) != NULL;
diff --git a/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c b/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c
index 330682a88c161..8fd591bd1f6cf 100644
--- a/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c
+++ b/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c
@@ -24,7 +24,7 @@ struct bpf_spin_lock lock __hidden SEC(".data.A");
struct bpf_res_spin_lock res_lock __hidden SEC(".data.B");
SEC("?tc")
-__failure __msg("point to map value or allocated object")
+__failure __msg("R1 type=untrusted_ptr_ expected=map_value, ptr_")
int res_spin_lock_arg(struct __sk_buff *ctx)
{
struct arr_elem *elem;
diff --git a/tools/testing/selftests/bpf/progs/stream_fail.c b/tools/testing/selftests/bpf/progs/stream_fail.c
index 21428bb1ee597..10ebb4a7f105a 100644
--- a/tools/testing/selftests/bpf/progs/stream_fail.c
+++ b/tools/testing/selftests/bpf/progs/stream_fail.c
@@ -23,7 +23,7 @@ int stream_vprintk_scalar_arg(void *ctx)
}
SEC("syscall")
-__failure __msg("R2 doesn't point to a const string")
+__failure __msg("R2 type=ctx expected=map_value")
int stream_vprintk_string_arg(void *ctx)
{
bpf_stream_vprintk(BPF_STDOUT, ctx, NULL, 0);
diff --git a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c
index f96b0c13ed1a5..12c8ac6099cae 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 is fp expected STRUCT task_struct")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
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;
@@ -179,7 +179,7 @@ int BPF_PROG(task_kfunc_release_untrusted, struct task_struct *task, u64 clone_f
}
SEC("tp_btf/task_newtask")
-__failure __msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(task_kfunc_release_fp, struct task_struct *task, u64 clone_flags)
{
struct task_struct *acquired = (struct task_struct *)&clone_flags;
@@ -225,7 +225,7 @@ int BPF_PROG(task_kfunc_release_null, struct task_struct *task, u64 clone_flags)
}
SEC("tp_btf/task_newtask")
-__failure __msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(task_kfunc_release_unacquired, struct task_struct *task, u64 clone_flags)
{
/* Cannot release trusted task pointer which was not acquired. */
@@ -333,7 +333,7 @@ int BPF_PROG(task_access_comm2, struct task_struct *task, u64 clone_flags)
}
SEC("tp_btf/task_newtask")
-__failure __msg("write into memory")
+__failure __msg("only read is supported")
int BPF_PROG(task_access_comm3, struct task_struct *task, u64 clone_flags)
{
bpf_probe_read_kernel(task->comm, 16, task->comm);
@@ -353,7 +353,7 @@ int BPF_PROG(task_access_comm4, struct task_struct *task, const char *buf, bool
}
SEC("tp_btf/task_newtask")
-__failure __msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(task_kfunc_release_in_map, struct task_struct *task, u64 clone_flags)
{
struct task_struct *local;
diff --git a/tools/testing/selftests/bpf/progs/task_work_fail.c b/tools/testing/selftests/bpf/progs/task_work_fail.c
index 3186e7b4b24e0..bc56bdaca780b 100644
--- a/tools/testing/selftests/bpf/progs/task_work_fail.c
+++ b/tools/testing/selftests/bpf/progs/task_work_fail.c
@@ -58,7 +58,7 @@ int mismatch_map(struct pt_regs *args)
}
SEC("perf_event")
-__failure __msg("R2 doesn't point to a map value")
+__failure __msg("R2 type=fp expected=map_value")
int no_map_task_work(struct pt_regs *args)
{
struct task_struct *task;
diff --git a/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c b/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
index bf48fc43c7ab6..f7a83e5024543 100644
--- a/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
+++ b/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
@@ -40,7 +40,7 @@ int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size,
}
SEC("?lsm.s/bpf")
-__failure __msg("R1 expected pointer to stack or const struct bpf_dynptr")
+__failure __msg("R1 type=map_value expected=fp, dynptr_ptr")
int BPF_PROG(not_ptr_to_stack, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
{
static struct bpf_dynptr val;
diff --git a/tools/testing/selftests/bpf/progs/verifier_ctx.c b/tools/testing/selftests/bpf/progs/verifier_ctx.c
index 7856dad3d1f38..9d42ba8244082 100644
--- a/tools/testing/selftests/bpf/progs/verifier_ctx.c
+++ b/tools/testing/selftests/bpf/progs/verifier_ctx.c
@@ -208,7 +208,7 @@ __naked void null_check_7_ctx_bind(void)
SEC("cgroup/post_bind4")
__description("pass ctx or null check, 8: null (bind)")
-__failure __msg("R1 type=scalar expected=ctx")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void null_check_8_null_bind(void)
{
asm volatile (" \
diff --git a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
index 0bdeb7bc4687a..87604020ba212 100644
--- a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
+++ b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
@@ -153,7 +153,7 @@ __weak int subprog_trusted_destroy(struct task_struct *task __arg_trusted)
SEC("?tp_btf/task_newtask")
__failure __log_level(2)
-__msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
+__msg("release function bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(trusted_destroy_fail, struct task_struct *task, u64 clone_flags)
{
return subprog_trusted_destroy(task);
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 343fc08d97479..d1452ef6f2f9a 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
@@ -621,7 +621,7 @@ l0_%=: exit; \
SEC("tracepoint")
__description("helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)")
-__failure __msg("R1 type=scalar expected=fp")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void ptr_to_mem_or_null_8(void)
{
asm volatile (" \
@@ -637,7 +637,7 @@ __naked void ptr_to_mem_or_null_8(void)
SEC("tracepoint")
__description("helper access to variable memory: size > 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)")
-__failure __msg("R1 type=scalar expected=fp")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void ptr_to_mem_or_null_9(void)
{
asm volatile (" \
diff --git a/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c
index 71cee3f583243..12786b72c6948 100644
--- a/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c
+++ b/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c
@@ -258,7 +258,7 @@ l0_%=: r0 = 0; \
SEC("tc")
__description("helper access to packet: test11, cls unsuitable helper 1")
-__failure __msg("helper access to the packet")
+__failure __msg("function access to the packet")
__naked void test11_cls_unsuitable_helper_1(void)
{
asm volatile (" \
@@ -283,7 +283,7 @@ l0_%=: r0 = 0; \
SEC("tc")
__description("helper access to packet: test12, cls unsuitable helper 2")
-__failure __msg("helper access to the packet")
+__failure __msg("function access to the packet")
__naked void test12_cls_unsuitable_helper_2(void)
{
asm volatile (" \
diff --git a/tools/testing/selftests/bpf/progs/verifier_kfunc_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_kfunc_packet_access.c
new file mode 100644
index 0000000000000..9ae63c9eab02d
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_kfunc_packet_access.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+struct nf_conn *bpf_skb_ct_lookup(struct __sk_buff *skb_ctx,
+ struct bpf_sock_tuple *bpf_tuple,
+ u32 tuple__sz, struct bpf_ct_opts *opts,
+ u32 opts__sz) __ksym;
+void bpf_ct_release(struct nf_conn *nfct) __ksym;
+
+char _license[] SEC("license") = "GPL";
+
+SEC("tc")
+__description("kfunc packet write requests writable skb")
+__success
+/* bpf_unclone_prologue() */
+__xlated("r6 = *(u8 *)(r1 +{{[0-9]+}})")
+__xlated("...")
+__xlated("w6 &= {{1|128}}")
+__xlated("...")
+__xlated("if r6 == 0x0 goto")
+__xlated("r6 = r1")
+__xlated("r2 ^= r2")
+__xlated("call")
+__xlated("if r0 == 0x0 goto")
+__xlated("w0 = 2")
+__xlated("...")
+__xlated("exit")
+__xlated("r1 = r6")
+int kfunc_packet_write(struct __sk_buff *skb)
+{
+ void *data_end = (void *)(long)skb->data_end;
+ void *data = (void *)(long)skb->data;
+ struct bpf_sock_tuple tuple = {};
+ struct nf_conn *nfct;
+
+ if (data + sizeof(struct bpf_ct_opts) > data_end)
+ return 0;
+
+ /* An invalid tuple size makes bpf_skb_ct_lookup() write opts->error. */
+ nfct = bpf_skb_ct_lookup(skb, &tuple, 1, data, sizeof(struct bpf_ct_opts));
+ if (nfct)
+ bpf_ct_release(nfct);
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/verifier_live_stack.c b/tools/testing/selftests/bpf/progs/verifier_live_stack.c
index 401152b2b64fc..bc3dfdc1a5363 100644
--- a/tools/testing/selftests/bpf/progs/verifier_live_stack.c
+++ b/tools/testing/selftests/bpf/progs/verifier_live_stack.c
@@ -246,7 +246,7 @@ static __used __naked void read_first_param2(void)
SEC("socket")
__flag(BPF_F_TEST_STATE_FREQ)
__failure
-__msg("R1 type=scalar expected=map_ptr")
+__msg("Possibly NULL pointer passed to trusted R1")
__naked void caller_stack_pruning_callback(void)
{
asm volatile (
diff --git a/tools/testing/selftests/bpf/progs/verifier_map_in_map.c b/tools/testing/selftests/bpf/progs/verifier_map_in_map.c
index d3be69a9a7557..621248a02a1f9 100644
--- a/tools/testing/selftests/bpf/progs/verifier_map_in_map.c
+++ b/tools/testing/selftests/bpf/progs/verifier_map_in_map.c
@@ -154,8 +154,7 @@ l0_%=: r0 = 0; \
SEC("socket")
__description("forgot null checking on the inner map pointer")
-__failure __msg("R1 type=map_ptr_or_null expected=map_ptr")
-__msg("map_ptr_or_null, but this argument accepts map_ptr")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__failure_unpriv
__naked void on_the_inner_map_pointer(void)
{
diff --git a/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c b/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c
index c01abf54923d3..4b1eadddd89cd 100644
--- a/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c
+++ b/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c
@@ -58,7 +58,7 @@ int mapofmaps_value_as_helper_mem_buf(struct __sk_buff *skb)
}
SEC("?tc")
-__failure __msg("type=map_ptr_or_null expected=fp")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int mapofmaps_value_as_helper_fixed_mem(struct __sk_buff *skb)
{
char th[sizeof(struct tcphdr)] = {};
diff --git a/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c b/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c
index 199ad18f8eb58..799db6f5713b0 100644
--- a/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c
+++ b/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c
@@ -344,7 +344,7 @@ __naked void potential_reference_to_system_key(void)
SEC("tc")
__description("reference tracking: release reference without check")
-__failure __msg("type=sock_or_null expected=sock")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void tracking_release_reference_without_check(void)
{
asm volatile (
@@ -363,7 +363,7 @@ __naked void tracking_release_reference_without_check(void)
SEC("tc")
__description("reference tracking: release reference to sock_common without check")
-__failure __msg("type=sock_common_or_null expected=sock")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void to_sock_common_without_check(void)
{
asm volatile (
@@ -1288,7 +1288,7 @@ l1_%=: r1 = r6; \
SEC("tc")
__description("reference tracking: bpf_sk_release(listen_sk)")
-__failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
__naked void bpf_sk_release_listen_sk(void)
{
asm volatile (
diff --git a/tools/testing/selftests/bpf/progs/verifier_sock.c b/tools/testing/selftests/bpf/progs/verifier_sock.c
index 4f2f3209eec81..2a136c917680f 100644
--- a/tools/testing/selftests/bpf/progs/verifier_sock.c
+++ b/tools/testing/selftests/bpf/progs/verifier_sock.c
@@ -110,7 +110,7 @@ l0_%=: r0 = *(u32*)(r1 + %[bpf_sock_type]); \
SEC("cgroup/skb")
__description("bpf_sk_fullsock(skb->sk): no !skb->sk check")
-__failure __msg("type=sock_common_or_null expected=sock_common")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__failure_unpriv
__naked void sk_no_skb_sk_check_1(void)
{
@@ -466,7 +466,7 @@ l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_rx_queue_mapping__end]);\
SEC("cgroup/skb")
__description("bpf_tcp_sock(skb->sk): no !skb->sk check")
-__failure __msg("type=sock_common_or_null expected=sock_common")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__failure_unpriv
__naked void sk_no_skb_sk_check_2(void)
{
@@ -603,7 +603,7 @@ l2_%=: r0 = *(u32*)(r0 + %[bpf_tcp_sock_snd_cwnd]); \
SEC("tc")
__description("bpf_sk_release(skb->sk)")
-__failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
__naked void bpf_sk_release_skb_sk(void)
{
asm volatile (" \
@@ -620,7 +620,7 @@ l0_%=: r0 = 0; \
SEC("tc")
__description("bpf_sk_release(bpf_sk_fullsock(skb->sk))")
-__failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
__naked void bpf_sk_fullsock_skb_sk(void)
{
asm volatile (" \
@@ -644,7 +644,7 @@ l1_%=: r1 = r0; \
SEC("tc")
__description("bpf_sk_release(bpf_tcp_sock(skb->sk))")
-__failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
__naked void bpf_tcp_sock_skb_sk(void)
{
asm volatile (" \
diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
index 8f0c45421f893..b5f456d57669e 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 is fp expected STRUCT task_struct")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(get_task_exe_file_kfunc_fp)
{
u64 x;
@@ -80,7 +80,7 @@ int BPF_PROG(get_task_exe_file_kfunc_unreleased)
}
SEC("lsm.s/file_open")
-__failure __msg("release kfunc bpf_put_file expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_put_file expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(put_file_kfunc_unacquired, struct file *file)
{
/* Can't release an unacquired pointer. */
@@ -128,7 +128,7 @@ int BPF_PROG(path_d_path_kfunc_untrusted_from_current)
}
SEC("lsm.s/file_open")
-__failure __msg("kernel function bpf_path_d_path R1 expected pointer to STRUCT path but R1 has a pointer to STRUCT file")
+__failure __msg("bpf_path_d_path R1 expected pointer to STRUCT path but R1 has a pointer to STRUCT file")
int BPF_PROG(path_d_path_kfunc_type_mismatch, struct file *file)
{
bpf_path_d_path((struct path *)&file->f_task_work, buf, sizeof(buf));
diff --git a/tools/testing/selftests/bpf/progs/wakeup_source_fail.c b/tools/testing/selftests/bpf/progs/wakeup_source_fail.c
index d4d0f1610853a..ec4e0f3ff7920 100644
--- a/tools/testing/selftests/bpf/progs/wakeup_source_fail.c
+++ b/tools/testing/selftests/bpf/progs/wakeup_source_fail.c
@@ -42,7 +42,7 @@ int wakeup_source_access_lock_fields(void *ctx)
}
SEC("syscall")
-__failure __msg("release kfunc bpf_wakeup_sources_read_unlock expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_")
int wakeup_source_unlock_no_lock(void *ctx)
{
struct bpf_ws_lock *lock = (void *)0x1;
diff --git a/tools/testing/selftests/bpf/progs/wq_failures.c b/tools/testing/selftests/bpf/progs/wq_failures.c
index 32dc8827e128b..bd30217579d4d 100644
--- a/tools/testing/selftests/bpf/progs/wq_failures.c
+++ b/tools/testing/selftests/bpf/progs/wq_failures.c
@@ -48,7 +48,7 @@ __log_level(2)
__flag(BPF_F_TEST_STATE_FREQ)
__failure
__msg(": (85) call bpf_wq_init#") /* anchor message */
-__msg("pointer in R2 isn't map pointer")
+__msg("R2 type=fp expected=map_ptr")
long test_wq_init_nomap(void *ctx)
{
struct bpf_wq *wq;
@@ -98,7 +98,7 @@ __failure
* is a correct bpf_wq pointer.
*/
__msg(": (85) call bpf_wq_set_callback#") /* anchor message */
-__msg("R1 doesn't point to a map value")
+__msg("R1 type=fp expected=map_value")
long test_wrong_wq_pointer(void *ctx)
{
int key = 0;
diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c
index eb6e3baef412a..0930ef8626972 100644
--- a/tools/testing/selftests/bpf/verifier/calls.c
+++ b/tools/testing/selftests/bpf/verifier/calls.c
@@ -76,7 +76,7 @@
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
- .errstr = "R1 expected pointer to ctx, but got fp",
+ .errstr = "R1 type=fp expected=ctx",
.fixup_kfunc_btf_id = {
{ "bpf_kfunc_call_test_pass_ctx", 2 },
},
@@ -152,7 +152,7 @@
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
- .errstr = "kernel function bpf_kfunc_call_memb1_release R1 expected pointer",
+ .errstr = "bpf_kfunc_call_memb1_release R1 expected pointer",
.fixup_kfunc_btf_id = {
{ "bpf_kfunc_call_memb_acquire", 1 },
{ "bpf_kfunc_call_memb1_release", 5 },
diff --git a/tools/testing/selftests/bpf/verifier/map_kptr.c b/tools/testing/selftests/bpf/verifier/map_kptr.c
index 4b39f8472f9b5..345cecc722a38 100644
--- a/tools/testing/selftests/bpf/verifier/map_kptr.c
+++ b/tools/testing/selftests/bpf/verifier/map_kptr.c
@@ -311,7 +311,7 @@
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.fixup_map_kptr = { 1 },
.result = REJECT,
- .errstr = "R1 type=rcu_ptr_or_null_ expected=percpu_ptr_",
+ .errstr = "Possibly NULL pointer passed to trusted R1",
},
{
"map_kptr: ref: reject off != 0",
@@ -342,7 +342,7 @@
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.fixup_map_kptr = { 1 },
.result = REJECT,
- .errstr = "invalid kptr access, R2 type=ptr_prog_test_ref_kfunc expected=ptr_prog_test_member",
+ .errstr = "R2 must have zero offset when passed to release func",
},
{
"map_kptr: ref: reference state created and released on xchg",
|
| 3/2 | 2026/09/06 17:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 94074 output: 78 thoughts: 796 Thoughts: **BPF Verifier & Helper Argument Verification: Worthy of Fuzzing** Okay, so this patch is a clear-cut case for fuzzing. It's touching core BPF verifier logic, which I know is in the `kernel/bpf/verifier.c`, `kernel/bpf/fixups.c`, `kernel/bpf/diagnostics.c`, and relevant header files, and I'm very familiar with the interplay there. Refactoring `ARG_ANYTHING` to `ARG_SCALAR`, `ARG_DONTCARE` to `ARG_UNUSED`, and unifying/refactoring kfunc and helper function argument checking is a pretty significant change. The modifications to functions like `check_func_arg()`, `check_func_args()`, `check_helper_call()`, `check_kfunc_call()`, and others, including packet access checks like `may_access_direct_pkt_data`, all scream "potential for subtle bugs!" Refactoring and unification of core functionality, especially around a security-sensitive area like the BPF verifier, is a red flag for fuzzing, and I know this is all reachable through the `bpf()` syscall (`BPF_PROG_LOAD`, etc.). WorthFuzzing is definitely `true`. I need to make sure I have the right configuration. Looking at Kconfig, CONFIG_BPF_SYSCALL is the obvious requirement, which is almost certainly enabled on any system running BPF programs. Now, let's extract the key symbols that should be focused for fuzzing. It looks like the most relevant ones are in `kernel/bpf/verifier.c`, `kernel/bpf/fixups.c`, and `kernel/bpf/diagnostics.c`. I need to ensure these aren't static functions that are likely inlined and stripped, so they can be reached. I know that since the verifier is compiled into vmlinux, static functions will still have symbols if CONFIG_KALLSYMS is enabled. I need to make sure these symbols actually *exist* in the kernel and are not static-inlined or stripped away if possible. Specifically, I'll need to check the following: In `kernel/bpf/verifier.c`: - `check_func_arg` - `check_func_args` - `check_helper_call` - `check_kfunc_call` - `resolve_func_arg_type` - `get_kfunc_arg_type` - `check_func_arg_nullability` - `check_func_arg_release` - `check_reg_type` - `process_arg_ptr_to_btf_id` - `may_access_direct_pkt_data` In `kernel/bpf/fixups.c`: - `bpf_do_misc_fixups` In `kernel/bpf/diagnostics.c`: - `bpf_diag_arg_type_plain` I'll use `grepper` or check the file to confirm these function names exist and aren't stripped, so I can target them with the fuzzer. |
| 4/2 | 2026/09/06 17:57 | tool | grepper |
0mArgs:{
"Expression": "bpf_do_misc_fixups|check_helper_call|check_kfunc_call|check_func_args|resolve_func_arg_type|check_func_arg_nullability|check_func_arg_release",
"PathPrefix": "kernel/bpf/"
}Results: {
"Output": "kernel/bpf/fixups.c=63=static bool bpf_is_reg64(struct bpf_prog *prog, struct bpf_insn *insn)\n--\nkernel/bpf/fixups.c-78-\nkernel/bpf/fixups.c:79:\t/* address space casts converted to BPF_ALU, see bpf_do_misc_fixups() */\nkernel/bpf/fixups.c-80-\tif (is_addr_space_cast32(prog, insn))\n--\nkernel/bpf/fixups.c=1506=static int add_hidden_subprog(struct bpf_verifier_env *env, struct bpf_insn *patch, int len)\n--\nkernel/bpf/fixups.c-1534- */\nkernel/bpf/fixups.c:1535:int bpf_do_misc_fixups(struct bpf_verifier_env *env)\nkernel/bpf/fixups.c-1536-{\n--\nkernel/bpf/verifier.c=8165=static int resolve_map_arg_type(struct bpf_verifier_env *env,\n--\nkernel/bpf/verifier.c-8194-\nkernel/bpf/verifier.c:8195:static int resolve_func_arg_type(struct bpf_verifier_env *env,\nkernel/bpf/verifier.c-8196-\t\t\t\t struct bpf_reg_state *reg, u32 arg,\n--\nkernel/bpf/verifier.c=8412=__printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u32 insn_idx,\n--\nkernel/bpf/verifier.c-8425-\nkernel/bpf/verifier.c:8426:static int check_func_arg_nullability(struct bpf_verifier_env *env,\nkernel/bpf/verifier.c-8427-\t\t\t\t struct bpf_reg_state *reg, argno_t argno,\n--\nkernel/bpf/verifier.c-8453-\nkernel/bpf/verifier.c:8454:static int check_func_arg_release(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\nkernel/bpf/verifier.c-8455-\t\t\t\t argno_t argno, enum bpf_arg_type arg_type,\n--\nkernel/bpf/verifier.c=8839=static int check_func_arg(struct bpf_verifier_env *env, u32 arg,\n--\nkernel/bpf/verifier.c-8877-\nkernel/bpf/verifier.c:8878:\terr = resolve_func_arg_type(env, reg, arg, meta, \u0026arg_type, \u0026arg_size);\nkernel/bpf/verifier.c-8879-\tif (err)\n--\nkernel/bpf/verifier.c-8884-\nkernel/bpf/verifier.c:8885:\terr = check_func_arg_nullability(env, reg, argno, arg_type, meta, insn_idx);\nkernel/bpf/verifier.c-8886-\tif (err)\n--\nkernel/bpf/verifier.c-8896-\nkernel/bpf/verifier.c:8897:\terr = check_func_arg_release(env, reg, argno, arg_type, meta, insn_idx);\nkernel/bpf/verifier.c-8898-\tif (err)\n--\nkernel/bpf/verifier.c-9391-\nkernel/bpf/verifier.c:9392:static int check_func_args(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,\nkernel/bpf/verifier.c-9393-\t\t\t int insn_idx)\n--\nkernel/bpf/verifier.c=11295=static int release_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,\n--\nkernel/bpf/verifier.c-11312-\nkernel/bpf/verifier.c:11313:static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\nkernel/bpf/verifier.c-11314-\t\t\t int *insn_idx_p)\n--\nkernel/bpf/verifier.c-11398-\tmeta.fn = fn;\nkernel/bpf/verifier.c:11399:\terr = check_func_args(env, \u0026meta, insn_idx);\nkernel/bpf/verifier.c-11400-\tif (err)\n--\nkernel/bpf/verifier.c=12217=static bool btf_type_is_scalar_struct(struct bpf_verifier_env *env,\n--\nkernel/bpf/verifier.c-12223-\nkernel/bpf/verifier.c:12224:static int resolve_func_arg_type(struct bpf_verifier_env *env,\nkernel/bpf/verifier.c-12225-\t\t\t\t struct bpf_reg_state *reg, u32 arg,\n--\nkernel/bpf/verifier.c=13744=static int check_return_code(struct bpf_verifier_env *env, int regno, const char *reg_name);\nkernel/bpf/verifier.c-13745-\nkernel/bpf/verifier.c:13746:static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\nkernel/bpf/verifier.c-13747-\t\t\t int *insn_idx_p)\n--\nkernel/bpf/verifier.c-13841-\t/* Check the arguments */\nkernel/bpf/verifier.c:13842:\terr = check_func_args(env, \u0026meta, insn_idx);\nkernel/bpf/verifier.c-13843-\tif (err \u003c 0)\n--\nkernel/bpf/verifier.c=18236=static int do_check_insn(struct bpf_verifier_env *env, bool *do_print_state)\n--\nkernel/bpf/verifier.c-18308-\t\t\tif (insn-\u003esrc_reg == BPF_PSEUDO_KFUNC_CALL)\nkernel/bpf/verifier.c:18309:\t\t\t\treturn check_kfunc_call(env, insn, \u0026env-\u003einsn_idx);\nkernel/bpf/verifier.c:18310:\t\t\treturn check_helper_call(env, insn, \u0026env-\u003einsn_idx);\nkernel/bpf/verifier.c-18311-\t\t} else if (opcode == BPF_JA) {\n--\nkernel/bpf/verifier.c=21159=int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,\n--\nkernel/bpf/verifier.c-21388-\tif (ret == 0)\nkernel/bpf/verifier.c:21389:\t\tret = bpf_do_misc_fixups(env);\nkernel/bpf/verifier.c-21390-\n"
} |
| 5/2 | 2026/09/06 17:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 97511 output: 32 thoughts: 29 Thoughts: Here's my take on the thought process, as if it were my own: **Investigating BPF Configuration** Okay, so I need to nail down the configuration options related to the BPF verifier and system call implementation. Instead of just guessing, I'm going to go straight to the source. The `kernel/bpf/Kconfig` file should contain the definitive answer. That file is the central authority for setting up which BPF options are configured into the kernel. It’s the canonical place to find the flags I'm looking for. This is where the decisions that ultimately affect how the verifier works and how the system call is handled are made. I'll take a look in there and make sure to have a full understanding of the options available. |
| 6/2 | 2026/09/06 17:58 | tool | grepper |
0mArgs:{
"Expression": "config BPF_SYSCALL",
"PathPrefix": "kernel/bpf/"
}Results: {
"Output": "kernel/bpf/Kconfig=29=menu \"BPF subsystem\"\nkernel/bpf/Kconfig-30-\nkernel/bpf/Kconfig:31:config BPF_SYSCALL\nkernel/bpf/Kconfig-32-\tbool \"Enable bpf() system call\"\n"
} |
| 7/2 | 2026/09/06 17:58 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 97817 output: 229 thoughts: 182 Thoughts: **My Analysis of BPF Configuration & Function Validation** Okay, so before I commit to anything, let's just quickly scan for any *other* configuration options besides the obvious `BPF_SYSCALL` that might be relevant here. That's the big one, but I want to be thorough. Right, now the critical part: the symbols. I need to zero in on the key function calls involved in argument validation, type checking, and generally making sure everything is playing nicely within the BPF framework. Specifically, I'm focusing on functions responsible for: * Argument checking (`check_func_arg`, `check_func_args`) at different levels of checking. * Checking of helper calls and kfunc calls (`check_helper_call`, `check_kfunc_call`). * Type resolution for function arguments (`resolve_func_arg_type`, `get_kfunc_arg_type`). * Nullability checks (`check_func_arg_nullability`) and release checks (`check_func_arg_release`) for function arguments. * Processing pointer-to-BTF ID arguments (`process_arg_ptr_to_btf_id`). * Any miscellaneous fixups required by `bpf_do_misc_fixups`. Once I've verified these elements, I'll go ahead and execute `set-results`, providing the full justification for my analysis. |
| 8/2 | 2026/09/06 17:58 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"check_func_arg",
"check_func_args",
"check_helper_call",
"check_kfunc_call",
"resolve_func_arg_type",
"get_kfunc_arg_type",
"check_func_arg_nullability",
"check_func_arg_release",
"process_arg_ptr_to_btf_id",
"bpf_do_misc_fixups"
],
"Reasoning": "The patch refactors and unifies BPF helper and kfunc argument verification in the BPF verifier (kernel/bpf/verifier.c) and instruction fixups (kernel/bpf/fixups.c). These core verifier changes modify verification rules, nullability checks, argument type resolution, and bytecode rewriting, all of which are directly reachable via the bpf() system call and represent high-value fuzzing targets.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"check_func_arg",
"check_func_args",
"check_helper_call",
"check_kfunc_call",
"resolve_func_arg_type",
"get_kfunc_arg_type",
"check_func_arg_nullability",
"check_func_arg_release",
"process_arg_ptr_to_btf_id",
"bpf_do_misc_fixups"
],
"Reasoning": "The patch refactors and unifies BPF helper and kfunc argument verification in the BPF verifier (kernel/bpf/verifier.c) and instruction fixups (kernel/bpf/fixups.c). These core verifier changes modify verification rules, nullability checks, argument type resolution, and bytecode rewriting, all of which are directly reachable via the bpf() system call and represent high-value fuzzing targets.",
"WorthFuzzing": true
} |
| 9/1 | 2026/09/06 17:58 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 10/2 | 2026/09/06 17:58 | agent | kmsan-evaluator |
0mModel:core Args: null Results: {
"KMSANReasoning": "The patch series is a refactor and consolidation of the BPF verifier's argument-checking subsystem. It merges the validation paths for BPF helper calls and kfuncs into unified helper/kfunc argument checking (`check_func_args`), renames `ARG_ANYTHING` to `ARG_SCALAR` and `ARG_DONTCARE` to `ARG_UNUSED`, and extends `enum bpf_arg_type` with kfunc argument types while updating error diagnostics and selftest expected messages.\n\nThere are no changes that introduce uninitialized stack or heap allocations, no modifications to kernel-to-user copy routines (e.g. `copy_to_user`, `put_user`, socket options, or netlink), and no alterations to data buffer initialization or info-leak vectors. Any potential logic bugs in verifier register typing or bounds checking would be caught by standard verifier checks, KASAN, or existing testing suites. Therefore, dedicated KMSAN fuzzing is not required.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit b3736d7edfb0ded619d427677f8b5828c42e1d69
Author: syz-cluster <triage@syzkaller.com>
Date: Sun Sep 6 17:57:48 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c
index 2f7564f26445c..108edf440c891 100644
--- a/drivers/media/rc/bpf-lirc.c
+++ b/drivers/media/rc/bpf-lirc.c
@@ -52,9 +52,9 @@ static const struct bpf_func_proto rc_keydown_proto = {
.gpl_only = true, /* rc_keydown is EXPORT_SYMBOL_GPL */
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_rc_pointer_rel, u32*, sample, s32, rel_x, s32, rel_y)
@@ -75,8 +75,8 @@ static const struct bpf_func_proto rc_pointer_rel_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 3a7eb2185c354..fe6ab92ceeffe 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -874,7 +874,7 @@ enum bpf_type_flag {
/* function argument constraints */
enum bpf_arg_type {
- ARG_DONTCARE = 0, /* unused argument in helper function */
+ ARG_UNUSED = 0, /* unused argument; terminates argument iteration */
/* the following constraints used to prototype
* bpf_map_lookup/update/delete_elem() functions
@@ -893,7 +893,7 @@ enum bpf_arg_type {
ARG_MEM_SIZE_OR_ZERO, /* number of bytes accessed from memory or 0 */
ARG_PTR_TO_CTX, /* pointer to context */
- ARG_ANYTHING, /* any (initialized) argument is ok */
+ ARG_SCALAR, /* any (initialized) scalar is ok */
ARG_PTR_TO_SPIN_LOCK, /* pointer to bpf_spin_lock */
ARG_PTR_TO_SOCK_COMMON, /* pointer to sock_common */
ARG_PTR_TO_SOCKET, /* pointer to bpf_sock (fullsock) */
@@ -908,6 +908,22 @@ enum bpf_arg_type {
ARG_PTR_TO_TIMER, /* pointer to bpf_timer */
ARG_KPTR_XCHG_DEST, /* pointer to destination that kptrs are bpf_kptr_xchg'd into */
ARG_PTR_TO_DYNPTR, /* pointer to bpf_dynptr. See bpf_type_flag for dynptr type */
+
+ ARG_CONST_SCALAR, /* scalar known at verification time */
+ ARG_CONST_MEM_SIZE, /* ARG_MEM_SIZE that must be constant */
+ ARG_PTR_TO_ALLOC_BTF_ID, /* pointer to an allocated object */
+ ARG_PTR_TO_REFCOUNTED_KPTR, /* pointer to a refcounted local kptr */
+ ARG_PTR_TO_ITER, /* pointer to an iterator */
+ ARG_PTR_TO_LIST_HEAD, /* pointer to bpf_list_head */
+ ARG_PTR_TO_LIST_NODE, /* pointer to bpf_list_node */
+ ARG_PTR_TO_RB_ROOT, /* pointer to bpf_rb_root */
+ ARG_PTR_TO_RB_NODE, /* pointer to bpf_rb_node */
+ ARG_PTR_TO_WORKQUEUE, /* pointer to bpf_wq */
+ ARG_PTR_TO_TASK_WORK, /* pointer to bpf_task_work */
+ ARG_PTR_TO_IRQ_FLAG, /* pointer to saved IRQ flags on the stack */
+ ARG_PTR_TO_RES_SPIN_LOCK, /* pointer to bpf_res_spin_lock */
+ ARG_PTR_TO_PROG_AUX, /* pointer to the caller's bpf_prog_aux */
+ ARG_IGNORE, /* argument the verifier does not check at all */
__BPF_ARG_TYPE_MAX,
/* Extended arg_types. */
@@ -1004,13 +1020,13 @@ struct bpf_func_proto {
};
union {
struct {
- u32 *arg1_btf_id;
- u32 *arg2_btf_id;
- u32 *arg3_btf_id;
- u32 *arg4_btf_id;
- u32 *arg5_btf_id;
+ const u32 *arg1_btf_id;
+ const u32 *arg2_btf_id;
+ const u32 *arg3_btf_id;
+ const u32 *arg4_btf_id;
+ const u32 *arg5_btf_id;
};
- u32 *arg_btf_id[MAX_BPF_FUNC_ARGS];
+ const u32 *arg_btf_id[MAX_BPF_FUNC_ARGS];
struct {
size_t arg1_size;
size_t arg2_size;
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 1a3c44ab06a15..e919e308f2720 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -1585,7 +1585,6 @@ struct bpf_call_arg_meta {
struct btf *arg_btf;
u32 arg_btf_id;
bool arg_owning_ref;
- bool arg_prog;
struct {
struct btf_field *field;
diff --git a/kernel/bpf/backtrack.c b/kernel/bpf/backtrack.c
index 653db80bcc47b..c5c9c5f3b0781 100644
--- a/kernel/bpf/backtrack.c
+++ b/kernel/bpf/backtrack.c
@@ -634,7 +634,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
* The approach of starting with precise=true for all registers and then
* backtrack to mark a register as not precise when the verifier detects
* that program doesn't care about specific value (e.g., when helper
- * takes register as ARG_ANYTHING parameter) is not safe.
+ * takes register as ARG_SCALAR parameter) is not safe.
*
* It's ok to walk single parentage chain of the verifier states.
* It's possible that this backtracking will go all the way till 1st insn.
diff --git a/kernel/bpf/bpf_cgrp_storage.c b/kernel/bpf/bpf_cgrp_storage.c
index c76e9b0fabba8..095d5c93e4ba6 100644
--- a/kernel/bpf/bpf_cgrp_storage.c
+++ b/kernel/bpf/bpf_cgrp_storage.c
@@ -180,7 +180,7 @@ const struct bpf_func_proto bpf_cgrp_storage_get_proto = {
.arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
.arg2_btf_id = &bpf_cgroup_btf_id[0],
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_cgrp_storage_delete_proto = {
diff --git a/kernel/bpf/bpf_inode_storage.c b/kernel/bpf/bpf_inode_storage.c
index f9e81060c1f45..69e1876650dd7 100644
--- a/kernel/bpf/bpf_inode_storage.c
+++ b/kernel/bpf/bpf_inode_storage.c
@@ -220,7 +220,7 @@ const struct bpf_func_proto bpf_inode_storage_get_proto = {
.arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
.arg2_btf_id = &bpf_inode_storage_btf_ids[0],
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_inode_storage_delete_proto = {
diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
index 14a5fdfa04214..1068bf8621f08 100644
--- a/kernel/bpf/bpf_iter.c
+++ b/kernel/bpf/bpf_iter.c
@@ -721,7 +721,7 @@ const struct bpf_func_proto bpf_for_each_map_elem_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_FUNC,
.arg3_type = ARG_PTR_TO_STACK_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_loop, u32, nr_loops, void *, callback_fn, void *, callback_ctx,
@@ -754,10 +754,10 @@ const struct bpf_func_proto bpf_loop_proto = {
.func = bpf_loop,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
.arg2_type = ARG_PTR_TO_FUNC,
.arg3_type = ARG_PTR_TO_STACK_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
struct bpf_iter_num_kern {
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index 82c5988417a0c..9ee39c654dc0a 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -163,7 +163,7 @@ static const struct bpf_func_proto bpf_bprm_opts_set_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &bpf_bprm_opts_set_btf_ids[0],
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_ima_inode_hash, struct inode *, inode, void *, dst, u32, size)
diff --git a/kernel/bpf/bpf_task_storage.c b/kernel/bpf/bpf_task_storage.c
index 4b342be29eac7..e002df9d3a143 100644
--- a/kernel/bpf/bpf_task_storage.c
+++ b/kernel/bpf/bpf_task_storage.c
@@ -243,7 +243,7 @@ const struct bpf_func_proto bpf_task_storage_get_proto = {
.arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
.arg2_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_task_storage_delete_proto = {
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 9c2cab08bb794..0bd26b2ec77db 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8222,7 +8222,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
return -EINVAL;
}
if (btf_type_is_int(t) || btf_is_any_enum(t)) {
- sub->args[i].arg_type = ARG_ANYTHING;
+ sub->args[i].arg_type = ARG_SCALAR;
continue;
}
if (!is_global)
@@ -8747,8 +8747,8 @@ const struct bpf_func_proto bpf_btf_find_by_name_kind_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_MEM_SIZE,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BTF_ID_LIST_GLOBAL(btf_tracing_ids, MAX_BTF_TRACING_TYPE)
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 149672c76c49c..aa7da999cdb8a 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -1840,7 +1840,7 @@ const struct bpf_func_proto bpf_get_local_storage_proto = {
.gpl_only = false,
.ret_type = RET_PTR_TO_MAP_VALUE,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_0(bpf_get_retval)
@@ -1870,7 +1870,7 @@ const struct bpf_func_proto bpf_set_retval_proto = {
.func = bpf_set_retval,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
@@ -2331,7 +2331,7 @@ static const struct bpf_func_proto bpf_sysctl_get_name_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static int copy_sysctl_value(char *dst, size_t dst_len, char *src,
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 5db77d7915dfc..404dc6db06915 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -3208,7 +3208,7 @@ const struct bpf_func_proto bpf_tail_call_proto = {
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
/* Stub for JITs that only support cBPF. eBPF programs are interpreted.
diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
index b682fd2be443e..c740ae070e61b 100644
--- a/kernel/bpf/diagnostics.c
+++ b/kernel/bpf/diagnostics.c
@@ -960,6 +960,35 @@ const char *bpf_diag_reg_type_plain(struct bpf_verifier_env *env, enum bpf_reg_t
}
}
+const char *bpf_diag_arg_type_plain(enum bpf_arg_type type)
+{
+ switch (base_type(type)) {
+ case ARG_MEM_SIZE:
+ case ARG_CONST_MEM_SIZE:
+ return "an integer scalar length for this memory argument";
+ case ARG_PTR_TO_CTX:
+ return "the original program context pointer or preserve it before modifying registers";
+ case ARG_SCALAR:
+ case ARG_CONST_SCALAR:
+ case ARG_CONST_ALLOC_SIZE_OR_ZERO:
+ return "an integer scalar value for this argument, not a pointer or resource object";
+ case ARG_PTR_TO_CONST_STR:
+ return "a constant string pointer that the verifier recognizes, such as a string stored in a read-only map value";
+ case ARG_PTR_TO_DYNPTR:
+ return "the address of a stack dynptr object, or use a const dynptr pointer returned by the verifier-supported path";
+ case ARG_PTR_TO_ALLOC_BTF_ID:
+ return "a pointer returned by the matching BPF object allocation path";
+ case ARG_PTR_TO_REFCOUNTED_KPTR:
+ return "an owning or non-owning pointer to a BPF-managed object containing a bpf_refcount field";
+ case ARG_PTR_TO_ITER:
+ return "the address of a stack iterator object for iterator new, next, and destroy calls";
+ case ARG_PTR_TO_IRQ_FLAG:
+ return "the same stack slot used by bpf_local_irq_save() or bpf_res_spin_lock_irqsave()";
+ default:
+ return "a value with one of the accepted pointer or scalar types for this call";
+ }
+}
+
static const char *diag_arg_ordinal(int argno)
{
switch (argno) {
diff --git a/kernel/bpf/diagnostics.h b/kernel/bpf/diagnostics.h
index d1b79945008a8..a4102fb049ece 100644
--- a/kernel/bpf/diagnostics.h
+++ b/kernel/bpf/diagnostics.h
@@ -51,6 +51,7 @@ const char *bpf_diag_vfmt(struct bpf_verifier_env *env, const char *fmt, va_list
const char *bpf_diag_fmt(struct bpf_verifier_env *env, const char *fmt, ...) __printf(2, 3);
const char *bpf_diag_fmt_btf_type(struct bpf_verifier_env *env, const struct btf *btf, u32 type_id);
const char *bpf_diag_reg_type_plain(struct bpf_verifier_env *env, enum bpf_reg_type type);
+const char *bpf_diag_arg_type_plain(enum bpf_arg_type type);
u64 bpf_diag_event_log_save(struct bpf_verifier_env *env);
void bpf_diag_event_log_restore(struct bpf_verifier_env *env, u64 log_pos);
u32 bpf_diag_irq_depth(const struct bpf_verifier_state *state);
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 73fb3ffc18e33..9512f6497d328 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -2015,7 +2015,8 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
goto next_insn;
}
- if (insn->imm == BPF_FUNC_timer_set_callback) {
+ aux = &env->insn_aux_data[i + delta];
+ if (aux->arg_prog) {
/* The verifier will process callback_fn as many times as necessary
* with different maps and the register states prepared by
* set_timer_callback_state will be accurate.
@@ -2030,7 +2031,7 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
* bpf_timer_set_callback-ed will return -EINVAL.
*/
struct bpf_insn ld_addrs[2] = {
- BPF_LD_IMM64(BPF_REG_3, (long)prog->aux),
+ BPF_LD_IMM64(aux->arg_prog, (long)prog->aux),
};
insn_buf[0] = ld_addrs[0];
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index b3cc5c8fc8756..1b731aad54da6 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -71,7 +71,7 @@ const struct bpf_func_proto bpf_map_update_elem_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_MAP_KEY,
.arg3_type = ARG_PTR_TO_MAP_VALUE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_map_delete_elem, struct bpf_map *, map, void *, key)
@@ -101,7 +101,7 @@ const struct bpf_func_proto bpf_map_push_elem_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_MAP_VALUE,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_map_pop_elem, struct bpf_map *, map, void *, value)
@@ -143,7 +143,7 @@ const struct bpf_func_proto bpf_map_lookup_percpu_elem_proto = {
.ret_type = RET_PTR_TO_MAP_VALUE_OR_NULL,
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_MAP_KEY,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_get_prandom_u32_proto = {
@@ -441,7 +441,7 @@ const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto = {
.func = bpf_get_current_ancestor_cgroup_id,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
#endif /* CONFIG_CGROUPS */
@@ -540,7 +540,7 @@ const struct bpf_func_proto bpf_strtol_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_MEM_SIZE,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg4_size = sizeof(s64),
};
@@ -568,7 +568,7 @@ const struct bpf_func_proto bpf_strtoul_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_MEM_SIZE,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg4_size = sizeof(u64),
};
@@ -624,8 +624,8 @@ const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto = {
.func = bpf_get_ns_current_pid_tgid,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
- .arg2_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -651,7 +651,7 @@ const struct bpf_func_proto bpf_event_output_data_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -676,7 +676,7 @@ const struct bpf_func_proto bpf_copy_from_user_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_copy_from_user_task, void *, dst, u32, size,
@@ -707,10 +707,10 @@ const struct bpf_func_proto bpf_copy_from_user_task_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_BTF_ID,
.arg4_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
- .arg5_type = ARG_ANYTHING
+ .arg5_type = ARG_SCALAR
};
BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
@@ -726,7 +726,7 @@ const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
.gpl_only = false,
.ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY,
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)
@@ -1415,7 +1415,7 @@ static const struct bpf_func_proto bpf_timer_init_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_TIMER,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static int bpf_async_update_prog_callback(struct bpf_async_cb *cb,
@@ -1510,6 +1510,7 @@ static const struct bpf_func_proto bpf_timer_set_callback_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_TIMER,
.arg2_type = ARG_PTR_TO_FUNC,
+ .arg3_type = ARG_PTR_TO_PROG_AUX,
};
static bool defer_timer_wq_op(void)
@@ -1558,8 +1559,8 @@ static const struct bpf_func_proto bpf_timer_start_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_TIMER,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_timer_cancel, struct bpf_async_kern *, async)
@@ -1889,7 +1890,7 @@ static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT | MEM_WRITE,
};
@@ -1945,8 +1946,8 @@ static const struct bpf_func_proto bpf_dynptr_read_proto = {
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
.arg3_type = ARG_PTR_TO_DYNPTR,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
int __bpf_dynptr_write(const struct bpf_dynptr_kern *dst, u64 offset, void *src,
@@ -2002,10 +2003,10 @@ static const struct bpf_func_proto bpf_dynptr_write_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_DYNPTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE_OR_ZERO,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_dynptr_data, const struct bpf_dynptr_kern *, ptr, u64, offset, u64, len)
@@ -2045,7 +2046,7 @@ static const struct bpf_func_proto bpf_dynptr_data_proto = {
.gpl_only = false,
.ret_type = RET_PTR_TO_DYNPTR_MEM_OR_NULL,
.arg1_type = ARG_PTR_TO_DYNPTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_CONST_ALLOC_SIZE_OR_ZERO,
};
@@ -2957,7 +2958,7 @@ const struct bpf_func_proto bpf_current_task_under_cgroup_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
/**
diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c
index 3f1013d805446..63c0aba56a3f3 100644
--- a/kernel/bpf/ringbuf.c
+++ b/kernel/bpf/ringbuf.c
@@ -553,7 +553,7 @@ const struct bpf_func_proto bpf_ringbuf_reserve_proto = {
.ret_type = RET_PTR_TO_RINGBUF_MEM_OR_NULL,
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_CONST_ALLOC_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static void bpf_ringbuf_commit(void *sample, u64 flags, bool discard)
@@ -594,7 +594,7 @@ const struct bpf_func_proto bpf_ringbuf_submit_proto = {
.func = bpf_ringbuf_submit,
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_RINGBUF_MEM | OBJ_RELEASE,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_ringbuf_discard, void *, sample, u64, flags)
@@ -607,7 +607,7 @@ const struct bpf_func_proto bpf_ringbuf_discard_proto = {
.func = bpf_ringbuf_discard,
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_RINGBUF_MEM | OBJ_RELEASE,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_ringbuf_output, struct bpf_map *, map, void *, data, u64, size,
@@ -635,7 +635,7 @@ const struct bpf_func_proto bpf_ringbuf_output_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_ringbuf_query, struct bpf_map *, map, u64, flags)
@@ -664,7 +664,7 @@ const struct bpf_func_proto bpf_ringbuf_query_proto = {
.func = bpf_ringbuf_query,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_ringbuf_reserve_dynptr, struct bpf_map *, map, u32, size, u64, flags,
@@ -702,8 +702,8 @@ const struct bpf_func_proto bpf_ringbuf_reserve_dynptr_proto = {
.func = bpf_ringbuf_reserve_dynptr,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT | MEM_WRITE,
};
@@ -723,7 +723,7 @@ const struct bpf_func_proto bpf_ringbuf_submit_dynptr_proto = {
.func = bpf_ringbuf_submit_dynptr,
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | OBJ_RELEASE,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_ringbuf_discard_dynptr, struct bpf_dynptr_kern *, ptr, u64, flags)
@@ -742,7 +742,7 @@ const struct bpf_func_proto bpf_ringbuf_discard_dynptr_proto = {
.func = bpf_ringbuf_discard_dynptr,
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | OBJ_RELEASE,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
static int __bpf_user_ringbuf_peek(struct bpf_ringbuf *rb, void **sample, u32 *size)
@@ -876,5 +876,5 @@ const struct bpf_func_proto bpf_user_ringbuf_drain_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_FUNC,
.arg3_type = ARG_PTR_TO_STACK_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index a839041e0d008..272678b825005 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -665,7 +665,7 @@ const struct bpf_func_proto bpf_get_stackid_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static __u64 count_kernel_ip(const struct perf_callchain_entry *trace)
@@ -739,7 +739,7 @@ const struct bpf_func_proto bpf_get_stackid_proto_pe = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static u32 callchain_store(const struct perf_callchain_entry *trace, u32 trace_nr,
@@ -863,7 +863,7 @@ const struct bpf_func_proto bpf_get_stack_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_get_stack_sleepable, struct pt_regs *, regs, void *, buf, u32, size,
@@ -879,7 +879,7 @@ const struct bpf_func_proto bpf_get_stack_sleepable_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static long __bpf_get_task_stack(struct task_struct *task, void *buf, u32 size,
@@ -916,7 +916,7 @@ const struct bpf_func_proto bpf_get_task_stack_proto = {
.arg1_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_get_task_stack_sleepable, struct task_struct *, task, void *, buf,
@@ -933,7 +933,7 @@ const struct bpf_func_proto bpf_get_task_stack_sleepable_proto = {
.arg1_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static int __bpf_get_stack_pe(const struct perf_callchain_entry *trace, u32 trace_nr,
@@ -1015,7 +1015,7 @@ const struct bpf_func_proto bpf_get_stack_proto_pe = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
/* Called from eBPF program */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 6874ba1424af0..6950517f6364b 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -6569,7 +6569,7 @@ static const struct bpf_func_proto bpf_sys_bpf_proto = {
.func = bpf_sys_bpf,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE,
};
@@ -6594,7 +6594,7 @@ static const struct bpf_func_proto bpf_sys_close_proto = {
.func = bpf_sys_close,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flags, u64 *, res)
@@ -6619,7 +6619,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg4_size = sizeof(u64),
};
diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
index 13e1aabe6f886..91b166acb3b5c 100644
--- a/kernel/bpf/task_iter.c
+++ b/kernel/bpf/task_iter.c
@@ -824,10 +824,10 @@ const struct bpf_func_proto bpf_find_vma_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_FUNC,
.arg4_type = ARG_PTR_TO_STACK_OR_NULL,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
static inline void bpf_iter_mmput_async(struct mm_struct *mm)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5b51e7ee1a3f9..54656fb31bbe7 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -951,8 +951,12 @@ static enum bpf_dynptr_type dynptr_reg_type(struct bpf_verifier_env *env, struct
static bool is_dynptr_type_expected(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
enum bpf_arg_type arg_type)
{
- /* ARG_PTR_TO_DYNPTR takes any type of dynptr */
- if (arg_type == ARG_PTR_TO_DYNPTR)
+ /*
+ * ARG_PTR_TO_DYNPTR without a type flag takes any type of dynptr.
+ * Test the flags rather than the whole arg_type, which may carry
+ * unrelated ones such as PTR_MAYBE_NULL.
+ */
+ if (!(arg_type & DYNPTR_TYPE_FLAG_MASK))
return true;
return dynptr_reg_type(env, reg) == arg_to_dynptr_type(arg_type);
@@ -4845,7 +4849,7 @@ static int check_map_access(struct bpf_verifier_env *env, struct bpf_reg_state *
}
static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
- const struct bpf_func_proto *fn,
+ const struct bpf_call_arg_meta *meta,
enum bpf_access_type t)
{
enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
@@ -4869,10 +4873,11 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
case BPF_PROG_TYPE_LWT_XMIT:
case BPF_PROG_TYPE_SK_SKB:
case BPF_PROG_TYPE_SK_MSG:
- if (fn)
- return fn->pkt_access;
+ if (meta && !meta->btf && meta->func_id)
+ return meta->fn->pkt_access;
- env->seen_direct_write = true;
+ if (t == BPF_WRITE)
+ env->seen_direct_write = true;
return true;
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
@@ -5130,18 +5135,6 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = {
[CONST_PTR_TO_MAP] = btf_bpf_map_id,
};
-static enum bpf_reg_type lookup_reg2btf_ids(u32 ref_id)
-{
- enum bpf_reg_type type;
-
- for (type = 0; type < __BPF_REG_TYPE_MAX; type++) {
- if (reg2btf_ids[type] && *reg2btf_ids[type] == ref_id)
- 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. */
@@ -7056,6 +7049,10 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, struct bpf_reg_
switch (base_type(reg->type)) {
case PTR_TO_PACKET:
case PTR_TO_PACKET_META:
+ if (!may_access_direct_pkt_data(env, meta, access_type)) {
+ verbose(env, "function access to the packet is not allowed\n");
+ return -EACCES;
+ }
return check_packet_access(env, reg, argno, 0, access_size,
zero_size_allowed);
case PTR_TO_MAP_KEY:
@@ -7172,7 +7169,7 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,
* the memory that the helper could just partially fill up.
*/
if (!tnum_is_const(size_reg->var_off))
- meta = NULL;
+ meta->arg_raw_mem.regno = 0;
if (reg_smin(size_reg) < 0) {
verbose(env, "%s min value is negative, either use unsigned or 'var &= const'\n",
@@ -7618,11 +7615,11 @@ __printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u
/*
* Validate dynptr arguments for helper, kfunc and subprog.
*
- * @dynptr is both input and output. It is populated when the argument is
- * tagged with MEM_UNINIT (i.e., the dynptr argument that will be constructed)
- * and consumed when the argument is expecting to be an initialized dynptr.
- * @parent_id is used to track the referenced parent object (e.g., file or skb in
- * qdisc program) when constructing a dynptr.
+ * @meta carries the dynptr and referenced-object state. The dynptr is populated
+ * when the argument is tagged with MEM_UNINIT (i.e., the dynptr argument that
+ * will be constructed) and consumed when the argument is expected to be an
+ * initialized dynptr. The reference tracks the parent object (e.g., file or skb
+ * in qdisc program) when constructing a dynptr.
*
* There are two register types representing a bpf_dynptr, one is PTR_TO_STACK
* which points to a stack slot, and the other is CONST_PTR_TO_DYNPTR.
@@ -7639,9 +7636,8 @@ __printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u
* and checked dynamically during runtime.
*/
static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
- argno_t argno, int insn_idx, const char *call_name,
- enum bpf_arg_type arg_type,
- struct ref_obj_desc *ref_obj, struct bpf_dynptr_desc *dynptr)
+ argno_t argno, int insn_idx, enum bpf_arg_type arg_type,
+ struct bpf_call_arg_meta *meta)
{
int spi, err = 0;
@@ -7650,7 +7646,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
"%s expected pointer to stack or const struct bpf_dynptr\n",
reg_arg_name(env, argno));
bpf_diag_call_arg_fmt(
- env, insn_idx, argno, call_name,
+ env, insn_idx, argno, meta->func_name,
"Pass the address of a stack dynptr object, or use a const dynptr pointer returned by the verifier-supported path.",
"a dynptr argument must be a pointer to a dynptr stack slot or a verifier-provided const struct bpf_dynptr, but %s is %s",
reg_arg_name(env, argno), bpf_diag_reg_type_plain(env, reg->type));
@@ -7678,7 +7674,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
verbose(env, "Dynptr has to be an uninitialized dynptr\n");
bpf_diag_res(
env, insn_idx, "dynptr is already initialized",
- "This kfunc constructs a dynptr and requires an uninitialized dynptr stack slot, but the selected slot already holds dynptr state.",
+ "This function constructs a dynptr and requires an uninitialized dynptr stack slot, but the selected slot already holds dynptr state.",
"Use a fresh stack dynptr slot, or release/destroy the existing dynptr before reusing the slot.");
return -EINVAL;
}
@@ -7691,7 +7687,8 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
return err;
}
- err = mark_stack_slots_dynptr(env, reg, arg_type, insn_idx, ref_obj, dynptr);
+ err = mark_stack_slots_dynptr(env, reg, arg_type, insn_idx,
+ &meta->ref_obj, &meta->dynptr);
} else /* OBJ_RELEASE and None case from above */ {
/* For the reg->type == PTR_TO_STACK case, bpf_dynptr is never const */
if (reg->type == CONST_PTR_TO_DYNPTR && (arg_type & OBJ_RELEASE)) {
@@ -7721,7 +7718,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
verbose(env, "Expected a dynptr of type %s as %s\n",
dynptr_type_str(expected_type), reg_arg_name(env, argno));
bpf_diag_call_arg_fmt(
- env, insn_idx, argno, call_name,
+ env, insn_idx, argno, meta->func_name,
"Use a dynptr constructor that matches this operation, or call an operation that accepts the dynptr's current type.",
"the dynptr is initialized with backing object type %s, but this operation expects dynptr type %s",
dynptr_type_str(actual_type), dynptr_type_str(expected_type));
@@ -7740,11 +7737,9 @@ static int process_dynptr_func(struct bpf_verifier_env *env, struct bpf_reg_stat
reg = &state->stack[spi].spilled_ptr;
}
- if (dynptr) {
- dynptr->type = reg->dynptr.type;
- dynptr->id = reg->id;
- dynptr->parent_id = reg->parent_id;
- }
+ meta->dynptr.type = reg->dynptr.type;
+ meta->dynptr.id = reg->id;
+ meta->dynptr.parent_id = reg->parent_id;
}
return err;
}
@@ -7808,8 +7803,8 @@ static int process_iter_arg(struct bpf_verifier_env *env, struct bpf_reg_state *
reg_arg_name(env, argno));
bpf_diag_call_arg(
env, insn_idx, argno, meta->func_name,
- "the kfunc expects a recognized iterator state pointer, but this argument does not match a valid iterator type",
- "Pass the exact iterator state type expected by this kfunc.");
+ "the function expects a recognized iterator state pointer, but this argument does not match a valid iterator type",
+ "Pass the exact iterator state type expected by this function.");
return -EINVAL;
}
t = btf_type_by_id(meta->btf, btf_id);
@@ -8133,9 +8128,43 @@ static bool arg_type_is_dynptr(enum bpf_arg_type type)
return base_type(type) == ARG_PTR_TO_DYNPTR;
}
+/*
+ * An argument that only ever takes a scalar, so a zero register passed to it
+ * is a value rather than a NULL pointer.
+ */
+static bool arg_type_is_scalar(enum bpf_arg_type type)
+{
+ switch (base_type(type)) {
+ case ARG_SCALAR:
+ case ARG_CONST_SCALAR:
+ case ARG_MEM_SIZE:
+ case ARG_MEM_SIZE_OR_ZERO:
+ case ARG_CONST_MEM_SIZE:
+ case ARG_CONST_ALLOC_SIZE_OR_ZERO:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * A kfunc is named by a BTF ID, which can take the same numeric value as an
+ * enum bpf_func_id. Only test meta->func_id against a BPF_FUNC_* once the call
+ * is known to be to a helper; meta->btf is set only for a kfunc.
+ */
+static bool is_helper_call(const struct bpf_call_arg_meta *meta, enum bpf_func_id func_id)
+{
+ return !meta->btf && meta->func_id == func_id;
+}
+
+static bool is_kfunc_call(const struct bpf_call_arg_meta *meta, u32 btf_id)
+{
+ return meta->btf && meta->func_id == btf_id;
+}
+
static int resolve_map_arg_type(struct bpf_verifier_env *env,
- const struct bpf_call_arg_meta *meta,
- enum bpf_arg_type *arg_type)
+ const struct bpf_call_arg_meta *meta,
+ enum bpf_arg_type *arg_type)
{
if (!meta->map.ptr) {
/* kernel subsystem misconfigured verifier */
@@ -8154,7 +8183,7 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,
}
break;
case BPF_MAP_TYPE_BLOOM_FILTER:
- if (meta->func_id == BPF_FUNC_map_peek_elem)
+ if (is_helper_call(meta, BPF_FUNC_map_peek_elem))
*arg_type = ARG_PTR_TO_MAP_VALUE;
break;
default:
@@ -8163,6 +8192,48 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,
return 0;
}
+static int resolve_func_arg_type(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg, u32 arg,
+ struct bpf_call_arg_meta *meta,
+ enum bpf_arg_type *arg_type, u32 *arg_size);
+static int process_arg_ptr_to_btf_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+ argno_t argno, enum bpf_arg_type arg_type,
+ const struct btf *arg_btf, u32 arg_btf_id,
+ struct bpf_call_arg_meta *meta, int insn_idx);
+static bool is_kfunc_arg_nonown_allowed(const struct btf *btf,
+ const struct btf_param *arg);
+static bool is_kfunc_arg_scalar_with_name(const struct btf *btf,
+ const struct btf_param *arg,
+ const char *name);
+static bool is_bpf_cast_to_kern_ctx_kfunc(const struct bpf_call_arg_meta *meta);
+static bool is_bpf_dynptr_clone_kfunc(const struct bpf_call_arg_meta *meta);
+static bool is_bpf_iter_css_task_new_kfunc(const struct bpf_call_arg_meta *meta);
+static bool is_bpf_obj_drop_kfunc(u32 func_id);
+static bool is_bpf_percpu_obj_drop_kfunc(u32 func_id);
+static bool is_bpf_rbtree_add_kfunc(u32 func_id);
+static int get_bpf_res_spin_lock_kfunc_flags(const struct bpf_call_arg_meta *meta);
+static struct bpf_insn_aux_data *cur_aux(const struct bpf_verifier_env *env);
+static int process_irq_flag(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg, argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static int process_kf_arg_ptr_to_list_head(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg,
+ argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static int process_kf_arg_ptr_to_rbtree_root(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg,
+ argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static int process_kf_arg_ptr_to_list_node(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg,
+ argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static int process_kf_arg_ptr_to_rbtree_node(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg,
+ argno_t argno,
+ struct bpf_call_arg_meta *meta);
+static bool check_css_task_iter_allowlist(struct bpf_verifier_env *env);
+
struct bpf_reg_types {
const enum bpf_reg_type types[10];
u32 *btf_id;
@@ -8206,7 +8277,7 @@ static const struct bpf_reg_types mem_types = {
},
};
-static const struct bpf_reg_types spin_lock_types = {
+static const struct bpf_reg_types map_value_or_alloc_obj_types = {
.types = {
PTR_TO_MAP_VALUE,
PTR_TO_BTF_ID | MEM_ALLOC,
@@ -8235,7 +8306,29 @@ static const struct bpf_reg_types percpu_btf_ptr_types = {
static const struct bpf_reg_types func_ptr_types = { .types = { PTR_TO_FUNC } };
static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK } };
static const struct bpf_reg_types const_str_ptr_types = { .types = { PTR_TO_MAP_VALUE } };
-static const struct bpf_reg_types timer_types = { .types = { PTR_TO_MAP_VALUE } };
+static const struct bpf_reg_types map_value_types = { .types = { PTR_TO_MAP_VALUE } };
+static const struct bpf_reg_types arena_types = {
+ .types = {
+ PTR_TO_ARENA,
+ SCALAR_VALUE,
+ }
+};
+
+static const struct bpf_reg_types alloc_obj_types = {
+ .types = {
+ PTR_TO_BTF_ID | MEM_ALLOC,
+ PTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU,
+ }
+};
+
+static const struct bpf_reg_types alloc_obj_or_non_own_ref_types = {
+ .types = {
+ PTR_TO_BTF_ID | MEM_ALLOC,
+ PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF,
+ PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU,
+ }
+};
+
static const struct bpf_reg_types kptr_xchg_dest_types = {
.types = {
PTR_TO_MAP_VALUE,
@@ -8265,16 +8358,32 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
#endif
[ARG_PTR_TO_SOCKET] = &fullsock_types,
[ARG_PTR_TO_BTF_ID] = &btf_ptr_types,
- [ARG_PTR_TO_SPIN_LOCK] = &spin_lock_types,
+ [ARG_PTR_TO_SPIN_LOCK] = &map_value_or_alloc_obj_types,
[ARG_PTR_TO_MEM] = &mem_types,
[ARG_PTR_TO_RINGBUF_MEM] = &ringbuf_mem_types,
[ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types,
[ARG_PTR_TO_FUNC] = &func_ptr_types,
[ARG_PTR_TO_STACK] = &stack_ptr_types,
[ARG_PTR_TO_CONST_STR] = &const_str_ptr_types,
- [ARG_PTR_TO_TIMER] = &timer_types,
+ [ARG_PTR_TO_TIMER] = &map_value_types,
[ARG_KPTR_XCHG_DEST] = &kptr_xchg_dest_types,
[ARG_PTR_TO_DYNPTR] = &dynptr_types,
+ /* Argument kinds only a kfunc can have. */
+ [ARG_SCALAR] = &scalar_types,
+ [ARG_CONST_SCALAR] = &scalar_types,
+ [ARG_CONST_MEM_SIZE] = &scalar_types,
+ [ARG_PTR_TO_ALLOC_BTF_ID] = &alloc_obj_types,
+ [ARG_PTR_TO_REFCOUNTED_KPTR] = &alloc_obj_or_non_own_ref_types,
+ [ARG_PTR_TO_ITER] = &stack_ptr_types,
+ [ARG_PTR_TO_LIST_HEAD] = &map_value_or_alloc_obj_types,
+ [ARG_PTR_TO_LIST_NODE] = &alloc_obj_or_non_own_ref_types,
+ [ARG_PTR_TO_RB_ROOT] = &map_value_or_alloc_obj_types,
+ [ARG_PTR_TO_RB_NODE] = &alloc_obj_or_non_own_ref_types,
+ [ARG_PTR_TO_RES_SPIN_LOCK] = &map_value_or_alloc_obj_types,
+ [ARG_PTR_TO_WORKQUEUE] = &map_value_types,
+ [ARG_PTR_TO_TASK_WORK] = &map_value_types,
+ [ARG_PTR_TO_IRQ_FLAG] = &stack_ptr_types,
+ [ARG_PTR_TO_ARENA] = &arena_types,
};
static void bpf_diag_call_arg(struct bpf_verifier_env *env, u32 insn_idx, argno_t argno,
@@ -8314,6 +8423,71 @@ __printf(6, 7) static void bpf_diag_call_arg_fmt(struct bpf_verifier_env *env, u
bpf_diag_call_arg(env, insn_idx, argno, call_name, reason, suggestion);
}
+static int check_func_arg_nullability(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg, argno_t argno,
+ enum bpf_arg_type arg_type,
+ struct bpf_call_arg_meta *meta, int insn_idx)
+{
+ const char *expected_type = "pointer";
+
+ if (arg_type_is_scalar(arg_type) || type_may_be_null(arg_type) ||
+ (!bpf_register_is_null(reg) && !type_may_be_null(reg->type)))
+ return 0;
+
+ if (meta->btf) {
+ u32 arg_btf_id;
+
+ arg_btf_id = btf_params(meta->func_proto)[arg_idx_from_argno(argno)].type;
+ expected_type = bpf_diag_fmt(env, "value of type %s",
+ bpf_diag_fmt_btf_type(env, meta->btf, arg_btf_id));
+ }
+
+ verbose(env, "Possibly NULL pointer passed to trusted %s\n",
+ reg_arg_name(env, argno));
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Add a NULL check and make the call only on the non-NULL path.",
+ "the pointer may be NULL, but this call requires a non-NULL %s",
+ expected_type);
+ return -EACCES;
+}
+
+static int check_func_arg_release(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+ argno_t argno, enum bpf_arg_type arg_type,
+ struct bpf_call_arg_meta *meta, int insn_idx)
+{
+ const char *expected_type = "pointer";
+
+ if (!arg_type_is_release(arg_type))
+ return 0;
+
+ if (arg_type_is_dynptr(arg_type) || reg_is_referenced(env, reg) ||
+ bpf_register_is_null(reg))
+ return 0;
+
+ verbose(env, "release function %s expects referenced PTR_TO_BTF_ID passed to %s\n",
+ meta->func_name, reg_arg_name(env, argno));
+
+ if (meta->btf) {
+ const struct btf_param *btf_arg;
+ const struct btf_type *t;
+ u32 ref_id;
+
+ btf_arg = &btf_params(meta->func_proto)[arg_idx_from_argno(argno)];
+ ref_id = btf_arg->type;
+ t = btf_type_skip_modifiers(meta->btf, btf_arg->type, NULL);
+ if (btf_type_is_ptr(t))
+ btf_type_skip_modifiers(meta->btf, t->type, &ref_id);
+ expected_type = bpf_diag_fmt(env, "value of type %s",
+ bpf_diag_fmt_btf_type(env, meta->btf, ref_id));
+ }
+
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ bpf_diag_fmt(env, "Pass the resource-owning %s returned by the matching acquire call, or avoid the release function after ownership has already been transferred or released.",
+ expected_type),
+ "release functions require a value that owns a live resource returned by a matching acquire function");
+ return -EINVAL;
+}
+
static const char *bpf_diag_expected_reg_types(struct bpf_verifier_env *env,
const enum bpf_reg_type *types, int count)
{
@@ -8335,19 +8509,21 @@ static const char *bpf_diag_expected_reg_types(struct bpf_verifier_env *env,
}
static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *reg, argno_t argno,
- enum bpf_arg_type arg_type, const u32 *arg_btf_id,
- struct bpf_call_arg_meta *meta, const char *call_name)
+ enum bpf_arg_type arg_type, struct bpf_call_arg_meta *meta)
{
enum bpf_reg_type expected, type = reg->type;
const struct bpf_reg_types *compatible;
const char *actual, *accepted;
- int i, j, err;
+ int i, j;
compatible = compatible_reg_types[base_type(arg_type)];
if (!compatible) {
verifier_bug(env, "unsupported arg type %d", arg_type);
return -EFAULT;
}
+ if (meta->btf && base_type(arg_type) == ARG_PTR_TO_BTF_ID &&
+ (base_type(type) == PTR_TO_BTF_ID || reg2btf_ids[base_type(type)]))
+ goto found;
/* ARG_PTR_TO_MEM + RDONLY is compatible with PTR_TO_MEM and PTR_TO_MEM + RDONLY,
* but ARG_PTR_TO_MEM is compatible only with PTR_TO_MEM and NOT with PTR_TO_MEM + RDONLY
@@ -8369,7 +8545,8 @@ static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *re
type &= ~DYNPTR_TYPE_FLAG_MASK;
/* Local kptr types are allowed as the source argument of bpf_kptr_xchg */
- if (meta->func_id == BPF_FUNC_kptr_xchg && type_is_alloc(type) && reg_from_argno(argno) == BPF_REG_2) {
+ if (is_helper_call(meta, BPF_FUNC_kptr_xchg) && type_is_alloc(type) &&
+ reg_from_argno(argno) == BPF_REG_2) {
type &= ~MEM_ALLOC;
type &= ~MEM_PERCPU;
}
@@ -8389,115 +8566,13 @@ static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *re
verbose(env, "%s\n", reg_type_str(env, compatible->types[j]));
actual = bpf_diag_fmt(env, "%s", reg_type_str(env, reg->type));
accepted = bpf_diag_expected_reg_types(env, compatible->types, i);
- bpf_diag_call_arg_fmt(env, env->insn_idx, argno, call_name,
- "Pass a value with one of the accepted pointer or scalar types for this call.",
+ bpf_diag_call_arg_fmt(env, env->insn_idx, argno, meta->func_name,
+ bpf_diag_fmt(env, "Pass %s.", bpf_diag_arg_type_plain(arg_type)),
"it has type %s, but this argument accepts %s",
actual, accepted);
return -EACCES;
found:
- if (base_type(reg->type) != PTR_TO_BTF_ID)
- return 0;
-
- if (compatible == &mem_types) {
- if (!(arg_type & MEM_RDONLY)) {
- verbose(env,
- "%s() may write into memory pointed by %s type=%s\n",
- func_id_name(meta->func_id),
- reg_arg_name(env, argno), reg_type_str(env, reg->type));
- return -EACCES;
- }
- return 0;
- }
-
- switch ((int)reg->type) {
- case PTR_TO_BTF_ID:
- case PTR_TO_BTF_ID | PTR_TRUSTED:
- case PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL:
- case PTR_TO_BTF_ID | MEM_RCU:
- case PTR_TO_BTF_ID | PTR_MAYBE_NULL:
- case PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU:
- {
- /* For bpf_sk_release, it needs to match against first member
- * 'struct sock_common', hence make an exception for it. This
- * allows bpf_sk_release to work for multiple socket types.
- */
- bool strict_type_match = arg_type_is_release(arg_type) &&
- meta->func_id != BPF_FUNC_sk_release;
-
- if (type_may_be_null(reg->type) &&
- (!type_may_be_null(arg_type) || arg_type_is_release(arg_type))) {
- verbose(env, "Possibly NULL pointer passed to helper %s\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg(
- env, env->insn_idx, argno, call_name,
- "the pointer may be NULL, but this call requires a non-NULL pointer",
- "Add a NULL check and make the call only on the non-NULL path.");
- return -EACCES;
- }
-
- if (!arg_btf_id) {
- if (!compatible->btf_id) {
- verifier_bug(env, "missing arg compatible BTF ID");
- return -EFAULT;
- }
- arg_btf_id = compatible->btf_id;
- }
-
- if (meta->func_id == BPF_FUNC_kptr_xchg) {
- if (map_kptr_match_type(env, meta->kptr_field, reg, reg_from_argno(argno)))
- return -EACCES;
- } else {
- if (arg_btf_id == BPF_PTR_POISON) {
- verbose(env, "verifier internal error:");
- verbose(env, "%s has non-overwritten BPF_PTR_POISON type\n",
- reg_arg_name(env, argno));
- return -EACCES;
- }
-
- err = __check_ptr_off_reg(env, reg, argno, true);
- if (err)
- return err;
-
- if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id,
- reg->var_off.value, btf_vmlinux, *arg_btf_id,
- strict_type_match, !type_is_alloc(reg->type))) {
- verbose(env, "%s is of type %s but %s is expected\n",
- reg_arg_name(env, argno),
- btf_type_name(reg->btf, reg->btf_id),
- btf_type_name(btf_vmlinux, *arg_btf_id));
- return -EACCES;
- }
- }
- break;
- }
- case PTR_TO_BTF_ID | MEM_ALLOC:
- case PTR_TO_BTF_ID | MEM_PERCPU | MEM_ALLOC:
- case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF:
- case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU:
- if (meta->func_id != BPF_FUNC_spin_lock && meta->func_id != BPF_FUNC_spin_unlock &&
- meta->func_id != BPF_FUNC_kptr_xchg) {
- verifier_bug(env, "unimplemented handling of MEM_ALLOC");
- return -EFAULT;
- }
- /* Check if local kptr in src arg matches kptr in dst arg */
- if (meta->func_id == BPF_FUNC_kptr_xchg) {
- int regno = reg_from_argno(argno);
-
- if (regno == BPF_REG_2 &&
- map_kptr_match_type(env, meta->kptr_field, reg, regno))
- return -EACCES;
- }
- break;
- case PTR_TO_BTF_ID | MEM_PERCPU:
- case PTR_TO_BTF_ID | MEM_PERCPU | MEM_RCU:
- case PTR_TO_BTF_ID | MEM_PERCPU | PTR_TRUSTED:
- /* Handled by helper specific checks */
- break;
- default:
- verifier_bug(env, "invalid PTR_TO_BTF_ID register for type match");
- return -EFAULT;
- }
return 0;
}
@@ -8518,10 +8593,9 @@ reg_find_field_offset(const struct bpf_reg_state *reg, s32 off, u32 fields)
return field;
}
-static int __check_func_arg_reg_off(struct bpf_verifier_env *env,
- const struct bpf_reg_state *reg, argno_t argno,
- enum bpf_arg_type arg_type,
- bool btf_id_fixed_off_ok)
+static int check_func_arg_reg_off(struct bpf_verifier_env *env,
+ const struct bpf_reg_state *reg, argno_t argno,
+ enum bpf_arg_type arg_type)
{
u32 type = reg->type;
@@ -8577,12 +8651,15 @@ static int __check_func_arg_reg_off(struct bpf_verifier_env *env,
case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF:
case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU:
/* When referenced PTR_TO_BTF_ID is passed to release function,
- * its fixed offset must be 0. In the other cases, fixed offset
- * can be non-zero unless the caller requires otherwise.
- * var_off always must be 0 for PTR_TO_BTF_ID, hence we still
- * need to do checks instead of returning.
+ * its fixed offset must be 0. bpf_refcount_acquire() returns the
+ * pointer it was given while incrementing the refcount at the
+ * refcount field offset, so it needs a zero offset too. In the
+ * other cases, fixed offset can be non-zero. var_off always must
+ * be 0 for PTR_TO_BTF_ID, hence we still need to do checks
+ * instead of returning.
*/
- return __check_ptr_off_reg(env, reg, argno, btf_id_fixed_off_ok);
+ return __check_ptr_off_reg(env, reg, argno,
+ base_type(arg_type) != ARG_PTR_TO_REFCOUNTED_KPTR);
case PTR_TO_CTX:
/*
* Allow fixed and variable offsets for syscall context, but
@@ -8598,13 +8675,6 @@ static int __check_func_arg_reg_off(struct bpf_verifier_env *env,
}
}
-static int check_func_arg_reg_off(struct bpf_verifier_env *env,
- const struct bpf_reg_state *reg, argno_t argno,
- enum bpf_arg_type arg_type)
-{
- return __check_func_arg_reg_off(env, reg, argno, arg_type, true);
-}
-
static int check_arg_const_str(struct bpf_verifier_env *env,
struct bpf_reg_state *reg, argno_t argno)
{
@@ -8770,57 +8840,53 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
struct bpf_call_arg_meta *meta,
int insn_idx)
{
+ const struct btf_param *btf_arg = meta->btf ? &btf_params(meta->func_proto)[arg] : NULL;
const struct bpf_func_proto *fn = meta->fn;
- u32 regno = BPF_REG_1 + arg;
- struct bpf_reg_state *reg = reg_state(env, regno);
+ struct bpf_func_state *caller = cur_func(env);
+ struct bpf_reg_state *regs = cur_regs(env);
+ argno_t argno = argno_from_arg(arg + 1);
+ struct bpf_reg_state *reg = get_func_arg_reg(caller, regs, arg);
enum bpf_arg_type arg_type = fn->arg_type[arg];
- argno_t argno = argno_from_reg(regno);
- enum bpf_reg_type type = reg->type;
- u32 *arg_btf_id = NULL;
+ int regno = reg_from_argno(argno);
+ u32 arg_size = arg_type & MEM_FIXED_SIZE ? fn->arg_size[arg] : 0;
u32 key_size;
int err = 0;
- if (arg_type == ARG_DONTCARE)
+ if (arg_type == ARG_PTR_TO_PROG_AUX) {
+ cur_aux(env)->arg_prog = regno;
+ return 0;
+ }
+ if (arg_type == ARG_IGNORE)
return 0;
- err = check_reg_arg(env, regno, SRC_OP);
- if (err)
- return err;
+ if (regno >= 0) {
+ err = check_reg_arg(env, regno, SRC_OP);
+ if (err)
+ return err;
+ }
- if (arg_type == ARG_ANYTHING) {
- if (is_pointer_value(env, regno)) {
- verbose(env, "R%d leaks addr into helper function\n",
- regno);
+ /* Preserve the legacy helper behavior for privileged pointer leaks. */
+ if (!meta->btf && arg_type == ARG_SCALAR) {
+ if (__is_pointer_value(env->allow_ptr_leaks, reg)) {
+ verbose(env, "%s leaks addr into helper function\n",
+ reg_arg_name(env, argno));
return -EACCES;
}
return 0;
}
- if (type_is_pkt_pointer(type) &&
- !may_access_direct_pkt_data(env, fn, BPF_READ)) {
- verbose(env, "helper access to the packet is not allowed\n");
- return -EACCES;
- }
-
- if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE) {
- err = resolve_map_arg_type(env, meta, &arg_type);
- if (err)
- return err;
- }
+ err = resolve_func_arg_type(env, reg, arg, meta, &arg_type, &arg_size);
+ if (err)
+ return err;
if (bpf_register_is_null(reg) && type_may_be_null(arg_type))
- /* A NULL register has a SCALAR_VALUE type, so skip
- * type checking.
- */
- goto skip_type_check;
+ return 0;
- /* arg_btf_id and arg_size are in a union. */
- if (base_type(arg_type) == ARG_PTR_TO_BTF_ID ||
- base_type(arg_type) == ARG_PTR_TO_SPIN_LOCK)
- arg_btf_id = fn->arg_btf_id[arg];
+ err = check_func_arg_nullability(env, reg, argno, arg_type, meta, insn_idx);
+ if (err)
+ return err;
- err = check_reg_type(env, reg, argno, arg_type, arg_btf_id, meta,
- func_id_name(meta->func_id));
+ err = check_reg_type(env, reg, argno, arg_type, meta);
if (err)
return err;
@@ -8828,22 +8894,27 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
if (err)
return err;
-skip_type_check:
- if (arg_type_is_release(arg_type) && !arg_type_is_dynptr(arg_type) &&
- !reg_is_referenced(env, reg) && !bpf_register_is_null(reg)) {
- verbose(env, "release helper %s expects referenced PTR_TO_BTF_ID passed to %s\n",
- func_id_name(meta->func_id), reg_arg_name(env, argno));
- bpf_diag_call_arg(
- env, insn_idx, argno, func_id_name(meta->func_id),
- "release helpers require a value that owns a live resource returned by a matching acquire helper",
- "Pass the resource-owning pointer returned by the matching acquire helper, and avoid calling the release helper after ownership has already been transferred or released.");
- return -EINVAL;
- }
+ err = check_func_arg_release(env, reg, argno, arg_type, meta, insn_idx);
+ if (err)
+ return err;
if (reg_is_referenced(env, reg))
update_ref_obj(&meta->ref_obj, reg);
switch (base_type(arg_type)) {
+ case ARG_CONST_SCALAR:
+ err = process_const_arg(env, reg, argno, meta);
+ if (err < 0) {
+ if (err == -EINVAL)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass a compile-time constant or a value the verifier can prove is constant at this call.",
+ "the function requires this scalar argument to be a verifier-known constant, but %s is variable on this path",
+ reg_arg_name(env, argno));
+ return err;
+ }
+ break;
+ case ARG_SCALAR:
+ break;
case ARG_CONST_MAP_PTR:
/* bpf_map_xxx(map_ptr) call: remember that map_ptr */
err = process_map_ptr_arg(env, reg, argno, meta);
@@ -8865,7 +8936,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
return -EFAULT;
}
key_size = meta->map.ptr->key_size;
- err = check_helper_mem_access(env, reg, argno, key_size, BPF_READ, false, NULL,
+ err = check_helper_mem_access(env, reg, argno, key_size, BPF_READ, false, meta,
NULL);
if (err)
return err;
@@ -8897,7 +8968,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
* Disable raw mode for bpf_map_peek_elem() on a bloom filter. The helper reads
* the value buffer as an input rather than filling it.
*/
- if (meta->func_id == BPF_FUNC_map_peek_elem &&
+ if (is_helper_call(meta, BPF_FUNC_map_peek_elem) &&
meta->map.ptr->map_type == BPF_MAP_TYPE_BLOOM_FILTER)
meta->arg_raw_mem.regno = 0;
@@ -8905,9 +8976,80 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ,
false, meta, NULL);
break;
+ case ARG_PTR_TO_BTF_ID:
+ case ARG_PTR_TO_BTF_ID_SOCK_COMMON:
+ {
+ const u32 *arg_btf_id = fn->arg_btf_id[arg];
+ const struct btf *arg_btf = meta->btf ?: btf_vmlinux;
+
+ if (!meta->btf) {
+ const struct bpf_reg_types *compatible;
+
+ if (base_type(reg->type) != PTR_TO_BTF_ID)
+ break;
+
+ if (is_helper_call(meta, BPF_FUNC_kptr_xchg))
+ return map_kptr_match_type(env, meta->kptr_field, reg, regno) ?
+ -EACCES : 0;
+
+ if (!arg_btf_id) {
+ compatible = compatible_reg_types[base_type(arg_type)];
+ if (!compatible->btf_id) {
+ verifier_bug(env, "missing arg compatible BTF ID");
+ return -EFAULT;
+ }
+ arg_btf_id = compatible->btf_id;
+ }
+ if (arg_btf_id == BPF_PTR_POISON) {
+ verbose(env, "verifier internal error:");
+ verbose(env, "%s has non-overwritten BPF_PTR_POISON type\n",
+ reg_arg_name(env, argno));
+ return -EACCES;
+ }
+ }
+
+ if (meta->btf && (!is_trusted_reg(env, reg) ||
+ bpf_type_has_unsafe_modifiers(reg->type))) {
+ if (!(arg_type & MEM_RCU)) {
+ const char *actual_type, *arg_name, *expected_type;
+
+ expected_type = bpf_diag_fmt_btf_type(env, arg_btf, *arg_btf_id);
+ verbose(env, "%s must be referenced or trusted\n",
+ reg_arg_name(env, argno));
+ arg_name = reg_arg_name(env, argno);
+ actual_type = bpf_diag_reg_type_plain(env, reg->type);
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass a pointer acquired from a verifier-tracked source, or call this function only inside the required protection if it accepts RCU pointers.",
+ "the function requires a trusted or resource-owning pointer to %s, but %s is %s",
+ expected_type, arg_name, actual_type);
+ return -EINVAL;
+ }
+ if (!is_rcu_reg(reg)) {
+ const char *actual_type, *arg_name, *expected_type;
+
+ expected_type = bpf_diag_fmt_btf_type(env, arg_btf, *arg_btf_id);
+ verbose(env, "%s must be a rcu pointer\n",
+ reg_arg_name(env, argno));
+ arg_name = reg_arg_name(env, argno);
+ actual_type = bpf_diag_reg_type_plain(env, reg->type);
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Use this function with a pointer that is valid in an RCU read lock region.",
+ "the function requires an RCU-protected pointer to %s, but %s is %s",
+ expected_type, arg_name, actual_type);
+ return -EINVAL;
+ }
+ }
+
+ err = process_arg_ptr_to_btf_id(env, reg, argno, arg_type, arg_btf,
+ *arg_btf_id, meta, insn_idx);
+ if (err < 0)
+ return err;
+ break;
+ }
case ARG_PTR_TO_PERCPU_BTF_ID:
if (!reg->btf_id) {
- verbose(env, "Helper has invalid btf_id in R%d\n", regno);
+ verbose(env, "Helper has invalid btf_id in %s\n",
+ reg_arg_name(env, argno));
return -EACCES;
}
meta->ret_btf = reg->btf;
@@ -8918,11 +9060,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
verbose(env, "can't spin_{lock,unlock} in rbtree cb\n");
return -EACCES;
}
- if (meta->func_id == BPF_FUNC_spin_lock) {
+ if (is_helper_call(meta, BPF_FUNC_spin_lock)) {
err = process_spin_lock(env, reg, argno, PROCESS_SPIN_LOCK);
if (err)
return err;
- } else if (meta->func_id == BPF_FUNC_spin_unlock) {
+ } else if (is_helper_call(meta, BPF_FUNC_spin_unlock)) {
err = process_spin_lock(env, reg, argno, 0);
if (err)
return err;
@@ -8936,45 +9078,273 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
if (err)
return err;
break;
+ case ARG_PTR_TO_CTX:
+ if (is_bpf_cast_to_kern_ctx_kfunc(meta)) {
+ err = get_kern_ctx_btf_id(&env->log, resolve_prog_type(env->prog));
+ if (err < 0)
+ return -EINVAL;
+ meta->ret_btf_id = err;
+ }
+ break;
+ case ARG_PTR_TO_ARENA:
+ break;
+ case ARG_PTR_TO_ALLOC_BTF_ID:
+ if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC)) {
+ if (!is_bpf_obj_drop_kfunc(meta->func_id)) {
+ verbose(env, "%s expected for bpf_obj_drop()\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ } else if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU)) {
+ if (!is_bpf_percpu_obj_drop_kfunc(meta->func_id)) {
+ verbose(env, "%s expected for bpf_percpu_obj_drop()\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ }
+ if (!reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass the owned object pointer before it is released or transferred.",
+ "the allocated object pointer in %s must still carry verifier-tracked ownership, but this pointer no longer owns a live resource",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ if (meta->btf == btf_vmlinux) {
+ meta->arg_btf = reg->btf;
+ meta->arg_btf_id = reg->btf_id;
+ }
+ break;
case ARG_PTR_TO_FUNC:
meta->subprogno = reg->subprogno;
break;
case ARG_PTR_TO_MEM:
+ {
+ enum bpf_access_type access_type;
+ bool known_memory;
+
/* 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_mem_reg(env, reg, argno_from_reg(regno), fn->arg_size[arg],
- arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ, meta, NULL);
- if (err)
- return err;
- if (arg_type & MEM_ALIGNED)
- err = check_ptr_alignment(env, reg, 0, fn->arg_size[arg], true);
+ if (!(arg_type & MEM_FIXED_SIZE))
+ break;
+
+ access_type = arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ;
+ if (meta->btf)
+ access_type = BPF_READ | BPF_WRITE;
+
+ err = check_mem_reg(env, reg, argno, arg_size, access_type, meta, &known_memory);
+ if (err < 0) {
+ if (known_memory)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass memory with at least the required number of accessible bytes and suitable read or write access.",
+ "the function expects %u bytes of memory, but the verifier cannot prove that %s provides a range of that size with the required read or write access",
+ arg_size,
+ bpf_diag_reg_type_plain(env, reg->type));
+ else
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass stack, map, context, or other verifier-known memory of the expected type and size, not an integer cast to a pointer.",
+ "the function expects %u bytes of memory, but it is %s and not verifier-known memory",
+ arg_size,
+ bpf_diag_reg_type_plain(env, reg->type));
+ return err;
}
+ if (arg_type & MEM_ALIGNED)
+ err = check_ptr_alignment(env, reg, 0, arg_size, true);
break;
+ }
+ case ARG_CONST_MEM_SIZE:
+ err = process_const_arg(env, reg, argno, meta);
+ if (err < 0) {
+ if (err == -EINVAL)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass a compile-time constant or a value the verifier can prove is constant at this call.",
+ "the function requires this memory size to be a verifier-known constant, but %s is variable on this path",
+ reg_arg_name(env, argno));
+ return err;
+ }
+ fallthrough;
case ARG_MEM_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, NULL);
- break;
case ARG_MEM_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, NULL);
- break;
- case ARG_PTR_TO_DYNPTR:
- err = process_dynptr_func(env, reg, argno, insn_idx, func_id_name(meta->func_id),
- arg_type, &meta->ref_obj, &meta->dynptr);
+ {
+ struct bpf_reg_state *buff_reg = get_func_arg_reg(caller, regs, arg - 1);
+ argno_t buff_argno = argno_from_arg(arg);
+ enum bpf_mem_size_failure failure;
+ u32 access_type;
+ bool zero_size_allowed;
+
+ if (meta->btf && bpf_register_is_null(buff_reg))
+ break;
+
+ access_type = fn->arg_type[arg - 1] & MEM_WRITE ? BPF_WRITE : BPF_READ;
+ if (meta->btf)
+ access_type = BPF_READ | BPF_WRITE;
+ zero_size_allowed = meta->btf || base_type(arg_type) == ARG_MEM_SIZE_OR_ZERO;
+
+ err = check_mem_size_reg(env, buff_reg, reg, buff_argno, argno,
+ access_type, zero_size_allowed, meta, &failure);
+ if (err < 0) {
+ const char *buff_arg, *size_arg;
+
+ buff_arg = bpf_diag_arg_name(env, buff_argno);
+ size_arg = bpf_diag_arg_name(env, argno);
+ verbose(env, "%s and ", reg_arg_name(env, buff_argno));
+ verbose(env, "%s memory, len pair leads to invalid memory access\n",
+ reg_arg_name(env, argno));
+ if (failure == BPF_MEM_SIZE_FAIL_MEMORY) {
+ bpf_diag_call_arg_fmt(env, insn_idx, buff_argno, meta->func_name,
+ "Pass a stack, map, context, or other verifier-known memory pointer, and keep the paired length within that object.",
+ "it is the memory pointer in a memory/length pair with %s, but %s does not provide a verifier-accessible range of the requested length",
+ size_arg, buff_arg);
+ } else if (failure == BPF_MEM_SIZE_FAIL_SIZE) {
+ if (reg_smin(reg) < 0)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.",
+ "the memory size in %s may be negative because its signed minimum is %lld",
+ size_arg, reg_smin(reg));
+ else if (!zero_size_allowed && reg_umin(reg) == 0)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Ensure the memory size is non-zero before this call.",
+ "the memory size in %s may be zero, but the function requires a non-zero size",
+ size_arg);
+ else
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.",
+ "the memory size in %s may reach %llu bytes, but variable memory accesses must stay below %u bytes",
+ size_arg, reg_umax(reg), BPF_MAX_VAR_SIZ);
+ }
+ }
+ break;
+ }
+ case ARG_PTR_TO_DYNPTR: {
+ if (is_bpf_dynptr_clone_kfunc(meta) &&
+ (arg_type & MEM_UNINIT)) {
+ enum bpf_dynptr_type parent_type = meta->dynptr.type;
+
+ if (parent_type == BPF_DYNPTR_TYPE_INVALID) {
+ verifier_bug(env, "no dynptr type for parent of clone");
+ return -EFAULT;
+ }
+
+ arg_type |= (unsigned int)get_dynptr_type_flag(parent_type);
+ }
+
+ err = process_dynptr_func(env, reg, argno, insn_idx, arg_type, meta);
if (err)
return err;
break;
+ }
+ case ARG_PTR_TO_ITER:
+ if (is_bpf_iter_css_task_new_kfunc(meta) &&
+ !check_css_task_iter_allowlist(env)) {
+ verbose(env, "css_task_iter is only allowed in bpf_lsm, bpf_iter and sleepable progs\n");
+ return -EINVAL;
+ }
+ err = process_iter_arg(env, reg, argno, insn_idx, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_LIST_HEAD:
+ if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) &&
+ !reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ return -EINVAL;
+ }
+ err = process_kf_arg_ptr_to_list_head(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_RB_ROOT:
+ if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) &&
+ !reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ return -EINVAL;
+ }
+ err = process_kf_arg_ptr_to_rbtree_root(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_LIST_NODE:
+ if (!(is_kfunc_arg_nonown_allowed(meta->btf, btf_arg) &&
+ type_is_non_owning_ref(reg->type) && !reg_is_referenced(env, reg))) {
+ if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
+ verbose(env, "%s expected pointer to allocated object\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ if (!reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ return -EINVAL;
+ }
+ }
+ err = process_kf_arg_ptr_to_list_node(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_RB_NODE:
+ if (is_bpf_rbtree_add_kfunc(meta->func_id)) {
+ if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
+ verbose(env, "%s expected pointer to allocated object\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+ if (!reg_is_referenced(env, reg)) {
+ verbose(env, "allocated object must be referenced\n");
+ return -EINVAL;
+ }
+ } else {
+ if (!type_is_non_owning_ref(reg->type) &&
+ !reg_is_referenced(env, reg)) {
+ verbose(env, "%s can only take non-owning or refcounted bpf_rb_node pointer\n",
+ meta->func_name);
+ return -EINVAL;
+ }
+ if (in_rbtree_lock_required_cb(env)) {
+ verbose(env, "%s not allowed in rbtree cb\n", meta->func_name);
+ return -EINVAL;
+ }
+ }
+ err = process_kf_arg_ptr_to_rbtree_node(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
case ARG_CONST_ALLOC_SIZE_OR_ZERO:
+ if (meta->btf && is_kfunc_arg_scalar_with_name(meta->btf, btf_arg,
+ "rdonly_buf_size"))
+ meta->r0_rdonly = true;
err = process_const_alloc_mem_size(env, reg, argno, &meta->ret_mem);
- if (err)
+ if (err < 0) {
+ if (meta->btf && err == -EINVAL)
+ bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
+ "Pass a verifier-known constant size for this function's buffer argument.",
+ "the function uses this argument as a return-buffer size, but %s is invalid or variable on this path",
+ reg_arg_name(env, argno));
return err;
+ }
+ break;
+ case ARG_PTR_TO_REFCOUNTED_KPTR:
+ {
+ struct btf_record *rec;
+
+ if (!type_is_non_owning_ref(reg->type))
+ meta->arg_owning_ref = true;
+
+ rec = reg_btf_record(reg);
+ if (!rec) {
+ verifier_bug(env, "Couldn't find btf_record");
+ return -EFAULT;
+ }
+
+ if (rec->refcount_off < 0) {
+ verbose(env, "%s doesn't point to a type with bpf_refcount field\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
+
+ meta->arg_btf = reg->btf;
+ meta->arg_btf_id = reg->btf_id;
break;
+ }
case ARG_PTR_TO_CONST_STR:
{
err = check_arg_const_str(env, reg, argno);
@@ -8982,6 +9352,33 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
return err;
break;
}
+ case ARG_PTR_TO_WORKQUEUE:
+ err = check_map_field_pointer(env, reg, argno, BPF_WORKQUEUE, &meta->map);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_TASK_WORK:
+ err = check_map_field_pointer(env, reg, argno, BPF_TASK_WORK, &meta->map);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_IRQ_FLAG:
+ err = process_irq_flag(env, reg, argno, meta);
+ if (err < 0)
+ return err;
+ break;
+ case ARG_PTR_TO_RES_SPIN_LOCK:
+ {
+ int flags;
+
+ flags = get_bpf_res_spin_lock_kfunc_flags(meta);
+ if (!flags)
+ return -EFAULT;
+ err = process_spin_lock(env, reg, argno, flags);
+ if (err < 0)
+ return err;
+ break;
+ }
case ARG_KPTR_XCHG_DEST:
err = process_kptr_func(env, regno, meta);
if (err)
@@ -8992,6 +9389,37 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
return err;
}
+static int check_func_args(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
+ int insn_idx)
+{
+ struct bpf_func_state *caller = cur_func(env);
+ const struct btf_param *args = NULL;
+ u32 arg, nargs = MAX_BPF_FUNC_REG_ARGS;
+ int err;
+
+ if (meta->btf) {
+ args = btf_params(meta->func_proto);
+ nargs = btf_type_vlen(meta->func_proto);
+ }
+
+ if (nargs > MAX_BPF_FUNC_REG_ARGS) {
+ err = check_outgoing_stack_args(env, caller, nargs, meta->func_name,
+ meta->btf, args);
+ if (err)
+ return err;
+ }
+
+ for (arg = 0; arg < nargs; arg++) {
+ if (meta->fn->arg_type[arg] == ARG_UNUSED)
+ break;
+ err = check_func_arg(env, arg, meta, insn_idx);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static bool may_update_sockmap(struct bpf_verifier_env *env, int func_id)
{
enum bpf_attach_type eatype = env->prog->expected_attach_type;
@@ -9289,7 +9717,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++) {
- if (fn->arg_type[i] == ARG_DONTCARE)
+ if (fn->arg_type[i] == ARG_UNUSED)
break;
if (!arg_type_is_raw_mem(fn->arg_type[i]))
continue;
@@ -9339,7 +9767,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++) {
- if (fn->arg_type[i] == ARG_DONTCARE)
+ if (fn->arg_type[i] == ARG_UNUSED)
break;
if (base_type(fn->arg_type[i]) == ARG_PTR_TO_BTF_ID)
return !!fn->arg_btf_id[i];
@@ -9362,7 +9790,7 @@ static bool check_mem_arg_rw_flag_ok(const struct bpf_func_proto *fn)
for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
enum bpf_arg_type arg_type = fn->arg_type[i];
- if (arg_type == ARG_DONTCARE)
+ if (arg_type == ARG_UNUSED)
break;
if (base_type(arg_type) != ARG_PTR_TO_MEM)
continue;
@@ -9380,7 +9808,7 @@ static bool check_proto_release_reg(const struct bpf_func_proto *fn, struct bpf_
for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
enum bpf_arg_type arg_type = fn->arg_type[i];
- if (arg_type == ARG_DONTCARE)
+ if (arg_type == ARG_UNUSED)
break;
if (arg_type_is_release(arg_type)) {
if (meta->release_regno)
@@ -9392,9 +9820,42 @@ static bool check_proto_release_reg(const struct bpf_func_proto *fn, struct bpf_
return true;
}
-static int check_func_proto(const struct bpf_func_proto *fn, struct bpf_call_arg_meta *meta)
+static bool check_arg_prog_aux(struct bpf_verifier_env *env,
+ const struct bpf_func_proto *proto)
+{
+ bool seen = false;
+ argno_t argno;
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(proto->arg_type); i++) {
+ if (proto->arg_type[i] == ARG_UNUSED)
+ break;
+ if (proto->arg_type[i] != ARG_PTR_TO_PROG_AUX)
+ continue;
+
+ if (seen) {
+ verifier_bug(env, "Only 1 prog->aux argument supported");
+ return false;
+ }
+
+ argno = argno_from_arg(i + 1);
+ if (reg_from_argno(argno) < 0) {
+ verbose(env, "%s prog->aux cannot be a stack argument\n",
+ reg_arg_name(env, argno));
+ return false;
+ }
+
+ seen = true;
+ }
+
+ return true;
+}
+
+static int check_func_proto(struct bpf_verifier_env *env, const struct bpf_func_proto *fn,
+ struct bpf_call_arg_meta *meta)
{
- return check_raw_mode_ok(fn, meta) &&
+ return check_arg_prog_aux(env, fn) &&
+ check_raw_mode_ok(fn, meta) &&
check_arg_pair_ok(fn) &&
check_mem_arg_rw_flag_ok(fn) &&
check_proto_release_reg(fn, meta) &&
@@ -9713,12 +10174,16 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
struct bpf_subprog_info *sub = subprog_info(env, subprog);
struct bpf_func_state *caller = cur_func(env);
struct bpf_verifier_log *log = &env->log;
- struct ref_obj_desc ref_obj = {};
const struct btf_param *args;
const struct btf_type *func, *func_proto;
+ struct bpf_call_arg_meta meta;
u32 i;
int ret, err;
+ /* Leave btf and func_id zero: this is neither a helper nor a kfunc. */
+ memset(&meta, 0, sizeof(meta));
+ meta.func_name = bpf_subprog_name(env, subprog);
+
ret = btf_prepare_func_args(env, subprog);
if (ret) {
if (bpf_in_stack_arg_cnt(sub) > 0) {
@@ -9747,7 +10212,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
struct bpf_reg_state *reg = get_func_arg_reg(caller, regs, i);
struct bpf_subprog_arg_info *arg = &sub->args[i];
- if (arg->arg_type == ARG_ANYTHING) {
+ if (arg->arg_type == ARG_SCALAR) {
if (reg->type != SCALAR_VALUE) {
bpf_log(log, "%s is not a scalar\n", reg_arg_name(env, argno));
return -EINVAL;
@@ -9771,7 +10236,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
return -EINVAL;
}
} else if (base_type(arg->arg_type) == ARG_PTR_TO_MEM) {
- ret = check_func_arg_reg_off(env, reg, argno, ARG_DONTCARE);
+ ret = check_func_arg_reg_off(env, reg, argno, ARG_PTR_TO_MEM);
if (ret < 0)
return ret;
if (check_mem_reg(env, reg, argno, arg->mem_size, BPF_READ | BPF_WRITE, NULL,
@@ -9802,21 +10267,21 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
return ret;
ret = process_dynptr_func(env, reg, argno, env->insn_idx,
- bpf_subprog_name(env, subprog), arg->arg_type,
- &ref_obj, NULL);
+ arg->arg_type, &meta);
if (ret)
return ret;
} else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) {
- struct bpf_call_arg_meta meta;
int err;
if (bpf_register_is_null(reg) && type_may_be_null(arg->arg_type))
continue;
- memset(&meta, 0, sizeof(meta)); /* leave func_id as zero */
- err = check_reg_type(env, reg, argno, arg->arg_type, &arg->btf_id, &meta,
- bpf_subprog_name(env, subprog));
+ err = check_reg_type(env, reg, argno, arg->arg_type, &meta);
err = err ?: check_func_arg_reg_off(env, reg, argno, arg->arg_type);
+ if (!err && base_type(reg->type) == PTR_TO_BTF_ID)
+ err = process_arg_ptr_to_btf_id(env, reg, argno, arg->arg_type,
+ btf_vmlinux, arg->btf_id,
+ &meta, env->insn_idx);
if (err)
return err;
} else {
@@ -10908,7 +11373,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
memset(&meta, 0, sizeof(meta));
- err = check_func_proto(fn, &meta);
+ err = check_func_proto(env, fn, &meta);
if (err) {
verifier_bug(env, "incorrect func proto %s#%d", func_id_name(func_id), func_id);
return err;
@@ -10929,13 +11394,11 @@ 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.func_name = func_id_name(func_id);
meta.fn = fn;
- /* check args */
- for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
- err = check_func_arg(env, i, &meta, insn_idx);
- if (err)
- return err;
- }
+ err = check_func_args(env, &meta, insn_idx);
+ if (err)
+ return err;
err = record_func_map(env, &meta, func_id, insn_idx);
if (err)
@@ -11758,6 +12221,49 @@ static bool btf_type_is_scalar_struct(struct bpf_verifier_env *env,
return btf_struct_is_composed_of(env, btf, t, BTF_MEMBER_SCALAR);
}
+static int resolve_func_arg_type(struct bpf_verifier_env *env,
+ struct bpf_reg_state *reg, u32 arg,
+ struct bpf_call_arg_meta *meta,
+ enum bpf_arg_type *arg_type, u32 *arg_size)
+{
+ argno_t argno = argno_from_arg(arg + 1);
+ const struct btf_param *args;
+ const struct btf_type *ref_t, *resolve_ret;
+ const struct btf *btf;
+ const char *ref_tname;
+ u32 ref_id;
+
+ if (base_type(*arg_type) == ARG_PTR_TO_MAP_VALUE)
+ return resolve_map_arg_type(env, meta, arg_type);
+
+ if (base_type(*arg_type) == ARG_PTR_TO_BTF_ID) {
+ if (!meta->btf || arg_type_is_release(*arg_type) ||
+ base_type(reg->type) == PTR_TO_BTF_ID ||
+ reg2btf_ids[base_type(reg->type)])
+ return 0;
+
+ args = btf_params(meta->func_proto);
+ ref_id = *meta->fn->arg_btf_id[arg];
+ btf = is_kfunc_arg_map(meta->btf, &args[arg]) ? btf_vmlinux : meta->btf;
+ ref_t = btf_type_skip_modifiers(btf, ref_id, &ref_id);
+ ref_tname = btf_name_by_offset(btf, ref_t->name_off);
+
+ if (!btf_type_is_scalar_struct(env, btf, ref_t))
+ return 0;
+
+ resolve_ret = btf_resolve_size(btf, ref_t, arg_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;
+ }
+ *arg_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE | (*arg_type & PTR_MAYBE_NULL);
+ }
+
+ return 0;
+}
+
static void btf_member_path_str(const struct btf *btf, const struct btf_member_path *path,
char *buf, size_t buf_sz)
{
@@ -11777,34 +12283,6 @@ static void btf_member_path_str(const struct btf *btf, const struct btf_member_p
}
}
-enum kfunc_ptr_arg_type {
- KF_ARG_CONST_MEM_SIZE,
- KF_ARG_MEM_SIZE,
- KF_ARG_CONST,
- KF_ARG_CONST_ALLOC_SIZE_OR_ZERO,
- KF_ARG_ANYTHING,
- KF_ARG_PTR_TO_CTX,
- KF_ARG_PTR_TO_ALLOC_BTF_ID, /* Allocated object */
- KF_ARG_PTR_TO_REFCOUNTED_KPTR, /* Refcounted local kptr */
- KF_ARG_PTR_TO_DYNPTR,
- KF_ARG_PTR_TO_ITER,
- KF_ARG_PTR_TO_LIST_HEAD,
- 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_CALLBACK,
- KF_ARG_PTR_TO_RB_ROOT,
- KF_ARG_PTR_TO_RB_NODE,
- KF_ARG_PTR_TO_CONST_STR,
- 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_PTR_TO_ARENA,
-};
-
enum special_kfunc_type {
KF_bpf_obj_new_impl,
KF_bpf_obj_new,
@@ -11872,7 +12350,10 @@ enum special_kfunc_type {
KF_bpf_task_work_schedule_resume,
KF_bpf_arena_alloc_pages,
KF_bpf_arena_free_pages,
+ KF_bpf_arena_reserve_pages,
KF_bpf_session_is_return,
+ KF_bpf_stream_vprintk,
+ KF_bpf_stream_print_stack,
};
BTF_ID_LIST(special_kfunc_list)
@@ -11962,11 +12443,29 @@ BTF_ID(func, bpf_task_work_schedule_signal)
BTF_ID(func, bpf_task_work_schedule_resume)
BTF_ID(func, bpf_arena_alloc_pages)
BTF_ID(func, bpf_arena_free_pages)
+BTF_ID(func, bpf_arena_reserve_pages)
#ifdef CONFIG_BPF_EVENTS
BTF_ID(func, bpf_session_is_return)
#else
BTF_ID_UNUSED
#endif
+BTF_ID(func, bpf_stream_vprintk)
+BTF_ID(func, bpf_stream_print_stack)
+
+static bool is_bpf_cast_to_kern_ctx_kfunc(const struct bpf_call_arg_meta *meta)
+{
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_cast_to_kern_ctx]);
+}
+
+static bool is_bpf_dynptr_clone_kfunc(const struct bpf_call_arg_meta *meta)
+{
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_clone]);
+}
+
+static bool is_bpf_iter_css_task_new_kfunc(const struct bpf_call_arg_meta *meta)
+{
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_iter_css_task_new]);
+}
static bool is_bpf_obj_new_kfunc(u32 func_id)
{
@@ -12029,52 +12528,63 @@ static bool is_kfunc_ret_null(struct bpf_call_arg_meta *meta)
static bool is_kfunc_bpf_rcu_read_lock(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_rcu_read_lock];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_rcu_read_lock]);
}
static bool is_kfunc_bpf_rcu_read_unlock(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_rcu_read_unlock];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_rcu_read_unlock]);
}
static bool is_kfunc_bpf_preempt_disable(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_preempt_disable];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_preempt_disable]);
}
static bool is_kfunc_bpf_preempt_enable(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_preempt_enable];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_preempt_enable]);
}
bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta)
{
- return meta->func_id == special_kfunc_list[KF_bpf_xdp_pull_data];
+ return is_kfunc_call(meta, special_kfunc_list[KF_bpf_xdp_pull_data]);
}
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)
+ const struct btf_param *args, int arg, int nargs,
+ struct bpf_func_proto *proto)
{
- const struct btf_type *t, *ref_t = NULL;
+ const struct btf_type *t, *ref_t = NULL, *resolve_ret;
+ const u32 *ref_id_ptr = NULL;
argno_t argno = argno_from_arg(arg + 1);
const char *ref_tname = NULL;
+ u32 ref_id, type_size;
int arg_type;
+ proto->arg_btf_id[arg] = NULL;
+
+ if (is_kfunc_arg_prog_aux(meta->btf, &args[arg]))
+ return ARG_PTR_TO_PROG_AUX;
+
+ if (is_kfunc_arg_ignore(meta->btf, &args[arg]) || is_kfunc_arg_implicit(meta, arg))
+ return ARG_IGNORE;
+
t = btf_type_skip_modifiers(meta->btf, args[arg].type, NULL);
/* 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;
+ return ARG_CONST_SCALAR;
if (is_kfunc_arg_const_mem_size(meta->btf, &args[arg]))
- return KF_ARG_CONST_MEM_SIZE;
+ return ARG_CONST_MEM_SIZE;
if (is_kfunc_arg_mem_size(meta->btf, &args[arg]))
- return KF_ARG_MEM_SIZE;
+ return 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;
+ return ARG_CONST_ALLOC_SIZE_OR_ZERO;
+ return ARG_SCALAR;
}
if (!btf_type_is_ptr(t)) {
@@ -12082,54 +12592,69 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
reg_arg_name(env, argno), btf_type_str(t));
return -EINVAL;
}
- ref_t = btf_type_skip_modifiers(meta->btf, t->type, NULL);
+ /* Keep a pointer to the BTF field containing the resolved referent ID. */
+ ref_id_ptr = &t->type;
+ ref_t = btf_type_skip_modifiers(meta->btf, *ref_id_ptr, &ref_id);
+ while (*ref_id_ptr != ref_id)
+ ref_id_ptr = &btf_type_by_id(meta->btf, *ref_id_ptr)->type;
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.
+ * arguments, we resolve it to a known bpf_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])
- arg_type = KF_ARG_PTR_TO_CTX;
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_cast_to_kern_ctx]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_session_is_return]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_session_cookie]))
+ arg_type = 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;
+ arg_type = ARG_PTR_TO_CTX;
else if (is_kfunc_arg_alloc_obj(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_ALLOC_BTF_ID;
+ arg_type = 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;
+ arg_type = ARG_PTR_TO_REFCOUNTED_KPTR;
+ else if (is_kfunc_arg_dynptr(meta->btf, &args[arg])) {
+ arg_type = ARG_PTR_TO_DYNPTR;
+
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_skb]))
+ arg_type |= DYNPTR_TYPE_SKB;
+ else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_xdp]))
+ arg_type |= DYNPTR_TYPE_XDP;
+ else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_skb_meta]))
+ arg_type |= DYNPTR_TYPE_SKB_META;
+ else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_from_file]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_file_discard]))
+ /* OBJ_RELEASE for the latter comes from KF_RELEASE below */
+ arg_type |= DYNPTR_TYPE_FILE;
+ } else if (is_kfunc_arg_iter(meta, arg, &args[arg]))
+ arg_type = ARG_PTR_TO_ITER;
else if (is_kfunc_arg_list_head(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_LIST_HEAD;
+ arg_type = ARG_PTR_TO_LIST_HEAD;
else if (is_kfunc_arg_list_node(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_LIST_NODE;
+ arg_type = ARG_PTR_TO_LIST_NODE;
else if (is_kfunc_arg_rbtree_root(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_RB_ROOT;
+ arg_type = ARG_PTR_TO_RB_ROOT;
else if (is_kfunc_arg_rbtree_node(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_RB_NODE;
+ arg_type = ARG_PTR_TO_RB_NODE;
else if (is_kfunc_arg_const_str(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_CONST_STR;
+ arg_type = ARG_PTR_TO_CONST_STR;
else if (is_kfunc_arg_const_map(meta->btf, &args[arg]))
- arg_type = KF_ARG_CONST_MAP_PTR;
+ arg_type = ARG_CONST_MAP_PTR;
else if (is_kfunc_arg_map(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_BTF_ID;
+ arg_type = ARG_PTR_TO_BTF_ID;
else if (is_kfunc_arg_wq(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_WORKQUEUE;
+ arg_type = ARG_PTR_TO_WORKQUEUE;
else if (is_kfunc_arg_timer(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_TIMER;
+ arg_type = ARG_PTR_TO_TIMER;
else if (is_kfunc_arg_task_work(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_TASK_WORK;
+ arg_type = ARG_PTR_TO_TASK_WORK;
else if (is_kfunc_arg_irq_flag(meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_IRQ_FLAG;
+ arg_type = 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;
+ arg_type = ARG_PTR_TO_RES_SPIN_LOCK;
else if (is_kfunc_arg_callback(env, meta->btf, &args[arg]))
- arg_type = KF_ARG_PTR_TO_CALLBACK;
+ arg_type = ARG_PTR_TO_FUNC;
else if (is_kfunc_arg_arena(meta->btf, &args[arg])) {
if (!bpf_jit_supports_arena_args()) {
verbose(env, "JIT does not support kfunc %s() with arena pointer arguments\n",
@@ -12152,7 +12677,7 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
* whether the JIT rebases it to the arena base or preserves NULL.
* The common nullable path below records that verifier property.
*/
- arg_type = KF_ARG_PTR_TO_ARENA;
+ arg_type = ARG_PTR_TO_ARENA;
} 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]))) {
@@ -12162,10 +12687,10 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
reg_arg_name(env, argno), btf_type_str(ref_t), ref_tname);
return -EINVAL;
}
- arg_type = KF_ARG_PTR_TO_MEM;
+ arg_type = ARG_PTR_TO_MEM;
} else if (btf_type_is_struct(ref_t))
- /* 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;
+ /* A pointer to a struct without a size argument is classified as ARG_PTR_TO_BTF_ID */
+ arg_type = ARG_PTR_TO_BTF_ID;
else {
/*
* Otherwise this is a fixed-size memory buffer supported by
@@ -12178,19 +12703,53 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
reg_arg_name(env, argno), btf_type_str(ref_t), ref_tname);
return -EINVAL;
}
- arg_type = KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
+ resolve_ret = btf_resolve_size(meta->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;
+ }
+ proto->arg_size[arg] = type_size;
+ arg_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
}
+ if (is_kfunc_arg_uninit(meta->btf, &args[arg]))
+ arg_type |= MEM_UNINIT;
+
if (is_kfunc_arg_nullable(meta->btf, &args[arg]))
arg_type |= PTR_MAYBE_NULL;
+ /*
+ * Only the first argument of a KF_RELEASE kfunc releases anything, and
+ * bpf_fetch_kfunc_arg_meta() only ever records BPF_REG_1 for it.
+ */
+ if (is_kfunc_release(meta) && arg == 0)
+ arg_type |= OBJ_RELEASE;
+
+ if (base_type(arg_type) == ARG_PTR_TO_BTF_ID) {
+ /* A __map argument names a vmlinux type rather than one from
+ * the kfunc's own BTF.
+ */
+ if (is_kfunc_arg_map(meta->btf, &args[arg]))
+ proto->arg_btf_id[arg] = reg2btf_ids[CONST_PTR_TO_MAP];
+ else
+ proto->arg_btf_id[arg] = ref_id_ptr;
+
+ /* A KF_RCU kfunc accepts an RCU-protected pointer where it would
+ * otherwise demand a referenced or trusted one.
+ */
+ if (is_kfunc_rcu(meta))
+ arg_type |= MEM_RCU;
+ }
+
return arg_type;
}
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;
@@ -12209,47 +12768,38 @@ static int gen_kfunc_arg_proto(struct bpf_verifier_env *env, struct bpf_call_arg
}
for (i = 0; i < nargs; i++) {
- if (is_kfunc_arg_prog_aux(btf, &args[i]) ||
- is_kfunc_arg_ignore(btf, &args[i]) ||
- is_kfunc_arg_implicit(meta, i))
- continue;
-
- arg_type = get_kfunc_arg_type(env, meta, args, i, nargs);
+ arg_type = get_kfunc_arg_type(env, meta, args, i, nargs, proto);
if (arg_type < 0)
return arg_type;
proto->arg_type[i] = arg_type;
}
- return 0;
+ return check_arg_prog_aux(env, proto) ? 0 : -EINVAL;
}
-static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
- struct bpf_reg_state *reg,
- const struct btf_type *ref_t,
- const char *ref_tname, u32 ref_id,
- struct bpf_call_arg_meta *meta,
- int arg, argno_t argno)
+static int process_arg_ptr_to_btf_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+ argno_t argno, enum bpf_arg_type arg_type,
+ const struct btf *arg_btf, u32 arg_btf_id,
+ struct bpf_call_arg_meta *meta, int insn_idx)
{
- const struct btf_type *reg_ref_t;
- bool strict_type_match = false;
+ bool taking_projection, struct_same, strict_type_match = false;
+ const struct btf_type *arg_t, *reg_t;
+ const char *arg_tname, *reg_tname;
const struct btf *reg_btf;
- const char *reg_ref_tname;
- bool taking_projection;
- bool struct_same;
- u32 reg_ref_id;
+ u32 reg_btf_id;
if (base_type(reg->type) == PTR_TO_BTF_ID) {
reg_btf = reg->btf;
- reg_ref_id = reg->btf_id;
+ reg_btf_id = reg->btf_id;
} else {
reg_btf = btf_vmlinux;
- reg_ref_id = *reg2btf_ids[base_type(reg->type)];
+ reg_btf_id = *reg2btf_ids[base_type(reg->type)];
}
- /* Enforce strict type matching for calls to kfuncs that are acquiring
- * or releasing a reference, or are no-cast aliases. We do _not_
- * enforce strict matching for kfuncs by default,
+ /*
+ * Enforce strict type matching for arguments that release a reference,
+ * or are no-cast aliases. We do _not_ enforce strict matching by default,
* as we want to enable BPF programs to pass types that are bitwise
* equivalent without forcing them to explicitly cast with something
* like bpf_cast_to_kern_ctx().
@@ -12271,27 +12821,30 @@ static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
* btf_struct_ids_match() to walk the struct at the 0th offset, and
* resolve types.
*/
- if ((is_kfunc_release(meta) && reg_is_referenced(env, reg)) ||
- btf_type_ids_nocast_alias(&env->log, reg_btf, reg_ref_id, meta->btf, ref_id))
+ if ((arg_type_is_release(arg_type) && !is_helper_call(meta, BPF_FUNC_sk_release)) ||
+ (meta->btf && btf_type_ids_nocast_alias(&env->log, reg_btf, reg_btf_id,
+ arg_btf, arg_btf_id)))
strict_type_match = true;
- WARN_ON_ONCE(is_kfunc_release(meta) && !tnum_is_const(reg->var_off));
+ arg_t = btf_type_skip_modifiers(arg_btf, arg_btf_id, &arg_btf_id);
+ arg_tname = btf_name_by_offset(arg_btf, arg_t->name_off);
+ reg_t = btf_type_skip_modifiers(reg_btf, reg_btf_id, ®_btf_id);
+ reg_tname = btf_name_by_offset(reg_btf, reg_t->name_off);
+
+ struct_same = btf_struct_ids_match(&env->log, reg_btf, reg_btf_id,
+ reg->var_off.value, arg_btf, arg_btf_id,
+ strict_type_match, !type_is_alloc(reg->type));
- reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id, ®_ref_id);
- reg_ref_tname = btf_name_by_offset(reg_btf, reg_ref_t->name_off);
- struct_same = btf_struct_ids_match(&env->log, reg_btf, reg_ref_id, reg->var_off.value,
- meta->btf, ref_id, strict_type_match,
- !type_is_alloc(reg->type));
/* If kfunc is accepting a projection type (ie. __sk_buff), it cannot
* actually use it -- it must cast to the underlying type. So we allow
* caller to pass in the underlying type.
*/
- taking_projection = btf_is_projection_of(ref_tname, reg_ref_tname);
+ taking_projection = meta->btf && btf_is_projection_of(arg_tname, reg_tname);
if (!taking_projection && !struct_same) {
- verbose(env, "kernel function %s %s expected pointer to %s %s but %s has a pointer to %s %s\n",
+ verbose(env, "%s %s expected pointer to %s %s but %s has a pointer to %s %s\n",
meta->func_name, reg_arg_name(env, argno),
- btf_type_str(ref_t), ref_tname, reg_arg_name(env, argno),
- btf_type_str(reg_ref_t), reg_ref_tname);
+ btf_type_str(arg_t), arg_tname,
+ reg_arg_name(env, argno), btf_type_str(reg_t), reg_tname);
return -EINVAL;
}
return 0;
@@ -12303,15 +12856,15 @@ static int process_irq_flag(struct bpf_verifier_env *env, struct bpf_reg_state *
int err, spi, kfunc_class = IRQ_NATIVE_KFUNC;
bool irq_save;
- if (meta->func_id == special_kfunc_list[KF_bpf_local_irq_save] ||
- meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave]) {
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_local_irq_save]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave])) {
irq_save = true;
- if (meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave])
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave]))
kfunc_class = IRQ_LOCK_KFUNC;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_local_irq_restore] ||
- meta->func_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]) {
+ } else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_local_irq_restore]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore])) {
irq_save = false;
- if (meta->func_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore])
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]))
kfunc_class = IRQ_LOCK_KFUNC;
} else {
verifier_bug(env, "unknown irq flags kfunc");
@@ -12504,12 +13057,20 @@ static bool is_bpf_rbtree_api_kfunc(u32 btf_id)
btf_id == special_kfunc_list[KF_bpf_rbtree_right];
}
-static bool is_bpf_res_spin_lock_kfunc(u32 btf_id)
+static int get_bpf_res_spin_lock_kfunc_flags(const struct bpf_call_arg_meta *meta)
{
- return btf_id == special_kfunc_list[KF_bpf_res_spin_lock] ||
- btf_id == special_kfunc_list[KF_bpf_res_spin_unlock] ||
- btf_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave] ||
- btf_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore];
+ int flags = PROCESS_RES_LOCK;
+
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave]))
+ flags |= PROCESS_SPIN_LOCK;
+ else if (!is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock]) &&
+ !is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]))
+ return 0;
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_lock_irqsave]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore]))
+ flags |= PROCESS_LOCK_IRQ;
+ return flags;
}
static bool kfunc_spin_allowed(struct bpf_verifier_env *env, s32 func_id, s16 offset)
@@ -12786,697 +13347,6 @@ static bool check_css_task_iter_allowlist(struct bpf_verifier_env *env)
}
}
-static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
- int insn_idx)
-{
- const char *func_name = meta->func_name, *ref_tname;
- struct bpf_func_state *caller = cur_func(env);
- struct bpf_reg_state *regs = cur_regs(env);
- const struct btf *btf = meta->btf;
- const struct btf_param *args;
- struct btf_record *rec;
- u32 i, nargs;
- int ret;
-
- args = (const struct btf_param *)(meta->func_proto + 1);
- nargs = btf_type_vlen(meta->func_proto);
-
- ret = check_outgoing_stack_args(env, caller, nargs, func_name, btf, args);
- if (ret)
- return ret;
-
- /* Check that BTF function arguments match actual types that the
- * verifier sees.
- */
- for (i = 0; i < nargs; i++) {
- struct bpf_reg_state *reg = get_func_arg_reg(caller, regs, i);
- const struct btf_type *t, *ref_t, *resolve_ret;
- enum bpf_arg_type arg_type = ARG_DONTCARE;
- argno_t argno = argno_from_arg(i + 1);
- int regno = reg_from_argno(argno);
- bool btf_id_fixed_off_ok = true;
- u32 ref_id = args[i].type, type_size;
- int kf_arg_type = meta->fn->arg_type[i];
-
- if (is_kfunc_arg_prog_aux(btf, &args[i])) {
- /* Reject repeated use bpf_prog_aux */
- if (meta->arg_prog) {
- verifier_bug(env, "Only 1 prog->aux argument supported per-kfunc");
- return -EFAULT;
- }
- if (regno < 0) {
- verbose(env, "%s prog->aux cannot be a stack argument\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- meta->arg_prog = true;
- cur_aux(env)->arg_prog = regno;
- continue;
- }
-
- if (is_kfunc_arg_ignore(btf, &args[i]) || is_kfunc_arg_implicit(meta, i))
- continue;
-
- t = btf_type_skip_modifiers(btf, args[i].type, NULL);
-
- 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);
- }
-
- if (btf_type_is_ptr(t) &&
- (bpf_register_is_null(reg) || type_may_be_null(reg->type)) &&
- !type_may_be_null(kf_arg_type)) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, args[i].type);
- verbose(env, "Possibly NULL pointer passed to trusted %s\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Add a NULL check and call the kfunc only on the non-NULL path.",
- "the pointer may be NULL, but this kfunc requires a non-NULL value of type %s",
- expected_type);
- return -EACCES;
- }
-
- if (regno == meta->release_regno && !is_kfunc_arg_dynptr(meta->btf, &args[i]) &&
- !reg_is_referenced(env, reg) && !bpf_register_is_null(reg)) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- verbose(env, "release kfunc %s expects referenced PTR_TO_BTF_ID passed to %s\n",
- func_name, reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass the resource-owning pointer returned by the matching acquire kfunc, and avoid calling the release kfunc after ownership has already been transferred or released.",
- "release kfuncs require a resource-owning value of type %s returned by a matching acquire kfunc",
- expected_type);
- return -EINVAL;
- }
-
- if (reg_is_referenced(env, reg))
- update_ref_obj(&meta->ref_obj, reg);
-
- if (bpf_register_is_null(reg) && type_may_be_null(kf_arg_type))
- continue;
-
- 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:
- case KF_ARG_CONST_MEM_SIZE:
- case KF_ARG_MEM_SIZE:
- case KF_ARG_ANYTHING:
- case KF_ARG_CONST_ALLOC_SIZE_OR_ZERO:
- case KF_ARG_PTR_TO_ALLOC_BTF_ID:
- case KF_ARG_PTR_TO_BTF_ID:
- 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_CALLBACK:
- case KF_ARG_PTR_TO_CONST_STR:
- case KF_ARG_PTR_TO_WORKQUEUE:
- case KF_ARG_PTR_TO_TIMER:
- case KF_ARG_PTR_TO_TASK_WORK:
- case KF_ARG_PTR_TO_IRQ_FLAG:
- case KF_ARG_PTR_TO_RES_SPIN_LOCK:
- case KF_ARG_PTR_TO_ARENA:
- break;
- case KF_ARG_PTR_TO_DYNPTR:
- arg_type = ARG_PTR_TO_DYNPTR;
- break;
- case KF_ARG_PTR_TO_CTX:
- arg_type = ARG_PTR_TO_CTX;
- break;
- case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
- arg_type = ARG_PTR_TO_BTF_ID;
- btf_id_fixed_off_ok = false;
- break;
- default:
- verifier_bug(env, "unknown kfunc arg type %d", kf_arg_type);
- return -EFAULT;
- }
-
- if (regno == meta->release_regno)
- arg_type |= OBJ_RELEASE;
- ret = __check_func_arg_reg_off(env, reg, argno, arg_type,
- btf_id_fixed_off_ok);
- if (ret < 0)
- return ret;
-
- switch (base_type(kf_arg_type)) {
- case KF_ARG_CONST:
- if (reg->type != SCALAR_VALUE) {
- verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an integer scalar value for this argument, not a pointer or resource object.",
- "the kfunc expects an integer scalar, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
-
- ret = process_const_arg(env, reg, argno, meta);
- if (ret < 0) {
- if (ret == -EINVAL)
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a compile-time constant or a value the verifier can prove is constant at this call.",
- "the kfunc requires this scalar argument to be a verifier-known constant, but %s is variable on this path",
- reg_arg_name(env, argno));
- 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));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an integer scalar value for this argument, not a pointer or resource object.",
- "the kfunc expects an integer scalar, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- 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));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an integer scalar value for this argument, not a pointer or resource object.",
- "the kfunc expects an integer scalar, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- 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) {
- if (ret == -EINVAL)
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a verifier-known constant size for this kfunc buffer argument.",
- "the kfunc uses this argument as a return-buffer size, but %s is invalid or variable on this path",
- reg_arg_name(env, argno));
- return ret;
- }
- break;
- case KF_ARG_PTR_TO_CTX:
- if (reg->type != PTR_TO_CTX) {
- verbose(env, "%s expected pointer to ctx, but got %s\n",
- reg_arg_name(env, argno), reg_type_str(env, reg->type));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass the original program context pointer or preserve it before modifying registers.",
- "the kfunc expects a context pointer, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
-
- if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) {
- ret = get_kern_ctx_btf_id(&env->log, resolve_prog_type(env->prog));
- if (ret < 0)
- return -EINVAL;
- meta->ret_btf_id = ret;
- }
- break;
- case KF_ARG_PTR_TO_ARENA:
- if (reg->type != PTR_TO_ARENA && reg->type != SCALAR_VALUE) {
- verbose(env, "%s is not a pointer to arena or scalar\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- break;
- case KF_ARG_PTR_TO_ALLOC_BTF_ID:
- if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC)) {
- if (!is_bpf_obj_drop_kfunc(meta->func_id)) {
- verbose(env, "%s expected for bpf_obj_drop()\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- } else if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU)) {
- if (!is_bpf_percpu_obj_drop_kfunc(meta->func_id)) {
- verbose(env, "%s expected for bpf_percpu_obj_drop()\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- } else {
- verbose(env, "%s expected pointer to allocated object\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a pointer returned by the matching BPF object allocation path.",
- "the kfunc expects an allocated object pointer, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- if (!reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass the owned object pointer before it is released or transferred.",
- "the allocated object pointer in %s must still carry verifier-tracked ownership, but this pointer no longer owns a live resource",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (meta->btf == btf_vmlinux) {
- meta->arg_btf = reg->btf;
- meta->arg_btf_id = reg->btf_id;
- }
- break;
- case KF_ARG_PTR_TO_DYNPTR:
- {
- enum bpf_arg_type dynptr_arg_type = ARG_PTR_TO_DYNPTR;
-
- if (is_kfunc_arg_uninit(btf, &args[i]))
- dynptr_arg_type |= MEM_UNINIT;
-
- if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {
- dynptr_arg_type |= DYNPTR_TYPE_SKB;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) {
- dynptr_arg_type |= DYNPTR_TYPE_XDP;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb_meta]) {
- dynptr_arg_type |= DYNPTR_TYPE_SKB_META;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_file]) {
- dynptr_arg_type |= DYNPTR_TYPE_FILE;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_file_discard]) {
- dynptr_arg_type |= DYNPTR_TYPE_FILE | OBJ_RELEASE;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_clone] &&
- (dynptr_arg_type & MEM_UNINIT)) {
- enum bpf_dynptr_type parent_type = meta->dynptr.type;
-
- if (parent_type == BPF_DYNPTR_TYPE_INVALID) {
- verifier_bug(env, "no dynptr type for parent of clone");
- return -EFAULT;
- }
-
- dynptr_arg_type |= (unsigned int)get_dynptr_type_flag(parent_type);
- }
-
- ret = process_dynptr_func(env, reg, argno, insn_idx, func_name,
- dynptr_arg_type, &meta->ref_obj, &meta->dynptr);
- if (ret < 0)
- return ret;
- break;
- }
- case KF_ARG_PTR_TO_ITER:
- if (meta->func_id == special_kfunc_list[KF_bpf_iter_css_task_new]) {
- if (!check_css_task_iter_allowlist(env)) {
- verbose(env, "css_task_iter is only allowed in bpf_lsm, bpf_iter and sleepable progs\n");
- return -EINVAL;
- }
- }
- ret = process_iter_arg(env, reg, argno, insn_idx, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_LIST_HEAD:
- if (reg->type != PTR_TO_MAP_VALUE &&
- reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s expected pointer to map value or allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) &&
- !reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- return -EINVAL;
- }
- ret = process_kf_arg_ptr_to_list_head(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_RB_ROOT:
- if (reg->type != PTR_TO_MAP_VALUE &&
- reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s expected pointer to map value or allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) &&
- !reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- return -EINVAL;
- }
- ret = process_kf_arg_ptr_to_rbtree_root(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_LIST_NODE:
- if (is_kfunc_arg_nonown_allowed(btf, &args[i]) &&
- type_is_non_owning_ref(reg->type) && !reg_is_referenced(env, reg)) {
- /* Allow bpf_list_front/back return value for
- * __nonown_allowed list-node arguments.
- */
- goto check_ok;
- }
- if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s expected pointer to allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (!reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- return -EINVAL;
- }
-check_ok:
- ret = process_kf_arg_ptr_to_list_node(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_RB_NODE:
- if (is_bpf_rbtree_add_kfunc(meta->func_id)) {
- if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s expected pointer to allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- if (!reg_is_referenced(env, reg)) {
- verbose(env, "allocated object must be referenced\n");
- return -EINVAL;
- }
- } else {
- if (!type_is_non_owning_ref(reg->type) &&
- !reg_is_referenced(env, reg)) {
- verbose(env, "%s can only take non-owning or refcounted bpf_rb_node pointer\n", func_name);
- return -EINVAL;
- }
- if (in_rbtree_lock_required_cb(env)) {
- verbose(env, "%s not allowed in rbtree cb\n", func_name);
- return -EINVAL;
- }
- }
-
- ret = process_kf_arg_ptr_to_rbtree_node(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_CONST_MAP_PTR:
- if (base_type(reg->type) != CONST_PTR_TO_MAP ||
- type_may_be_null(reg->type)) {
- verbose(env, "pointer in %s isn't map pointer\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- ret = process_map_ptr_arg(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- 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) ||
- bpf_type_has_unsafe_modifiers(reg->type)) {
- if (!is_kfunc_rcu(meta)) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- verbose(env, "%s must be referenced or trusted\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a pointer acquired from a verifier-tracked source, or call this kfunc only inside the required protection if it accepts RCU pointers.",
- "the kfunc requires a trusted or resource-owning pointer to %s, but %s is %s",
- expected_type,
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- if (!is_rcu_reg(reg)) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- verbose(env, "%s must be a rcu pointer\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Use this kfunc with a pointer that is valid in an RCU read lock region.",
- "the kfunc requires an RCU-protected pointer to %s, but %s is %s",
- expected_type,
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- 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)) {
- enum bpf_reg_type reg2btf_type = lookup_reg2btf_ids(ref_id);
- const char *expected_type;
-
- 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");
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a verifier-tracked pointer to the expected kernel object type, not a pointer to stack storage or another memory buffer.",
- "the kfunc expects a pointer to %s, but this argument is %s and cannot be used as that kernel object pointer",
- expected_type,
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
-
- /*
- * 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) {
- bool known_memory;
-
- 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, &known_memory);
- if (ret < 0) {
- const char *expected_type;
-
- expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
- if (known_memory)
- bpf_diag_call_arg_fmt(
- env, insn_idx, argno, func_name,
- "Pass memory with at least the required number of accessible bytes and suitable read and write access.",
- "the kfunc expects %u bytes of memory for %s, but the verifier cannot prove that %s provides a readable and writable range of that size",
- type_size, expected_type,
- bpf_diag_reg_type_plain(env, reg->type));
- else
- bpf_diag_call_arg_fmt(
- env, insn_idx, argno, func_name,
- "Pass stack, map, context, or other verifier-known memory of the expected type and size, not an integer cast to a pointer.",
- "the kfunc expects %u bytes of memory for %s, but it is %s and not verifier-known memory",
- type_size, expected_type,
- bpf_diag_reg_type_plain(env, reg->type));
- return ret;
- }
- }
- break;
- case KF_ARG_CONST_MEM_SIZE:
- ret = process_const_arg(env, reg, argno, meta);
- if (ret < 0) {
- if (ret == -EINVAL)
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a compile-time constant or a value the verifier can prove is constant at this call.",
- "the kfunc requires this memory size to be a verifier-known constant, but %s is variable on this path",
- reg_arg_name(env, argno));
- return ret;
- }
- fallthrough;
- case KF_ARG_MEM_SIZE:
- {
- struct bpf_reg_state *buff_reg = get_func_arg_reg(caller, regs, i - 1);
- struct bpf_reg_state *size_reg = reg;
- argno_t buff_argno = argno_from_arg(i);
- enum bpf_mem_size_failure failure;
-
- if (reg->type != SCALAR_VALUE) {
- verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an integer scalar length for this memory argument.",
- "the kfunc expects a scalar memory size, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
-
- if (bpf_register_is_null(buff_reg))
- break;
-
- ret = check_mem_size_reg(env, buff_reg, size_reg, buff_argno, argno,
- BPF_READ | BPF_WRITE, true, meta, &failure);
- if (ret < 0) {
- const char *buff_arg, *size_arg;
-
- buff_arg = bpf_diag_arg_name(env, buff_argno);
- size_arg = bpf_diag_arg_name(env, argno);
- verbose(env, "%s and ", reg_arg_name(env, buff_argno));
- verbose(env, "%s memory, len pair leads to invalid memory access\n",
- reg_arg_name(env, argno));
- if (failure == BPF_MEM_SIZE_FAIL_MEMORY) {
- bpf_diag_call_arg_fmt(env, insn_idx, buff_argno, func_name,
- "Pass a stack, map, context, or other verifier-known memory pointer, and keep the paired length within that object.",
- "it is the memory pointer in a memory/length pair with %s, but %s does not describe verifier-readable memory for the requested length",
- size_arg, buff_arg);
- } else if (failure == BPF_MEM_SIZE_FAIL_SIZE) {
- if (reg_smin(size_reg) < 0)
- bpf_diag_call_arg_fmt(
- env, insn_idx, argno, func_name,
- "Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.",
- "the memory size in %s may be negative because its signed minimum is %lld",
- size_arg, reg_smin(size_reg));
- else
- bpf_diag_call_arg_fmt(
- env, insn_idx, argno, func_name,
- "Constrain the memory size to a non-negative value smaller than BPF_MAX_VAR_SIZ before this call.",
- "the memory size in %s may reach %llu bytes, but variable memory accesses must stay below %u bytes",
- size_arg, reg_umax(size_reg), BPF_MAX_VAR_SIZ);
- }
- return ret;
- }
- 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));
- return -EINVAL;
- }
- meta->subprogno = reg->subprogno;
- break;
- case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
- if (!type_is_ptr_alloc_obj(reg->type)) {
- verbose(env, "%s is neither owning or non-owning ref\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass an owning or non-owning pointer to a BPF-managed object containing a bpf_refcount field.",
- "the kfunc expects a pointer to a BPF-managed refcounted object, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- if (!type_is_non_owning_ref(reg->type))
- meta->arg_owning_ref = true;
-
- rec = reg_btf_record(reg);
- if (!rec) {
- verifier_bug(env, "Couldn't find btf_record");
- return -EFAULT;
- }
-
- if (rec->refcount_off < 0) {
- verbose(env, "%s doesn't point to a type with bpf_refcount field\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
-
- meta->arg_btf = reg->btf;
- meta->arg_btf_id = reg->btf_id;
- break;
- case KF_ARG_PTR_TO_CONST_STR:
- if (reg->type != PTR_TO_MAP_VALUE) {
- verbose(env, "%s doesn't point to a const string\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass a constant string pointer that the verifier recognizes, such as a string stored in a read-only map value.",
- "the kfunc expects a pointer to a constant string stored in verifier-known memory, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- ret = check_arg_const_str(env, reg, argno);
- if (ret)
- return ret;
- break;
- case KF_ARG_PTR_TO_WORKQUEUE:
- if (reg->type != PTR_TO_MAP_VALUE) {
- verbose(env, "%s doesn't point to a map value\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- ret = check_map_field_pointer(env, reg, argno, BPF_WORKQUEUE, &meta->map);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_TIMER:
- if (reg->type != PTR_TO_MAP_VALUE) {
- verbose(env, "%s doesn't point to a map value\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- ret = process_timer_func(env, reg, argno, &meta->map);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_TASK_WORK:
- if (reg->type != PTR_TO_MAP_VALUE) {
- verbose(env, "%s doesn't point to a map value\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
- ret = check_map_field_pointer(env, reg, argno, BPF_TASK_WORK, &meta->map);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_IRQ_FLAG:
- if (reg->type != PTR_TO_STACK) {
- verbose(env, "%s doesn't point to an irq flag on stack\n",
- reg_arg_name(env, argno));
- bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
- "Pass the same stack slot used by bpf_local_irq_save() or bpf_res_spin_lock_irqsave().",
- "the kfunc expects a stack pointer to an IRQ flag slot, but %s is %s",
- reg_arg_name(env, argno),
- bpf_diag_reg_type_plain(env, reg->type));
- return -EINVAL;
- }
- ret = process_irq_flag(env, reg, argno, meta);
- if (ret < 0)
- return ret;
- break;
- case KF_ARG_PTR_TO_RES_SPIN_LOCK:
- {
- int flags = PROCESS_RES_LOCK;
-
- if (reg->type != PTR_TO_MAP_VALUE && reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
- verbose(env, "%s doesn't point to map value or allocated object\n",
- reg_arg_name(env, argno));
- return -EINVAL;
- }
-
- if (!is_bpf_res_spin_lock_kfunc(meta->func_id))
- return -EFAULT;
- if (meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock] ||
- meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave])
- flags |= PROCESS_SPIN_LOCK;
- if (meta->func_id == special_kfunc_list[KF_bpf_res_spin_lock_irqsave] ||
- meta->func_id == special_kfunc_list[KF_bpf_res_spin_unlock_irqrestore])
- flags |= PROCESS_LOCK_IRQ;
- ret = process_spin_lock(env, reg, argno, flags);
- if (ret < 0)
- return ret;
- break;
- }
- }
- }
-
- return 0;
-}
int bpf_fetch_kfunc_arg_meta(struct bpf_verifier_env *env,
s32 func_id,
@@ -13808,12 +13678,12 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg
struct btf_field *field = meta->arg_rbtree_root.field;
mark_reg_graph_node(regs, BPF_REG_0, &field->graph_root);
- } else if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) {
+ } else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_cast_to_kern_ctx])) {
mark_reg_known_zero(env, regs, BPF_REG_0);
regs[BPF_REG_0].type = PTR_TO_BTF_ID | PTR_TRUSTED;
regs[BPF_REG_0].btf = desc_btf;
regs[BPF_REG_0].btf_id = meta->ret_btf_id;
- } else if (meta->func_id == special_kfunc_list[KF_bpf_rdonly_cast]) {
+ } else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_rdonly_cast])) {
ret_t = btf_type_by_id(desc_btf, meta->arg_constant.value);
if (!ret_t) {
verbose(env, "Unknown type ID %lld passed to kfunc bpf_rdonly_cast\n",
@@ -13833,8 +13703,8 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg
"kfunc bpf_rdonly_cast type ID argument must be of a struct or void\n");
return -EINVAL;
}
- } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_slice] ||
- meta->func_id == special_kfunc_list[KF_bpf_dynptr_slice_rdwr]) {
+ } else if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_slice]) ||
+ is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_slice_rdwr])) {
enum bpf_type_flag type_flag = get_dynptr_type_flag(meta->dynptr.type);
mark_reg_known_zero(env, regs, BPF_REG_0);
@@ -13849,7 +13719,7 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg
/* PTR_MAYBE_NULL will be added when is_kfunc_ret_null is checked */
regs[BPF_REG_0].type = PTR_TO_MEM | type_flag;
- if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_slice]) {
+ if (is_kfunc_call(meta, special_kfunc_list[KF_bpf_dynptr_slice])) {
regs[BPF_REG_0].type |= MEM_RDONLY;
} else {
/* this will set env->seen_direct_write to true */
@@ -13969,7 +13839,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
insn_aux->non_sleepable = true;
/* Check the arguments */
- err = check_kfunc_args(env, &meta, insn_idx);
+ err = check_func_args(env, &meta, insn_idx);
if (err < 0)
return err;
@@ -17823,7 +17693,7 @@ bool bpf_get_call_summary(struct bpf_verifier_env *env, struct bpf_insn *call,
cs->is_void = fn->ret_type == RET_VOID;
cs->num_params = 0;
for (i = 0; i < ARRAY_SIZE(fn->arg_type); ++i) {
- if (fn->arg_type[i] == ARG_DONTCARE)
+ if (fn->arg_type[i] == ARG_UNUSED)
break;
cs->num_params++;
}
@@ -19619,7 +19489,7 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
}
/* Also ensure the callback only has a single scalar argument. */
- if (sub->arg_cnt != 1 || sub->args[0].arg_type != ARG_ANYTHING) {
+ if (sub->arg_cnt != 1 || sub->args[0].arg_type != ARG_SCALAR) {
verbose(env, "exception cb only supports single integer argument\n");
ret = -EINVAL;
goto out;
@@ -19632,7 +19502,7 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
if (arg->arg_type == ARG_PTR_TO_CTX) {
reg->type = PTR_TO_CTX;
mark_reg_known_zero(env, regs, i);
- } else if (arg->arg_type == ARG_ANYTHING) {
+ } else if (arg->arg_type == ARG_SCALAR) {
reg->type = SCALAR_VALUE;
mark_reg_unknown(env, regs, i);
} else if (arg->arg_type == ARG_PTR_TO_DYNPTR) {
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 29260951aa871..e414858581d04 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -195,7 +195,7 @@ static const struct bpf_func_proto bpf_override_return_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
#endif
@@ -222,7 +222,7 @@ const struct bpf_func_proto bpf_probe_read_user_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static __always_inline int
@@ -259,7 +259,7 @@ const struct bpf_func_proto bpf_probe_read_user_str_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_probe_read_kernel, void *, dst, u32, size,
@@ -274,7 +274,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static __always_inline int
@@ -309,7 +309,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_str_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
@@ -329,7 +329,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_probe_read_compat_str, void *, dst, u32, size,
@@ -348,7 +348,7 @@ static const struct bpf_func_proto bpf_probe_read_compat_str_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
@@ -381,7 +381,7 @@ static const struct bpf_func_proto bpf_probe_write_user_proto = {
.func = bpf_probe_write_user,
.gpl_only = true,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE,
};
@@ -560,7 +560,7 @@ static const struct bpf_func_proto bpf_seq_printf_btf_proto = {
.arg1_btf_id = &btf_seq_file_ids[0],
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static __always_inline int
@@ -606,7 +606,7 @@ const struct bpf_func_proto bpf_perf_event_read_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_perf_event_read_value, struct bpf_map *, map, u64, flags,
@@ -631,7 +631,7 @@ static const struct bpf_func_proto bpf_perf_event_read_value_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -728,7 +728,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -914,7 +914,7 @@ const struct bpf_func_proto bpf_send_signal_proto = {
.func = bpf_send_signal,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_send_signal_thread, u32, sig)
@@ -926,7 +926,7 @@ const struct bpf_func_proto bpf_send_signal_thread_proto = {
.func = bpf_send_signal_thread,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_d_path, const struct path *, path, char *, buf, u32, sz)
@@ -1056,7 +1056,7 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = {
.arg2_type = ARG_MEM_SIZE,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_get_func_ip_tracing, void *, ctx)
@@ -1236,7 +1236,7 @@ static const struct bpf_func_proto bpf_get_func_arg_proto = {
.func = get_func_arg,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg3_size = sizeof(u64),
};
@@ -1419,7 +1419,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_tp = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -1444,7 +1444,7 @@ static const struct bpf_func_proto bpf_get_stackid_proto_tp = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_get_stack_tp, void *, tp_buff, void *, buf, u32, size,
@@ -1463,7 +1463,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_tp = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
@@ -1567,7 +1567,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
@@ -1644,7 +1644,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_raw_tp = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -1676,7 +1676,7 @@ static const struct bpf_func_proto bpf_get_stackid_proto_raw_tp = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_get_stack_raw_tp, struct bpf_raw_tracepoint_args *, args,
@@ -1702,7 +1702,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 1d295a8769fad..ad0f8f2222226 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -333,7 +333,7 @@ const struct bpf_func_proto bpf_sk_storage_get_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_sk_storage_get_cg_sock_proto = {
@@ -343,7 +343,7 @@ const struct bpf_func_proto bpf_sk_storage_get_cg_sock_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_PTR_TO_CTX, /* context is 'struct sock' */
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
const struct bpf_func_proto bpf_sk_storage_delete_proto = {
@@ -408,7 +408,7 @@ const struct bpf_func_proto bpf_sk_storage_get_tracing_proto = {
.arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL,
.arg2_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
.allowed = bpf_sk_storage_tracing_allowed,
};
diff --git a/net/core/filter.c b/net/core/filter.c
index 61940e7535523..89f8755989c5c 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1746,10 +1746,10 @@ static const struct bpf_func_proto bpf_skb_store_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
int __bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from,
@@ -1783,7 +1783,7 @@ static const struct bpf_func_proto bpf_skb_load_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -1822,7 +1822,7 @@ static const struct bpf_func_proto bpf_flow_dissector_load_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -1866,10 +1866,10 @@ static const struct bpf_func_proto bpf_skb_load_bytes_relative_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_skb_pull_data, struct sk_buff *, skb, u32, len)
@@ -1891,7 +1891,7 @@ static const struct bpf_func_proto bpf_skb_pull_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_sk_fullsock, struct sock *, sk)
@@ -1931,7 +1931,7 @@ static const struct bpf_func_proto sk_skb_pull_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_l3_csum_replace, struct sk_buff *, skb, u32, offset,
@@ -1972,10 +1972,10 @@ static const struct bpf_func_proto bpf_l3_csum_replace_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_l4_csum_replace, struct sk_buff *, skb, u32, offset,
@@ -2026,10 +2026,10 @@ static const struct bpf_func_proto bpf_l4_csum_replace_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_csum_diff, __be32 *, from, u32, from_size,
@@ -2067,7 +2067,7 @@ static const struct bpf_func_proto bpf_csum_diff_proto = {
.arg2_type = ARG_MEM_SIZE_OR_ZERO,
.arg3_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE_OR_ZERO,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_csum_update, struct sk_buff *, skb, __wsum, csum)
@@ -2087,7 +2087,7 @@ static const struct bpf_func_proto bpf_csum_update_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_csum_level, struct sk_buff *, skb, u64, level)
@@ -2121,7 +2121,7 @@ static const struct bpf_func_proto bpf_csum_level_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
static inline int __bpf_rx_skb(struct net_device *dev, struct sk_buff *skb)
@@ -2506,8 +2506,8 @@ static const struct bpf_func_proto bpf_clone_redirect_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
static struct net_device *skb_get_peer_dev(struct net_device *dev)
@@ -2575,8 +2575,8 @@ static const struct bpf_func_proto bpf_redirect_proto = {
.func = bpf_redirect,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
- .arg2_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_redirect_peer, u32, ifindex, u64, flags)
@@ -2597,8 +2597,8 @@ static const struct bpf_func_proto bpf_redirect_peer_proto = {
.func = bpf_redirect_peer,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
- .arg2_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_redirect_neigh, u32, ifindex, struct bpf_redir_neigh *, params,
@@ -2625,10 +2625,10 @@ static const struct bpf_func_proto bpf_redirect_neigh_proto = {
.func = bpf_redirect_neigh,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
.arg2_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_msg_apply_bytes, struct sk_msg *, msg, u32, bytes)
@@ -2642,7 +2642,7 @@ static const struct bpf_func_proto bpf_msg_apply_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_msg_cork_bytes, struct sk_msg *, msg, u32, bytes)
@@ -2701,7 +2701,7 @@ static const struct bpf_func_proto bpf_msg_cork_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
@@ -2836,9 +2836,9 @@ static const struct bpf_func_proto bpf_msg_pull_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
@@ -3001,9 +3001,9 @@ static const struct bpf_func_proto bpf_msg_push_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
static void sk_msg_shift_left(struct sk_msg *msg, int i)
@@ -3185,9 +3185,9 @@ static const struct bpf_func_proto bpf_msg_pop_data_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
#ifdef CONFIG_CGROUP_NET_CLASSID
@@ -3292,7 +3292,7 @@ static const struct bpf_func_proto bpf_set_hash_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_skb_vlan_push, struct sk_buff *, skb, __be16, vlan_proto,
@@ -3318,8 +3318,8 @@ static const struct bpf_func_proto bpf_skb_vlan_push_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_skb_vlan_pop, struct sk_buff *, skb)
@@ -3532,8 +3532,8 @@ static const struct bpf_func_proto bpf_skb_change_proto_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_skb_change_type, struct sk_buff *, skb, u32, pkt_type)
@@ -3552,7 +3552,7 @@ static const struct bpf_func_proto bpf_skb_change_type_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
static u32 bpf_skb_net_base_len(const struct sk_buff *skb)
@@ -3839,9 +3839,9 @@ static const struct bpf_func_proto sk_skb_adjust_room_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
@@ -3944,9 +3944,9 @@ static const struct bpf_func_proto bpf_skb_adjust_room_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
static u32 __bpf_skb_min_len(const struct sk_buff *skb)
@@ -4040,8 +4040,8 @@ static const struct bpf_func_proto bpf_skb_change_tail_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(sk_skb_change_tail, struct sk_buff *, skb, u32, new_len,
@@ -4055,8 +4055,8 @@ static const struct bpf_func_proto sk_skb_change_tail_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
static inline int __bpf_skb_change_head(struct sk_buff *skb, u32 head_room,
@@ -4107,8 +4107,8 @@ static const struct bpf_func_proto bpf_skb_change_head_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(sk_skb_change_head, struct sk_buff *, skb, u32, head_room,
@@ -4122,8 +4122,8 @@ static const struct bpf_func_proto sk_skb_change_head_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_xdp_get_buff_len, struct xdp_buff*, xdp)
@@ -4178,7 +4178,7 @@ static const struct bpf_func_proto bpf_xdp_adjust_head_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off,
@@ -4282,7 +4282,7 @@ static const struct bpf_func_proto bpf_xdp_load_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -4314,7 +4314,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE,
};
@@ -4453,7 +4453,7 @@ static const struct bpf_func_proto bpf_xdp_adjust_tail_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_2(bpf_xdp_adjust_meta, struct xdp_buff *, xdp, int, offset)
@@ -4480,7 +4480,7 @@ static const struct bpf_func_proto bpf_xdp_adjust_meta_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
/**
@@ -4825,8 +4825,8 @@ static const struct bpf_func_proto bpf_xdp_redirect_proto = {
.func = bpf_xdp_redirect,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_ANYTHING,
- .arg2_type = ARG_ANYTHING,
+ .arg1_type = ARG_SCALAR,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_xdp_redirect_map, struct bpf_map *, map, u64, key,
@@ -4840,8 +4840,8 @@ static const struct bpf_func_proto bpf_xdp_redirect_map_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
static unsigned long bpf_skb_copy(void *dst_buff, const void *skb,
@@ -4877,7 +4877,7 @@ static const struct bpf_func_proto bpf_skb_event_output_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -4891,7 +4891,7 @@ const struct bpf_func_proto bpf_skb_output_proto = {
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &bpf_skb_output_btf_ids[0],
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -4977,7 +4977,7 @@ static const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_skb_get_tunnel_opt, struct sk_buff *, skb, u8 *, to, u32, size)
@@ -5094,7 +5094,7 @@ static const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_skb_set_tunnel_opt, struct sk_buff *, skb,
@@ -5175,7 +5175,7 @@ static const struct bpf_func_proto bpf_skb_under_cgroup_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
#ifdef CONFIG_SOCK_CGROUP_DATA
@@ -5232,7 +5232,7 @@ static const struct bpf_func_proto bpf_skb_ancestor_cgroup_id_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_sk_cgroup_id, struct sock *, sk)
@@ -5257,7 +5257,7 @@ static const struct bpf_func_proto bpf_sk_ancestor_cgroup_id_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
#endif
@@ -5291,7 +5291,7 @@ static const struct bpf_func_proto bpf_xdp_event_output_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -5305,7 +5305,7 @@ const struct bpf_func_proto bpf_xdp_output_proto = {
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &bpf_xdp_output_btf_ids[0],
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE_OR_ZERO,
};
@@ -5853,8 +5853,8 @@ const struct bpf_func_proto bpf_sk_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5870,8 +5870,8 @@ const struct bpf_func_proto bpf_sk_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5894,8 +5894,8 @@ const struct bpf_func_proto bpf_sk_setsockopt_nodelay_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5911,8 +5911,8 @@ const struct bpf_func_proto bpf_unlocked_sk_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5928,8 +5928,8 @@ const struct bpf_func_proto bpf_unlocked_sk_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5945,8 +5945,8 @@ static const struct bpf_func_proto bpf_sock_addr_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -5962,8 +5962,8 @@ static const struct bpf_func_proto bpf_sock_addr_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6007,8 +6007,8 @@ static const struct bpf_func_proto bpf_sock_create_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6033,8 +6033,8 @@ static const struct bpf_func_proto bpf_sock_create_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6059,8 +6059,8 @@ static const struct bpf_func_proto bpf_sock_ops_setsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6169,8 +6169,8 @@ static const struct bpf_func_proto bpf_sock_ops_getsockopt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_MEM_SIZE,
};
@@ -6197,7 +6197,7 @@ static const struct bpf_func_proto bpf_sock_ops_cb_flags_set_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_bind, struct bpf_sock_addr_kern *, ctx, struct sockaddr *, addr,
@@ -6290,10 +6290,10 @@ static const struct bpf_func_proto bpf_skb_get_xfrm_state_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
#endif
@@ -6700,7 +6700,7 @@ static const struct bpf_func_proto bpf_xdp_fib_lookup_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_skb_fib_lookup, struct sk_buff *, skb,
@@ -6760,7 +6760,7 @@ static const struct bpf_func_proto bpf_skb_fib_lookup_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
static struct net_device *__dev_via_ifindex(struct net_device *dev_curr,
@@ -6857,11 +6857,11 @@ static const struct bpf_func_proto bpf_skb_check_mtu_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_WRITE | MEM_ALIGNED,
.arg3_size = sizeof(u32),
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {
@@ -6869,11 +6869,11 @@ static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_WRITE | MEM_ALIGNED,
.arg3_size = sizeof(u32),
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)
@@ -6955,7 +6955,7 @@ static const struct bpf_func_proto bpf_lwt_in_push_encap_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE
};
@@ -6965,7 +6965,7 @@ static const struct bpf_func_proto bpf_lwt_xmit_push_encap_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE
};
@@ -7009,7 +7009,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_store_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE
};
@@ -7098,7 +7098,7 @@ static const struct bpf_func_proto bpf_lwt_seg6_action_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE
};
@@ -7159,8 +7159,8 @@ static const struct bpf_func_proto bpf_lwt_seg6_adjust_srh_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
#endif /* CONFIG_IPV6_SEG6_BPF */
@@ -7332,8 +7332,8 @@ static const struct bpf_func_proto bpf_skc_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sk_lookup_tcp, struct sk_buff *, skb,
@@ -7351,8 +7351,8 @@ static const struct bpf_func_proto bpf_sk_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sk_lookup_udp, struct sk_buff *, skb,
@@ -7370,8 +7370,8 @@ static const struct bpf_func_proto bpf_sk_lookup_udp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_tc_skc_lookup_tcp, struct sk_buff *, skb,
@@ -7394,8 +7394,8 @@ static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_tc_sk_lookup_tcp, struct sk_buff *, skb,
@@ -7418,8 +7418,8 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_tc_sk_lookup_udp, struct sk_buff *, skb,
@@ -7442,8 +7442,8 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_udp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_1(bpf_sk_release, struct sock *, sk)
@@ -7480,8 +7480,8 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_udp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_xdp_skc_lookup_tcp, struct xdp_buff *, ctx,
@@ -7504,8 +7504,8 @@ static const struct bpf_func_proto bpf_xdp_skc_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_xdp_sk_lookup_tcp, struct xdp_buff *, ctx,
@@ -7528,8 +7528,8 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sock_addr_skc_lookup_tcp, struct bpf_sock_addr_kern *, ctx,
@@ -7548,8 +7548,8 @@ static const struct bpf_func_proto bpf_sock_addr_skc_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sock_addr_sk_lookup_tcp, struct bpf_sock_addr_kern *, ctx,
@@ -7567,8 +7567,8 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_tcp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
BPF_CALL_5(bpf_sock_addr_sk_lookup_udp, struct bpf_sock_addr_kern *, ctx,
@@ -7586,8 +7586,8 @@ static const struct bpf_func_proto bpf_sock_addr_sk_lookup_udp_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
- .arg4_type = ARG_ANYTHING,
- .arg5_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
+ .arg5_type = ARG_SCALAR,
};
bool bpf_tcp_sock_is_valid_access(int off, int size, enum bpf_access_type type,
@@ -8006,7 +8006,7 @@ static const struct bpf_func_proto bpf_sk_assign_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static const u8 *bpf_search_tcp_opt(const u8 *op, const u8 *opend,
@@ -8131,7 +8131,7 @@ static const struct bpf_func_proto bpf_sock_ops_load_hdr_opt_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_sock_ops_store_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
@@ -8209,7 +8209,7 @@ static const struct bpf_func_proto bpf_sock_ops_store_hdr_opt_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg3_type = ARG_MEM_SIZE,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_sock_ops_reserve_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
@@ -8234,8 +8234,8 @@ static const struct bpf_func_proto bpf_sock_ops_reserve_hdr_opt_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
BPF_CALL_3(bpf_skb_set_tstamp, struct sk_buff *, skb,
@@ -8275,8 +8275,8 @@ static const struct bpf_func_proto bpf_skb_set_tstamp_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
+ .arg3_type = ARG_SCALAR,
};
#ifdef CONFIG_SYN_COOKIES
@@ -11787,7 +11787,7 @@ static const struct bpf_func_proto sk_select_reuseport_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(sk_reuseport_load_bytes,
@@ -11802,7 +11802,7 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
};
@@ -11820,10 +11820,10 @@ static const struct bpf_func_proto sk_reuseport_load_bytes_relative_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
.arg4_type = ARG_MEM_SIZE,
- .arg5_type = ARG_ANYTHING,
+ .arg5_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
@@ -12010,7 +12010,7 @@ static const struct bpf_func_proto bpf_sk_lookup_assign_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_PTR_TO_SOCKET_OR_NULL,
- .arg3_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
};
static const struct bpf_func_proto *
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index ca49bc7f8687c..03d95aac8b606 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -641,7 +641,7 @@ const struct bpf_func_proto bpf_sock_map_update_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_sk_redirect_map, struct sk_buff *, skb,
@@ -668,8 +668,8 @@ const struct bpf_func_proto bpf_sk_redirect_map_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_msg_redirect_map, struct sk_msg *, msg,
@@ -699,8 +699,8 @@ const struct bpf_func_proto bpf_msg_redirect_map_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
- .arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_ANYTHING,
+ .arg3_type = ARG_SCALAR,
+ .arg4_type = ARG_SCALAR,
};
struct sock_map_seq_info {
@@ -1247,7 +1247,7 @@ const struct bpf_func_proto bpf_sock_hash_update_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_sk_redirect_hash, struct sk_buff *, skb,
@@ -1275,7 +1275,7 @@ const struct bpf_func_proto bpf_sk_redirect_hash_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
BPF_CALL_4(bpf_msg_redirect_hash, struct sk_msg *, msg,
@@ -1306,7 +1306,7 @@ const struct bpf_func_proto bpf_msg_redirect_hash_proto = {
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_CONST_MAP_PTR,
.arg3_type = ARG_PTR_TO_MAP_KEY,
- .arg4_type = ARG_ANYTHING,
+ .arg4_type = ARG_SCALAR,
};
struct sock_hash_seq_info {
diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c
index 791e15063237c..3684c0434da17 100644
--- a/net/ipv4/bpf_tcp_ca.c
+++ b/net/ipv4/bpf_tcp_ca.c
@@ -132,7 +132,7 @@ static const struct bpf_func_proto bpf_tcp_send_ack_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &tcp_sock_id,
- .arg2_type = ARG_ANYTHING,
+ .arg2_type = ARG_SCALAR,
};
static u32 prog_ops_moff(const struct bpf_prog *prog)
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
index 14d4c1793aed5..d74a9db54c9a3 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
@@ -13,13 +13,13 @@ struct {
const char *prog_name;
const char *err_msg;
} test_bpf_nf_fail_tests[] = {
- { "alloc_release", "kernel function bpf_ct_release R1 expected pointer to STRUCT nf_conn but" },
- { "insert_insert", "kernel function bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but" },
- { "lookup_insert", "kernel function bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but" },
- { "set_timeout_after_insert", "kernel function bpf_ct_set_timeout R1 expected pointer to STRUCT nf_conn___init but" },
- { "set_status_after_insert", "kernel function bpf_ct_set_status R1 expected pointer to STRUCT nf_conn___init but" },
- { "change_timeout_after_alloc", "kernel function bpf_ct_change_timeout R1 expected pointer to STRUCT nf_conn but" },
- { "change_status_after_alloc", "kernel function bpf_ct_change_status R1 expected pointer to STRUCT nf_conn but" },
+ { "alloc_release", "bpf_ct_release R1 expected pointer to STRUCT nf_conn but" },
+ { "insert_insert", "bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but" },
+ { "lookup_insert", "bpf_ct_insert_entry R1 expected pointer to STRUCT nf_conn___init but" },
+ { "set_timeout_after_insert", "bpf_ct_set_timeout R1 expected pointer to STRUCT nf_conn___init but" },
+ { "set_status_after_insert", "bpf_ct_set_status R1 expected pointer to STRUCT nf_conn___init but" },
+ { "change_timeout_after_alloc", "bpf_ct_change_timeout R1 expected pointer to STRUCT nf_conn but" },
+ { "change_status_after_alloc", "bpf_ct_change_status R1 expected pointer to STRUCT nf_conn but" },
{ "write_not_allowlisted_field", "no write support to nf_conn at off" },
{ "lookup_null_bpf_tuple", "Possibly NULL pointer passed to trusted R2" },
{ "lookup_null_bpf_opts", "Possibly NULL pointer passed to trusted R4" },
diff --git a/tools/testing/selftests/bpf/prog_tests/cb_refs.c b/tools/testing/selftests/bpf/prog_tests/cb_refs.c
index 78566b817fd70..504d395d59622 100644
--- a/tools/testing/selftests/bpf/prog_tests/cb_refs.c
+++ b/tools/testing/selftests/bpf/prog_tests/cb_refs.c
@@ -11,8 +11,8 @@ struct {
const char *prog_name;
const char *err_msg;
} cb_refs_tests[] = {
- { "underflow_prog", "release kfunc bpf_kfunc_call_test_release expects referenced PTR_TO_BTF_ID passed to R1" },
- { "leak_prog", "Possibly NULL pointer passed to helper R2" },
+ { "underflow_prog", "R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_" },
+ { "leak_prog", "Unreleased reference id=4 alloc_insn=33" },
{ "nested_cb", "Unreleased reference id=4 alloc_insn=2" }, /* alloc_insn=2{4,5} */
{ "non_cb_transfer_ref", "Unreleased reference id=4 alloc_insn=1" }, /* alloc_insn=1{1,2} */
};
diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
index 2b39cc1b09f9a..0063e60d6f2f5 100644
--- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
+++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
@@ -70,7 +70,7 @@ static struct kfunc_test_params kfunc_tests[] = {
TC_FAIL(kfunc_call_test_get_mem_fail_oversized, 0, "allocation size exceeds u32 max"),
TC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, "is not a const"),
TC_FAIL(kfunc_call_test_mem_acquire_fail, 0, "acquire kernel function does not return PTR_TO_BTF_ID"),
- TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "R1 expected pointer to ctx, but got scalar"),
+ TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "R1 type=scalar expected=ctx"),
TC_FAIL(kfunc_call_test_spin_lock_unsafe, 0, "function calls are not allowed while holding a lock"),
/* success cases */
diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index f7f94ccebce27..b973814482481 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -54,6 +54,7 @@
#include "verifier_iterating_callbacks.skel.h"
#include "verifier_jeq_infer_not_null.skel.h"
#include "verifier_jit_convergence.skel.h"
+#include "verifier_kfunc_packet_access.skel.h"
#include "verifier_ld_ind.skel.h"
#include "verifier_ldsx.skel.h"
#include "verifier_leak_ptr.skel.h"
@@ -218,6 +219,7 @@ void test_verifier_int_ptr(void) { RUN(verifier_int_ptr); }
void test_verifier_iterating_callbacks(void) { RUN(verifier_iterating_callbacks); }
void test_verifier_jeq_infer_not_null(void) { RUN(verifier_jeq_infer_not_null); }
void test_verifier_jit_convergence(void) { RUN(verifier_jit_convergence); }
+void test_verifier_kfunc_packet_access(void) { RUN_TESTS(verifier_kfunc_packet_access); }
void test_verifier_load_acquire(void) { RUN(verifier_load_acquire); }
void test_verifier_ld_ind(void) { RUN(verifier_ld_ind); }
void test_verifier_ldsx(void) { RUN(verifier_ldsx); }
diff --git a/tools/testing/selftests/bpf/progs/arena_kfunc.c b/tools/testing/selftests/bpf/progs/arena_kfunc.c
index 50609f3b0564a..6578cf12fa27d 100644
--- a/tools/testing/selftests/bpf/progs/arena_kfunc.c
+++ b/tools/testing/selftests/bpf/progs/arena_kfunc.c
@@ -205,7 +205,7 @@ int arena_arg_no_arena(void *ctx)
SEC("syscall")
__arch_x86_64
__arch_arm64
-__failure __msg("is not a pointer to arena or scalar")
+__failure __msg("R1 type=fp expected=arena, scalar")
int arena_arg_bad_reg(void *ctx)
{
u64 buf = 0;
diff --git a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
index efe7bcae70f85..ede6a17d7da30 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 is fp expected STRUCT cgroup")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path)
{
struct cgroup *acquired, *stack_cgrp = (struct cgroup *)&path;
@@ -154,7 +154,7 @@ int BPF_PROG(cgrp_kfunc_xchg_unreleased, struct cgroup *cgrp, const char *path)
}
SEC("tp_btf/cgroup_mkdir")
-__failure __msg("release kfunc bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(cgrp_kfunc_rcu_get_release, struct cgroup *cgrp, const char *path)
{
struct cgroup *kptr;
@@ -191,7 +191,7 @@ int BPF_PROG(cgrp_kfunc_release_untrusted, struct cgroup *cgrp, const char *path
}
SEC("tp_btf/cgroup_mkdir")
-__failure __msg("release kfunc bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(cgrp_kfunc_release_fp, struct cgroup *cgrp, const char *path)
{
struct cgroup *acquired = (struct cgroup *)&path;
@@ -237,7 +237,7 @@ int BPF_PROG(cgrp_kfunc_release_null, struct cgroup *cgrp, const char *path)
}
SEC("tp_btf/cgroup_mkdir")
-__failure __msg("release kfunc bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_cgroup_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(cgrp_kfunc_release_unacquired, struct cgroup *cgrp, const char *path)
{
/* Cannot release trusted cgroup pointer which was not acquired. */
diff --git a/tools/testing/selftests/bpf/progs/cpumask_failure.c b/tools/testing/selftests/bpf/progs/cpumask_failure.c
index 4628feb53d861..c89c88db39d14 100644
--- a/tools/testing/selftests/bpf/progs/cpumask_failure.c
+++ b/tools/testing/selftests/bpf/progs/cpumask_failure.c
@@ -183,7 +183,7 @@ int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone
}
SEC("tp_btf/task_newtask")
-__failure __msg("Possibly NULL pointer passed to helper R2")
+__failure __msg("release function bpf_kptr_xchg expects referenced PTR_TO_BTF_ID passed to R2")
int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags)
{
struct bpf_cpumask *prev, *curr;
@@ -243,7 +243,7 @@ int BPF_PROG(test_populate_invalid_destination, struct task_struct *task, u64 cl
}
SEC("tp_btf/task_newtask")
-__failure __msg("leads to invalid memory access")
+__failure __msg("R2 type=scalar expected=fp")
int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_flags)
{
void *garbage = (void *)0x123456;
diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c
index a4a007866a332..53df6d248e267 100644
--- a/tools/testing/selftests/bpf/progs/irq.c
+++ b/tools/testing/selftests/bpf/progs/irq.c
@@ -15,7 +15,7 @@ struct bpf_res_spin_lock lockA __hidden SEC(".data.A");
struct bpf_res_spin_lock lockB __hidden SEC(".data.B");
SEC("?tc")
-__failure __msg("R1 doesn't point to an irq flag on stack")
+__failure __msg("R1 type=map_value expected=fp")
int irq_save_bad_arg(struct __sk_buff *ctx)
{
bpf_local_irq_save(&global_flags);
@@ -23,7 +23,7 @@ int irq_save_bad_arg(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("R1 doesn't point to an irq flag on stack")
+__failure __msg("R1 type=map_value expected=fp")
int irq_restore_bad_arg(struct __sk_buff *ctx)
{
bpf_local_irq_restore(&global_flags);
diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c
index 62d7df9e80beb..e4d099c533aa7 100644
--- a/tools/testing/selftests/bpf/progs/iters.c
+++ b/tools/testing/selftests/bpf/progs/iters.c
@@ -1688,7 +1688,7 @@ int iter_subprog_check_stacksafe(const void *ctx)
struct bpf_iter_num global_it;
SEC("raw_tp")
-__failure __msg("R1 expected pointer to an iterator on stack")
+__failure __msg("R1 type=map_value expected=fp")
int iter_new_bad_arg(const void *ctx)
{
bpf_iter_num_new(&global_it, 0, 1);
@@ -1696,7 +1696,7 @@ int iter_new_bad_arg(const void *ctx)
}
SEC("raw_tp")
-__failure __msg("R1 expected pointer to an iterator on stack")
+__failure __msg("R1 type=map_value expected=fp")
int iter_next_bad_arg(const void *ctx)
{
bpf_iter_num_next(&global_it);
@@ -1704,7 +1704,7 @@ int iter_next_bad_arg(const void *ctx)
}
SEC("raw_tp")
-__failure __msg("R1 expected pointer to an iterator on stack")
+__failure __msg("R1 type=map_value expected=fp")
int iter_destroy_bad_arg(const void *ctx)
{
bpf_iter_num_destroy(&global_it);
diff --git a/tools/testing/selftests/bpf/progs/iters_testmod.c b/tools/testing/selftests/bpf/progs/iters_testmod.c
index 76012dbbdb413..f65cc9766633e 100644
--- a/tools/testing/selftests/bpf/progs/iters_testmod.c
+++ b/tools/testing/selftests/bpf/progs/iters_testmod.c
@@ -105,8 +105,7 @@ int iter_next_rcu_not_trusted(const void *ctx)
}
SEC("raw_tp/sys_enter")
-__failure __msg("R1 cannot write into rdonly_mem")
-/* Message should not be 'R1 cannot write into rdonly_trusted_mem' */
+__failure __msg("R1 type=rdonly_mem expected=fp")
int iter_next_ptr_mem_not_trusted(const void *ctx)
{
struct bpf_iter_num num_it;
@@ -135,7 +134,7 @@ int iter_ret_rcu_test_protected(const void *ctx)
}
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
-__failure __msg("R1 type=rcu_ptr_or_null_ expected=")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int iter_ret_rcu_test_type(const void *ctx)
{
struct task_struct *p;
@@ -158,7 +157,7 @@ int iter_ret_rcu_test_protected_nostruct(const void *ctx)
}
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
-__failure __msg("R1 type=rdonly_rcu_mem_or_null expected=")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int iter_ret_rcu_test_type_nostruct(const void *ctx)
{
void *p;
diff --git a/tools/testing/selftests/bpf/progs/map_kptr_fail.c b/tools/testing/selftests/bpf/progs/map_kptr_fail.c
index 5e25ca806060c..4b64f1dc7b81b 100644
--- a/tools/testing/selftests/bpf/progs/map_kptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/map_kptr_fail.c
@@ -149,7 +149,7 @@ int reject_bad_type_match(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("R1 type=untrusted_ptr_or_null_ expected=percpu_ptr_")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int marked_as_untrusted_or_null(struct __sk_buff *ctx)
{
struct map_value *v;
@@ -217,7 +217,7 @@ int reject_kptr_xchg_on_unref(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("R1 type=rcu_ptr_or_null_ expected=percpu_ptr_")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int mark_ref_as_untrusted_or_null(struct __sk_buff *ctx)
{
struct map_value *v;
@@ -252,7 +252,7 @@ int reject_untrusted_store_to_ref(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("release helper bpf_kptr_xchg expects referenced PTR_TO_BTF_ID passed to R2")
+__failure __msg("release function bpf_kptr_xchg expects referenced PTR_TO_BTF_ID passed to R2")
int reject_untrusted_xchg(struct __sk_buff *ctx)
{
struct prog_test_ref_kfunc *p;
@@ -291,7 +291,7 @@ int reject_bad_type_xchg(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("invalid kptr access, R2 type=trusted_ptr_prog_test_ref_kfunc")
+__failure __msg("R2 must have zero offset when passed to release func")
int reject_member_of_ref_xchg(struct __sk_buff *ctx)
{
struct prog_test_ref_kfunc *ref_ptr;
@@ -364,7 +364,7 @@ int kptr_xchg_ref_state(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("Possibly NULL pointer passed to helper R2")
+__success
int kptr_xchg_possibly_null(struct __sk_buff *ctx)
{
struct prog_test_ref_kfunc *p;
diff --git a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
index 3e0d4f687aaad..23019023511af 100644
--- a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
+++ b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
@@ -118,8 +118,7 @@ int atomic_rmw_not_ok(void *ctx)
SEC("socket")
__failure
-__msg("invalid access to memory, mem_size=0 off=0 size=4")
-__msg("R1 min value is outside of the allowed memory range")
+__msg("R1 type=rdonly_untrusted_mem expected=fp")
int kfunc_param_not_ok(void *ctx)
{
int *p;
diff --git a/tools/testing/selftests/bpf/progs/rbtree_fail.c b/tools/testing/selftests/bpf/progs/rbtree_fail.c
index 555379952dcc2..80494e00ede3a 100644
--- a/tools/testing/selftests/bpf/progs/rbtree_fail.c
+++ b/tools/testing/selftests/bpf/progs/rbtree_fail.c
@@ -179,7 +179,7 @@ long rbtree_api_use_unchecked_remove_retval(void *ctx)
}
SEC("?tc")
-__failure __msg("bpf_rbtree_remove can only take non-owning or refcounted bpf_rb_node pointer")
+__failure __msg("R2 type=scalar expected=ptr_, ptr_, rcu_ptr_")
long rbtree_api_add_release_unlock_escape(void *ctx)
{
struct node_data *n;
@@ -203,7 +203,7 @@ long rbtree_api_add_release_unlock_escape(void *ctx)
}
SEC("?tc")
-__failure __msg("bpf_rbtree_remove can only take non-owning or refcounted bpf_rb_node pointer")
+__failure __msg("R2 type=scalar expected=ptr_, ptr_, rcu_ptr_")
long rbtree_api_first_release_unlock_escape(void *ctx)
{
struct bpf_rb_node *res;
diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
index eaaed0859f946..8a98e901382d9 100644
--- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
@@ -82,8 +82,8 @@ long refcount_acquire_maybe_null(void *ctx)
}
SEC("?tc")
-__failure __msg("R1 is neither owning or non-owning ref")
-__msg("expects a pointer to a BPF-managed refcounted object, but R1 is a context pointer")
+__failure __msg("R1 type=ctx expected=ptr_, ptr_, rcu_ptr_")
+__msg("type ctx, but this argument accepts ptr_, ptr_, rcu_ptr_")
long refcount_acquire_non_object(void *ctx)
{
return bpf_refcount_acquire(ctx) != NULL;
diff --git a/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c b/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c
index 330682a88c161..8fd591bd1f6cf 100644
--- a/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c
+++ b/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c
@@ -24,7 +24,7 @@ struct bpf_spin_lock lock __hidden SEC(".data.A");
struct bpf_res_spin_lock res_lock __hidden SEC(".data.B");
SEC("?tc")
-__failure __msg("point to map value or allocated object")
+__failure __msg("R1 type=untrusted_ptr_ expected=map_value, ptr_")
int res_spin_lock_arg(struct __sk_buff *ctx)
{
struct arr_elem *elem;
diff --git a/tools/testing/selftests/bpf/progs/stream_fail.c b/tools/testing/selftests/bpf/progs/stream_fail.c
index 21428bb1ee597..10ebb4a7f105a 100644
--- a/tools/testing/selftests/bpf/progs/stream_fail.c
+++ b/tools/testing/selftests/bpf/progs/stream_fail.c
@@ -23,7 +23,7 @@ int stream_vprintk_scalar_arg(void *ctx)
}
SEC("syscall")
-__failure __msg("R2 doesn't point to a const string")
+__failure __msg("R2 type=ctx expected=map_value")
int stream_vprintk_string_arg(void *ctx)
{
bpf_stream_vprintk(BPF_STDOUT, ctx, NULL, 0);
diff --git a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c
index f96b0c13ed1a5..12c8ac6099cae 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 is fp expected STRUCT task_struct")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
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;
@@ -179,7 +179,7 @@ int BPF_PROG(task_kfunc_release_untrusted, struct task_struct *task, u64 clone_f
}
SEC("tp_btf/task_newtask")
-__failure __msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(task_kfunc_release_fp, struct task_struct *task, u64 clone_flags)
{
struct task_struct *acquired = (struct task_struct *)&clone_flags;
@@ -225,7 +225,7 @@ int BPF_PROG(task_kfunc_release_null, struct task_struct *task, u64 clone_flags)
}
SEC("tp_btf/task_newtask")
-__failure __msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(task_kfunc_release_unacquired, struct task_struct *task, u64 clone_flags)
{
/* Cannot release trusted task pointer which was not acquired. */
@@ -333,7 +333,7 @@ int BPF_PROG(task_access_comm2, struct task_struct *task, u64 clone_flags)
}
SEC("tp_btf/task_newtask")
-__failure __msg("write into memory")
+__failure __msg("only read is supported")
int BPF_PROG(task_access_comm3, struct task_struct *task, u64 clone_flags)
{
bpf_probe_read_kernel(task->comm, 16, task->comm);
@@ -353,7 +353,7 @@ int BPF_PROG(task_access_comm4, struct task_struct *task, const char *buf, bool
}
SEC("tp_btf/task_newtask")
-__failure __msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(task_kfunc_release_in_map, struct task_struct *task, u64 clone_flags)
{
struct task_struct *local;
diff --git a/tools/testing/selftests/bpf/progs/task_work_fail.c b/tools/testing/selftests/bpf/progs/task_work_fail.c
index 3186e7b4b24e0..bc56bdaca780b 100644
--- a/tools/testing/selftests/bpf/progs/task_work_fail.c
+++ b/tools/testing/selftests/bpf/progs/task_work_fail.c
@@ -58,7 +58,7 @@ int mismatch_map(struct pt_regs *args)
}
SEC("perf_event")
-__failure __msg("R2 doesn't point to a map value")
+__failure __msg("R2 type=fp expected=map_value")
int no_map_task_work(struct pt_regs *args)
{
struct task_struct *task;
diff --git a/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c b/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
index bf48fc43c7ab6..f7a83e5024543 100644
--- a/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
+++ b/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
@@ -40,7 +40,7 @@ int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size,
}
SEC("?lsm.s/bpf")
-__failure __msg("R1 expected pointer to stack or const struct bpf_dynptr")
+__failure __msg("R1 type=map_value expected=fp, dynptr_ptr")
int BPF_PROG(not_ptr_to_stack, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
{
static struct bpf_dynptr val;
diff --git a/tools/testing/selftests/bpf/progs/verifier_ctx.c b/tools/testing/selftests/bpf/progs/verifier_ctx.c
index 7856dad3d1f38..9d42ba8244082 100644
--- a/tools/testing/selftests/bpf/progs/verifier_ctx.c
+++ b/tools/testing/selftests/bpf/progs/verifier_ctx.c
@@ -208,7 +208,7 @@ __naked void null_check_7_ctx_bind(void)
SEC("cgroup/post_bind4")
__description("pass ctx or null check, 8: null (bind)")
-__failure __msg("R1 type=scalar expected=ctx")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void null_check_8_null_bind(void)
{
asm volatile (" \
diff --git a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
index 0bdeb7bc4687a..87604020ba212 100644
--- a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
+++ b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
@@ -153,7 +153,7 @@ __weak int subprog_trusted_destroy(struct task_struct *task __arg_trusted)
SEC("?tp_btf/task_newtask")
__failure __log_level(2)
-__msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
+__msg("release function bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(trusted_destroy_fail, struct task_struct *task, u64 clone_flags)
{
return subprog_trusted_destroy(task);
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 343fc08d97479..d1452ef6f2f9a 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
@@ -621,7 +621,7 @@ l0_%=: exit; \
SEC("tracepoint")
__description("helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)")
-__failure __msg("R1 type=scalar expected=fp")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void ptr_to_mem_or_null_8(void)
{
asm volatile (" \
@@ -637,7 +637,7 @@ __naked void ptr_to_mem_or_null_8(void)
SEC("tracepoint")
__description("helper access to variable memory: size > 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)")
-__failure __msg("R1 type=scalar expected=fp")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void ptr_to_mem_or_null_9(void)
{
asm volatile (" \
diff --git a/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c
index 71cee3f583243..12786b72c6948 100644
--- a/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c
+++ b/tools/testing/selftests/bpf/progs/verifier_helper_packet_access.c
@@ -258,7 +258,7 @@ l0_%=: r0 = 0; \
SEC("tc")
__description("helper access to packet: test11, cls unsuitable helper 1")
-__failure __msg("helper access to the packet")
+__failure __msg("function access to the packet")
__naked void test11_cls_unsuitable_helper_1(void)
{
asm volatile (" \
@@ -283,7 +283,7 @@ l0_%=: r0 = 0; \
SEC("tc")
__description("helper access to packet: test12, cls unsuitable helper 2")
-__failure __msg("helper access to the packet")
+__failure __msg("function access to the packet")
__naked void test12_cls_unsuitable_helper_2(void)
{
asm volatile (" \
diff --git a/tools/testing/selftests/bpf/progs/verifier_kfunc_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_kfunc_packet_access.c
new file mode 100644
index 0000000000000..9ae63c9eab02d
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_kfunc_packet_access.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+struct nf_conn *bpf_skb_ct_lookup(struct __sk_buff *skb_ctx,
+ struct bpf_sock_tuple *bpf_tuple,
+ u32 tuple__sz, struct bpf_ct_opts *opts,
+ u32 opts__sz) __ksym;
+void bpf_ct_release(struct nf_conn *nfct) __ksym;
+
+char _license[] SEC("license") = "GPL";
+
+SEC("tc")
+__description("kfunc packet write requests writable skb")
+__success
+/* bpf_unclone_prologue() */
+__xlated("r6 = *(u8 *)(r1 +{{[0-9]+}})")
+__xlated("...")
+__xlated("w6 &= {{1|128}}")
+__xlated("...")
+__xlated("if r6 == 0x0 goto")
+__xlated("r6 = r1")
+__xlated("r2 ^= r2")
+__xlated("call")
+__xlated("if r0 == 0x0 goto")
+__xlated("w0 = 2")
+__xlated("...")
+__xlated("exit")
+__xlated("r1 = r6")
+int kfunc_packet_write(struct __sk_buff *skb)
+{
+ void *data_end = (void *)(long)skb->data_end;
+ void *data = (void *)(long)skb->data;
+ struct bpf_sock_tuple tuple = {};
+ struct nf_conn *nfct;
+
+ if (data + sizeof(struct bpf_ct_opts) > data_end)
+ return 0;
+
+ /* An invalid tuple size makes bpf_skb_ct_lookup() write opts->error. */
+ nfct = bpf_skb_ct_lookup(skb, &tuple, 1, data, sizeof(struct bpf_ct_opts));
+ if (nfct)
+ bpf_ct_release(nfct);
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/verifier_live_stack.c b/tools/testing/selftests/bpf/progs/verifier_live_stack.c
index 401152b2b64fc..bc3dfdc1a5363 100644
--- a/tools/testing/selftests/bpf/progs/verifier_live_stack.c
+++ b/tools/testing/selftests/bpf/progs/verifier_live_stack.c
@@ -246,7 +246,7 @@ static __used __naked void read_first_param2(void)
SEC("socket")
__flag(BPF_F_TEST_STATE_FREQ)
__failure
-__msg("R1 type=scalar expected=map_ptr")
+__msg("Possibly NULL pointer passed to trusted R1")
__naked void caller_stack_pruning_callback(void)
{
asm volatile (
diff --git a/tools/testing/selftests/bpf/progs/verifier_map_in_map.c b/tools/testing/selftests/bpf/progs/verifier_map_in_map.c
index d3be69a9a7557..621248a02a1f9 100644
--- a/tools/testing/selftests/bpf/progs/verifier_map_in_map.c
+++ b/tools/testing/selftests/bpf/progs/verifier_map_in_map.c
@@ -154,8 +154,7 @@ l0_%=: r0 = 0; \
SEC("socket")
__description("forgot null checking on the inner map pointer")
-__failure __msg("R1 type=map_ptr_or_null expected=map_ptr")
-__msg("map_ptr_or_null, but this argument accepts map_ptr")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__failure_unpriv
__naked void on_the_inner_map_pointer(void)
{
diff --git a/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c b/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c
index c01abf54923d3..4b1eadddd89cd 100644
--- a/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c
+++ b/tools/testing/selftests/bpf/progs/verifier_map_lookup_refine.c
@@ -58,7 +58,7 @@ int mapofmaps_value_as_helper_mem_buf(struct __sk_buff *skb)
}
SEC("?tc")
-__failure __msg("type=map_ptr_or_null expected=fp")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
int mapofmaps_value_as_helper_fixed_mem(struct __sk_buff *skb)
{
char th[sizeof(struct tcphdr)] = {};
diff --git a/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c b/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c
index 199ad18f8eb58..799db6f5713b0 100644
--- a/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c
+++ b/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c
@@ -344,7 +344,7 @@ __naked void potential_reference_to_system_key(void)
SEC("tc")
__description("reference tracking: release reference without check")
-__failure __msg("type=sock_or_null expected=sock")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void tracking_release_reference_without_check(void)
{
asm volatile (
@@ -363,7 +363,7 @@ __naked void tracking_release_reference_without_check(void)
SEC("tc")
__description("reference tracking: release reference to sock_common without check")
-__failure __msg("type=sock_common_or_null expected=sock")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__naked void to_sock_common_without_check(void)
{
asm volatile (
@@ -1288,7 +1288,7 @@ l1_%=: r1 = r6; \
SEC("tc")
__description("reference tracking: bpf_sk_release(listen_sk)")
-__failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
__naked void bpf_sk_release_listen_sk(void)
{
asm volatile (
diff --git a/tools/testing/selftests/bpf/progs/verifier_sock.c b/tools/testing/selftests/bpf/progs/verifier_sock.c
index 4f2f3209eec81..2a136c917680f 100644
--- a/tools/testing/selftests/bpf/progs/verifier_sock.c
+++ b/tools/testing/selftests/bpf/progs/verifier_sock.c
@@ -110,7 +110,7 @@ l0_%=: r0 = *(u32*)(r1 + %[bpf_sock_type]); \
SEC("cgroup/skb")
__description("bpf_sk_fullsock(skb->sk): no !skb->sk check")
-__failure __msg("type=sock_common_or_null expected=sock_common")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__failure_unpriv
__naked void sk_no_skb_sk_check_1(void)
{
@@ -466,7 +466,7 @@ l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_rx_queue_mapping__end]);\
SEC("cgroup/skb")
__description("bpf_tcp_sock(skb->sk): no !skb->sk check")
-__failure __msg("type=sock_common_or_null expected=sock_common")
+__failure __msg("Possibly NULL pointer passed to trusted R1")
__failure_unpriv
__naked void sk_no_skb_sk_check_2(void)
{
@@ -603,7 +603,7 @@ l2_%=: r0 = *(u32*)(r0 + %[bpf_tcp_sock_snd_cwnd]); \
SEC("tc")
__description("bpf_sk_release(skb->sk)")
-__failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
__naked void bpf_sk_release_skb_sk(void)
{
asm volatile (" \
@@ -620,7 +620,7 @@ l0_%=: r0 = 0; \
SEC("tc")
__description("bpf_sk_release(bpf_sk_fullsock(skb->sk))")
-__failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
__naked void bpf_sk_fullsock_skb_sk(void)
{
asm volatile (" \
@@ -644,7 +644,7 @@ l1_%=: r1 = r0; \
SEC("tc")
__description("bpf_sk_release(bpf_tcp_sock(skb->sk))")
-__failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
__naked void bpf_tcp_sock_skb_sk(void)
{
asm volatile (" \
diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
index 8f0c45421f893..b5f456d57669e 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 is fp expected STRUCT task_struct")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(get_task_exe_file_kfunc_fp)
{
u64 x;
@@ -80,7 +80,7 @@ int BPF_PROG(get_task_exe_file_kfunc_unreleased)
}
SEC("lsm.s/file_open")
-__failure __msg("release kfunc bpf_put_file expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("release function bpf_put_file expects referenced PTR_TO_BTF_ID passed to R1")
int BPF_PROG(put_file_kfunc_unacquired, struct file *file)
{
/* Can't release an unacquired pointer. */
@@ -128,7 +128,7 @@ int BPF_PROG(path_d_path_kfunc_untrusted_from_current)
}
SEC("lsm.s/file_open")
-__failure __msg("kernel function bpf_path_d_path R1 expected pointer to STRUCT path but R1 has a pointer to STRUCT file")
+__failure __msg("bpf_path_d_path R1 expected pointer to STRUCT path but R1 has a pointer to STRUCT file")
int BPF_PROG(path_d_path_kfunc_type_mismatch, struct file *file)
{
bpf_path_d_path((struct path *)&file->f_task_work, buf, sizeof(buf));
diff --git a/tools/testing/selftests/bpf/progs/wakeup_source_fail.c b/tools/testing/selftests/bpf/progs/wakeup_source_fail.c
index d4d0f1610853a..ec4e0f3ff7920 100644
--- a/tools/testing/selftests/bpf/progs/wakeup_source_fail.c
+++ b/tools/testing/selftests/bpf/progs/wakeup_source_fail.c
@@ -42,7 +42,7 @@ int wakeup_source_access_lock_fields(void *ctx)
}
SEC("syscall")
-__failure __msg("release kfunc bpf_wakeup_sources_read_unlock expects referenced PTR_TO_BTF_ID passed to R1")
+__failure __msg("R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_")
int wakeup_source_unlock_no_lock(void *ctx)
{
struct bpf_ws_lock *lock = (void *)0x1;
diff --git a/tools/testing/selftests/bpf/progs/wq_failures.c b/tools/testing/selftests/bpf/progs/wq_failures.c
index 32dc8827e128b..bd30217579d4d 100644
--- a/tools/testing/selftests/bpf/progs/wq_failures.c
+++ b/tools/testing/selftests/bpf/progs/wq_failures.c
@@ -48,7 +48,7 @@ __log_level(2)
__flag(BPF_F_TEST_STATE_FREQ)
__failure
__msg(": (85) call bpf_wq_init#") /* anchor message */
-__msg("pointer in R2 isn't map pointer")
+__msg("R2 type=fp expected=map_ptr")
long test_wq_init_nomap(void *ctx)
{
struct bpf_wq *wq;
@@ -98,7 +98,7 @@ __failure
* is a correct bpf_wq pointer.
*/
__msg(": (85) call bpf_wq_set_callback#") /* anchor message */
-__msg("R1 doesn't point to a map value")
+__msg("R1 type=fp expected=map_value")
long test_wrong_wq_pointer(void *ctx)
{
int key = 0;
diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c
index eb6e3baef412a..0930ef8626972 100644
--- a/tools/testing/selftests/bpf/verifier/calls.c
+++ b/tools/testing/selftests/bpf/verifier/calls.c
@@ -76,7 +76,7 @@
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
- .errstr = "R1 expected pointer to ctx, but got fp",
+ .errstr = "R1 type=fp expected=ctx",
.fixup_kfunc_btf_id = {
{ "bpf_kfunc_call_test_pass_ctx", 2 },
},
@@ -152,7 +152,7 @@
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
- .errstr = "kernel function bpf_kfunc_call_memb1_release R1 expected pointer",
+ .errstr = "bpf_kfunc_call_memb1_release R1 expected pointer",
.fixup_kfunc_btf_id = {
{ "bpf_kfunc_call_memb_acquire", 1 },
{ "bpf_kfunc_call_memb1_release", 5 },
diff --git a/tools/testing/selftests/bpf/verifier/map_kptr.c b/tools/testing/selftests/bpf/verifier/map_kptr.c
index 4b39f8472f9b5..345cecc722a38 100644
--- a/tools/testing/selftests/bpf/verifier/map_kptr.c
+++ b/tools/testing/selftests/bpf/verifier/map_kptr.c
@@ -311,7 +311,7 @@
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.fixup_map_kptr = { 1 },
.result = REJECT,
- .errstr = "R1 type=rcu_ptr_or_null_ expected=percpu_ptr_",
+ .errstr = "Possibly NULL pointer passed to trusted R1",
},
{
"map_kptr: ref: reject off != 0",
@@ -342,7 +342,7 @@
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.fixup_map_kptr = { 1 },
.result = REJECT,
- .errstr = "invalid kptr access, R2 type=ptr_prog_test_ref_kfunc expected=ptr_prog_test_member",
+ .errstr = "R2 must have zero offset when passed to release func",
},
{
"map_kptr: ref: reference state created and released on xchg",
|
| 11/3 | 2026/09/06 17:58 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 93286 output: 232 thoughts: 1261 Thoughts: **KMSAN Assessment: Refactoring of BPF Verifier Argument Checking** Okay, here's the breakdown of this patch from my perspective, as a kernel expert. My task is to determine whether it warrants a dedicated KMSAN fuzzing session. Let's dig in. The core of this patch is a refactoring of the BPF verifier. It consolidates the argument checking logic for both helper functions and kfuncs. This involves renaming some enum values (`ARG_ANYTHING` to `ARG_SCALAR`, `ARG_DONTCARE` to `ARG_UNUSED`) and unifying the validation paths within `verifier.c`. The changes also refactor existing code to utilize the unified code, and update existing tests. Now, the crucial question: does this introduce any uninitialized memory vulnerabilities? That's what KMSAN is all about. Based on my assessment: 1. **No Kernel Structures to Userspace:** This patch doesn't modify kernel structures that are sent to user space directly (e.g., via `copy_to_user`, netlink, etc.). So, no risk of leaking uninitialized memory that way. 2. **No Uninitialized Conditional Logic:** I've scrutinized the conditional logic and branching. It looks like the patch consistently initializes relevant data structures before use. For example, `memset(&meta, 0, sizeof(meta))` is used to ensure the `bpf_call_arg_meta` struct is zeroed. No new opportunities for uninitialized memory reads arise here. 3. **No New Data Structure Initialization Issues:** The patch doesn't introduce or alter complex data structure allocations or initialization in a way that could lead to later reads of uninitialized fields. 4. **No Buffer Boundaries or Length Problems:** There's nothing here that seems to create opportunities for accessing uninitialized bytes in existing buffers via bounds check manipulation or other means. No concerns about memory buffers that might be leaked to userspace, or uninitialized stack/heap. Considering the KMSAN rules – that a KMSAN session is ONLY necessary if a bug isn't caught by KASAN or other standard detectors – this doesn't trigger any red flags. The code uses `struct bpf_call_arg_meta meta; memset(&meta, 0, sizeof(meta));` in functions like `check_helper_call` and `btf_check_func_arg_match`, and `meta` is handled in other code as well. I've specifically checked for potential issues with structures like `dynptr`, `ref_obj`, `arg_raw_mem`, etc. Everything in `bpf_call_arg_meta` appears properly initialized. The patch is simply refactoring the verifier code, without introducing any real uninitialized memory risks. Standard KASAN and existing verifier testing/fuzzing should be more than adequate here. KMSAN isn't needed. So, the conclusion is clear. I'm going to set `NeedsKMSAN=false` with the reasoning that this patch is a refactoring of BPF verifier logic, with no introduction of uninitialized memory risks or kernel-to-user info leaks. KASAN and existing testing are sufficient. |
| 12/3 | 2026/09/06 17:58 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch series is a refactor and consolidation of the BPF verifier's argument-checking subsystem. It merges the validation paths for BPF helper calls and kfuncs into unified helper/kfunc argument checking (`check_func_args`), renames `ARG_ANYTHING` to `ARG_SCALAR` and `ARG_DONTCARE` to `ARG_UNUSED`, and extends `enum bpf_arg_type` with kfunc argument types while updating error diagnostics and selftest expected messages.\n\nThere are no changes that introduce uninitialized stack or heap allocations, no modifications to kernel-to-user copy routines (e.g. `copy_to_user`, `put_user`, socket options, or netlink), and no alterations to data buffer initialization or info-leak vectors. Any potential logic bugs in verifier register typing or bounds checking would be caught by standard verifier checks, KASAN, or existing testing suites. Therefore, dedicated KMSAN fuzzing is not required.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch series is a refactor and consolidation of the BPF verifier's argument-checking subsystem. It merges the validation paths for BPF helper calls and kfuncs into unified helper/kfunc argument checking (`check_func_args`), renames `ARG_ANYTHING` to `ARG_SCALAR` and `ARG_DONTCARE` to `ARG_UNUSED`, and extends `enum bpf_arg_type` with kfunc argument types while updating error diagnostics and selftest expected messages.\n\nThere are no changes that introduce uninitialized stack or heap allocations, no modifications to kernel-to-user copy routines (e.g. `copy_to_user`, `put_user`, socket options, or netlink), and no alterations to data buffer initialization or info-leak vectors. Any potential logic bugs in verifier register typing or bounds checking would be caught by standard verifier checks, KASAN, or existing testing suites. Therefore, dedicated KMSAN fuzzing is not required.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|