| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/06/22 02:47 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"__check_func_arg_reg_off",
"check_kfunc_args",
"bpf_refcount_acquire"
],
"Reasoning": "The patch modifies the BPF verifier to restrict the allowed offset for KF_ARG_PTR_TO_REFCOUNTED_KPTR arguments to 0. This is a functional change in the core BPF verifier logic, reachable from userspace via the bpf() syscall, and should be fuzzed to ensure it correctly rejects invalid offsets without breaking valid use cases.",
"WorthFuzzing": true
} |
| 1/1 | 2026/06/22 02:47 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit acf0ae823dd377acee71eca0e9dfe3f24f1e8041\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jun 22 02:47:48 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c\nindex 2abc79dbf281c2..f65eff28ecd25e 100644\n--- a/kernel/bpf/verifier.c\n+++ b/kernel/bpf/verifier.c\n@@ -7990,9 +7990,10 @@ 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+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 {\n \tu32 type = reg-\u003etype;\n \n@@ -8049,12 +8050,11 @@ static int check_func_arg_reg_off(struct bpf_verifier_env *env,\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. This was already checked above. So pass\n-\t\t * fixed_off_ok as true to allow fixed offset for all other\n-\t\t * cases. var_off always must be 0 for PTR_TO_BTF_ID, hence we\n-\t\t * still need to do checks instead of returning.\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 */\n-\t\treturn __check_ptr_off_reg(env, reg, argno, true);\n+\t\treturn __check_ptr_off_reg(env, reg, argno, btf_id_fixed_off_ok);\n \tcase PTR_TO_CTX:\n \t\t/*\n \t\t * Allow fixed and variable offsets for syscall context, but\n@@ -8070,6 +8070,13 @@ 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@@ -11941,6 +11948,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_\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, type_size;\n \t\tbool is_ret_buf_sz = false;\n \t\tint kf_arg_type;\n@@ -12114,7 +12122,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_\n \t\tcase KF_ARG_PTR_TO_MEM:\n \t\tcase KF_ARG_PTR_TO_MEM_SIZE:\n \t\tcase KF_ARG_PTR_TO_CALLBACK:\n-\t\tcase KF_ARG_PTR_TO_REFCOUNTED_KPTR:\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@@ -12128,6 +12135,10 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_\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@@ -12135,7 +12146,8 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_\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\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 \ndiff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c\nindex 7247a20c0a3bf5..77cda5ca236012 100644\n--- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c\n+++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c\n@@ -13,12 +13,22 @@ struct node_acquire {\n \tstruct bpf_refcount refcount;\n };\n \n+struct node_refcounted {\n+\tlong key;\n+\tstruct bpf_rb_node rb;\n+\tstruct bpf_list_node list;\n+\tstruct bpf_refcount refcount;\n+};\n+\n extern void bpf_rcu_read_lock(void) __ksym;\n extern void bpf_rcu_read_unlock(void) __ksym;\n \n #define private(name) SEC(\".data.\" #name) __hidden __attribute__((aligned(8)))\n private(A) struct bpf_spin_lock glock;\n private(A) struct bpf_rb_root groot __contains(node_acquire, node);\n+private(B) struct bpf_spin_lock lock;\n+private(B) struct bpf_rb_root root __contains(node_refcounted, rb);\n+private(B) struct bpf_list_head head __contains(node_refcounted, list);\n \n static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b)\n {\n@@ -31,6 +41,17 @@ static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b)\n \treturn node_a-\u003ekey \u003c node_b-\u003ekey;\n }\n \n+static bool less_refcounted(struct bpf_rb_node *a, const struct bpf_rb_node *b)\n+{\n+\tstruct node_refcounted *node_a;\n+\tstruct node_refcounted *node_b;\n+\n+\tnode_a = container_of(a, struct node_refcounted, rb);\n+\tnode_b = container_of(b, struct node_refcounted, rb);\n+\n+\treturn node_a-\u003ekey \u003c node_b-\u003ekey;\n+}\n+\n SEC(\"?tc\")\n __failure __msg(\"Unreleased reference id=4 alloc_insn={{[0-9]+}}\")\n long rbtree_refcounted_node_ref_escapes(void *ctx)\n@@ -93,6 +114,62 @@ long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx)\n \treturn 0;\n }\n \n+SEC(\"?tc\")\n+__failure __msg(\"dereference of modified ptr_ ptr R1\")\n+long refcount_acquire_list_node_offset(void *ctx)\n+{\n+\tstruct node_refcounted *node, *base, *ref;\n+\tstruct bpf_list_node *list_node;\n+\n+\tnode = bpf_obj_new(typeof(*node));\n+\tif (!node)\n+\t\treturn 1;\n+\n+\tbpf_spin_lock(\u0026lock);\n+\tbpf_list_push_front(\u0026head, \u0026node-\u003elist);\n+\tlist_node = bpf_list_pop_front(\u0026head);\n+\tbpf_spin_unlock(\u0026lock);\n+\tif (!list_node)\n+\t\treturn 2;\n+\n+\tbase = container_of(list_node, struct node_refcounted, list);\n+\tref = bpf_refcount_acquire(list_node);\n+\tif (ref)\n+\t\tbpf_obj_drop(ref);\n+\tbpf_obj_drop(base);\n+\treturn 0;\n+}\n+\n+SEC(\"?tc\")\n+__failure __msg(\"dereference of modified ptr_ ptr R1\")\n+long refcount_acquire_rbtree_node_offset(void *ctx)\n+{\n+\tstruct node_refcounted *node, *base, *ref;\n+\tstruct bpf_rb_node *rb_node;\n+\n+\tnode = bpf_obj_new(typeof(*node));\n+\tif (!node)\n+\t\treturn 1;\n+\n+\tnode-\u003ekey = 1;\n+\n+\tbpf_spin_lock(\u0026lock);\n+\tbpf_rbtree_add(\u0026root, \u0026node-\u003erb, less_refcounted);\n+\trb_node = bpf_rbtree_first(\u0026root);\n+\tif (rb_node)\n+\t\trb_node = bpf_rbtree_remove(\u0026root, rb_node);\n+\tbpf_spin_unlock(\u0026lock);\n+\tif (!rb_node)\n+\t\treturn 2;\n+\n+\tbase = container_of(rb_node, struct node_refcounted, rb);\n+\tref = bpf_refcount_acquire(rb_node);\n+\tif (ref)\n+\t\tbpf_obj_drop(ref);\n+\tbpf_obj_drop(base);\n+\treturn 0;\n+}\n+\n SEC(\"?fentry.s/\" SYS_PREFIX \"sys_getpgid\")\n __failure __msg(\"function calls are not allowed while holding a lock\")\n int BPF_PROG(rbtree_fail_sleepable_lock_across_rcu,\n"
} |
| 2/1 | 2026/06/22 02:47 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"__check_func_arg_reg_off",
"check_kfunc_args",
"bpf_refcount_acquire"
],
"Reasoning": "The patch modifies the BPF verifier to restrict the allowed offset for KF_ARG_PTR_TO_REFCOUNTED_KPTR arguments to 0. This is a functional change in the core BPF verifier logic, reachable from userspace via the bpf() syscall, and should be fuzzed to ensure it correctly rejects invalid offsets without breaking valid use cases.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit acf0ae823dd377acee71eca0e9dfe3f24f1e8041
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jun 22 02:47:48 2026 +0000
syz-cluster: applied patch under review
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2abc79dbf281c2..f65eff28ecd25e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7990,9 +7990,10 @@ 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)
+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)
{
u32 type = reg->type;
@@ -8049,12 +8050,11 @@ static int check_func_arg_reg_off(struct bpf_verifier_env *env,
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. This was already checked above. So pass
- * fixed_off_ok as true to allow fixed offset for all other
- * cases. var_off always must be 0 for PTR_TO_BTF_ID, hence we
- * still need to do checks instead of returning.
+ * 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.
*/
- return __check_ptr_off_reg(env, reg, argno, true);
+ return __check_ptr_off_reg(env, reg, argno, btf_id_fixed_off_ok);
case PTR_TO_CTX:
/*
* Allow fixed and variable offsets for syscall context, but
@@ -8070,6 +8070,13 @@ 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)
{
@@ -11941,6 +11948,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
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, type_size;
bool is_ret_buf_sz = false;
int kf_arg_type;
@@ -12114,7 +12122,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
case KF_ARG_PTR_TO_MEM:
case KF_ARG_PTR_TO_MEM_SIZE:
case KF_ARG_PTR_TO_CALLBACK:
- case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
case KF_ARG_PTR_TO_CONST_STR:
case KF_ARG_PTR_TO_WORKQUEUE:
case KF_ARG_PTR_TO_TIMER:
@@ -12128,6 +12135,10 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
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;
@@ -12135,7 +12146,8 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
if (regno == meta->release_regno)
arg_type |= OBJ_RELEASE;
- ret = check_func_arg_reg_off(env, reg, argno, arg_type);
+ ret = __check_func_arg_reg_off(env, reg, argno, arg_type,
+ btf_id_fixed_off_ok);
if (ret < 0)
return ret;
diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
index 7247a20c0a3bf5..77cda5ca236012 100644
--- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
@@ -13,12 +13,22 @@ struct node_acquire {
struct bpf_refcount refcount;
};
+struct node_refcounted {
+ long key;
+ struct bpf_rb_node rb;
+ struct bpf_list_node list;
+ struct bpf_refcount refcount;
+};
+
extern void bpf_rcu_read_lock(void) __ksym;
extern void bpf_rcu_read_unlock(void) __ksym;
#define private(name) SEC(".data." #name) __hidden __attribute__((aligned(8)))
private(A) struct bpf_spin_lock glock;
private(A) struct bpf_rb_root groot __contains(node_acquire, node);
+private(B) struct bpf_spin_lock lock;
+private(B) struct bpf_rb_root root __contains(node_refcounted, rb);
+private(B) struct bpf_list_head head __contains(node_refcounted, list);
static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b)
{
@@ -31,6 +41,17 @@ static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b)
return node_a->key < node_b->key;
}
+static bool less_refcounted(struct bpf_rb_node *a, const struct bpf_rb_node *b)
+{
+ struct node_refcounted *node_a;
+ struct node_refcounted *node_b;
+
+ node_a = container_of(a, struct node_refcounted, rb);
+ node_b = container_of(b, struct node_refcounted, rb);
+
+ return node_a->key < node_b->key;
+}
+
SEC("?tc")
__failure __msg("Unreleased reference id=4 alloc_insn={{[0-9]+}}")
long rbtree_refcounted_node_ref_escapes(void *ctx)
@@ -93,6 +114,62 @@ long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx)
return 0;
}
+SEC("?tc")
+__failure __msg("dereference of modified ptr_ ptr R1")
+long refcount_acquire_list_node_offset(void *ctx)
+{
+ struct node_refcounted *node, *base, *ref;
+ struct bpf_list_node *list_node;
+
+ node = bpf_obj_new(typeof(*node));
+ if (!node)
+ return 1;
+
+ bpf_spin_lock(&lock);
+ bpf_list_push_front(&head, &node->list);
+ list_node = bpf_list_pop_front(&head);
+ bpf_spin_unlock(&lock);
+ if (!list_node)
+ return 2;
+
+ base = container_of(list_node, struct node_refcounted, list);
+ ref = bpf_refcount_acquire(list_node);
+ if (ref)
+ bpf_obj_drop(ref);
+ bpf_obj_drop(base);
+ return 0;
+}
+
+SEC("?tc")
+__failure __msg("dereference of modified ptr_ ptr R1")
+long refcount_acquire_rbtree_node_offset(void *ctx)
+{
+ struct node_refcounted *node, *base, *ref;
+ struct bpf_rb_node *rb_node;
+
+ node = bpf_obj_new(typeof(*node));
+ if (!node)
+ return 1;
+
+ node->key = 1;
+
+ bpf_spin_lock(&lock);
+ bpf_rbtree_add(&root, &node->rb, less_refcounted);
+ rb_node = bpf_rbtree_first(&root);
+ if (rb_node)
+ rb_node = bpf_rbtree_remove(&root, rb_node);
+ bpf_spin_unlock(&lock);
+ if (!rb_node)
+ return 2;
+
+ base = container_of(rb_node, struct node_refcounted, rb);
+ ref = bpf_refcount_acquire(rb_node);
+ if (ref)
+ bpf_obj_drop(ref);
+ bpf_obj_drop(base);
+ return 0;
+}
+
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
__failure __msg("function calls are not allowed while holding a lock")
int BPF_PROG(rbtree_fail_sleepable_lock_across_rcu,
|
| 3/2 | 2026/06/22 02:47 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 4422 output: 28 thoughts: 243 Thoughts: **Analyzing a BPF Verifier Patch** Okay, so I'm looking at this patch that tweaks the BPF verifier, specifically within `kernel/bpf/verifier.c`. They've added some tests, too, which is always good – specifically in `tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c`. The core of the change seems to be in a function called `check_func_arg_reg_off`. It's been renamed (or maybe just declared, and the original function is still there?) to `__check_func_arg_reg_off`, and now accepts an extra boolean argument, `btf_id_fixed_off_ok`. That's the key. Now, in `check_kfunc_args`, they're handling arguments of the `KF_ARG_PTR_TO_REFCOUNTED_KPTR` type. This is where it gets interesting, and I need to dive in a bit deeper. What they're doing is, when they encounter this argument type, they set `arg_type` to `ARG_PTR_TO_BTF_ID` and critically, set `btf_id_fixed_off_ok = false`. This means they're explicitly *disallowing* a fixed offset for `KF_ARG_PTR_TO_REFCOUNTED_KPTR` arguments. Effectively, they're enforcing that the offset has to be zero, right? No wiggle room. I need to see the surrounding code in `kernel/bpf/verifier.c` to fully understand the rationale behind this change. So, I'll use `grepper` to quickly find the `check_kfunc_args` function and specifically how it handles `KF_ARG_PTR_TO_REFCOUNTED_KPTR`. Understanding the context is crucial to evaluating the implications of this restriction. I need to see how the verifier utilizes that `arg_type` and the implications of forbidding a fixed offset in this specific scenario. |
| 4/2 | 2026/06/22 02:47 | tool | grepper |
0mArgs:{
"Expression": "KF_ARG_PTR_TO_REFCOUNTED_KPTR"
}Results: {
"Output": "include/linux/bpf_verifier.h=1441=struct bpf_kfunc_call_arg_meta {\n--\ninclude/linux/bpf_verifier.h-1463-\t * Record the local kptr type to be drop'd\ninclude/linux/bpf_verifier.h:1464:\t * bpf_refcount_acquire (via KF_ARG_PTR_TO_REFCOUNTED_KPTR arg type)\ninclude/linux/bpf_verifier.h-1465-\t * Record the local kptr type to be refcount_incr'd and use\n--\nkernel/bpf/verifier.c=10965=enum kfunc_ptr_arg_type {\n--\nkernel/bpf/verifier.c-10967-\tKF_ARG_PTR_TO_ALLOC_BTF_ID, /* Allocated object */\nkernel/bpf/verifier.c:10968:\tKF_ARG_PTR_TO_REFCOUNTED_KPTR, /* Refcounted local kptr */\nkernel/bpf/verifier.c-10969-\tKF_ARG_PTR_TO_DYNPTR,\n--\nkernel/bpf/verifier.c=11243=get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, struct bpf_func_state *caller,\n--\nkernel/bpf/verifier.c-11276-\tif (is_kfunc_arg_refcounted_kptr(meta-\u003ebtf, \u0026args[arg]))\nkernel/bpf/verifier.c:11277:\t\treturn KF_ARG_PTR_TO_REFCOUNTED_KPTR;\nkernel/bpf/verifier.c-11278-\n--\nkernel/bpf/verifier.c=11913=static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_arg_meta *meta,\n--\nkernel/bpf/verifier.c-12137-\t\t\tbreak;\nkernel/bpf/verifier.c:12138:\t\tcase KF_ARG_PTR_TO_REFCOUNTED_KPTR:\nkernel/bpf/verifier.c-12139-\t\t\targ_type = ARG_PTR_TO_BTF_ID;\n--\nkernel/bpf/verifier.c-12400-\t\t\tbreak;\nkernel/bpf/verifier.c:12401:\t\tcase KF_ARG_PTR_TO_REFCOUNTED_KPTR:\nkernel/bpf/verifier.c-12402-\t\t\tif (!type_is_ptr_alloc_obj(reg-\u003etype)) {\n"
} |
| 5/2 | 2026/06/22 02:47 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 5787 output: 21 thoughts: 133 Thoughts: **Fuzzing Potential: BPF Verifier Modification** Okay, so this patch is tweaking how the BPF verifier deals with `KF_ARG_PTR_TO_REFCOUNTED_KPTR` arguments passed to kfuncs. That's immediately interesting because if there's a change in the verifier's logic, especially around how it validates those arguments, it's a prime target for fuzzing, and it's reachable from userspace through `bpf()`. That's a good start. My first thought is, what kfuncs are even *using* this argument type? I need to understand the scope of the change. Luckily the comment mentions that this argument type is used with `bpf_refcount_acquire`. That gives me a keyword to grep for. Let's see what pops up when I search for that. Knowing that should give me a good understanding of what's potentially affected. Time to get to it. |
| 6/2 | 2026/06/22 02:48 | tool | grepper |
0mArgs:{
"Expression": "bpf_refcount_acquire"
}Results: {
"Output": "include/linux/bpf_verifier.h=1441=struct bpf_kfunc_call_arg_meta {\n--\ninclude/linux/bpf_verifier.h-1463-\t * Record the local kptr type to be drop'd\ninclude/linux/bpf_verifier.h:1464:\t * bpf_refcount_acquire (via KF_ARG_PTR_TO_REFCOUNTED_KPTR arg type)\ninclude/linux/bpf_verifier.h-1465-\t * Record the local kptr type to be refcount_incr'd and use\n--\nkernel/bpf/helpers.c=2449=__bpf_kfunc void bpf_percpu_obj_drop_impl(void *p__alloc, void *meta__ign)\n--\nkernel/bpf/helpers.c-2454-/**\nkernel/bpf/helpers.c:2455: * bpf_refcount_acquire() - turn a local kptr into an owning reference\nkernel/bpf/helpers.c-2456- * @p__refcounted_kptr: non-owning local kptr\n--\nkernel/bpf/helpers.c-2463- */\nkernel/bpf/helpers.c:2464:__bpf_kfunc void *bpf_refcount_acquire(void *p__refcounted_kptr, struct btf_struct_meta *meta)\nkernel/bpf/helpers.c-2465-{\n--\nkernel/bpf/helpers.c-2480-\nkernel/bpf/helpers.c:2481:__bpf_kfunc void *bpf_refcount_acquire_impl(void *p__refcounted_kptr, void *meta__ign)\nkernel/bpf/helpers.c-2482-{\nkernel/bpf/helpers.c:2483:\treturn bpf_refcount_acquire(p__refcounted_kptr, meta__ign);\nkernel/bpf/helpers.c-2484-}\n--\nkernel/bpf/helpers.c=4813=BTF_ID_FLAGS(func, bpf_percpu_obj_drop_impl, KF_RELEASE)\nkernel/bpf/helpers.c:4814:BTF_ID_FLAGS(func, bpf_refcount_acquire, KF_ACQUIRE | KF_RET_NULL | KF_RCU | KF_IMPLICIT_ARGS)\nkernel/bpf/helpers.c:4815:BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE | KF_RET_NULL | KF_RCU)\nkernel/bpf/helpers.c-4816-BTF_ID_FLAGS(func, bpf_list_push_front, KF_IMPLICIT_ARGS)\n--\nkernel/bpf/verifier.c=10989=enum special_kfunc_type {\n--\nkernel/bpf/verifier.c-10993-\tKF_bpf_obj_drop,\nkernel/bpf/verifier.c:10994:\tKF_bpf_refcount_acquire_impl,\nkernel/bpf/verifier.c:10995:\tKF_bpf_refcount_acquire,\nkernel/bpf/verifier.c-10996-\tKF_bpf_list_push_front_impl,\n--\nkernel/bpf/verifier.c=11066=BTF_ID(func, bpf_obj_drop)\nkernel/bpf/verifier.c:11067:BTF_ID(func, bpf_refcount_acquire_impl)\nkernel/bpf/verifier.c:11068:BTF_ID(func, bpf_refcount_acquire)\nkernel/bpf/verifier.c-11069-BTF_ID(func, bpf_list_push_front_impl)\n--\nkernel/bpf/verifier.c=11176=static bool is_bpf_percpu_obj_drop_kfunc(u32 func_id)\n--\nkernel/bpf/verifier.c-11181-\nkernel/bpf/verifier.c:11182:static bool is_bpf_refcount_acquire_kfunc(u32 func_id)\nkernel/bpf/verifier.c-11183-{\nkernel/bpf/verifier.c:11184:\treturn func_id == special_kfunc_list[KF_bpf_refcount_acquire] ||\nkernel/bpf/verifier.c:11185:\t func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl];\nkernel/bpf/verifier.c-11186-}\n--\nkernel/bpf/verifier.c=11209=static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta)\nkernel/bpf/verifier.c-11210-{\nkernel/bpf/verifier.c:11211:\tif (is_bpf_refcount_acquire_kfunc(meta-\u003efunc_id) \u0026\u0026 meta-\u003earg_owning_ref)\nkernel/bpf/verifier.c-11212-\t\treturn false;\n--\nkernel/bpf/verifier.c=11617=static bool is_bpf_graph_api_kfunc(u32 btf_id)\n--\nkernel/bpf/verifier.c-11620-\t is_bpf_rbtree_api_kfunc(btf_id) ||\nkernel/bpf/verifier.c:11621:\t is_bpf_refcount_acquire_kfunc(btf_id);\nkernel/bpf/verifier.c-11622-}\n--\nkernel/bpf/verifier.c=12727=static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_call_arg_meta *meta,\n--\nkernel/bpf/verifier.c-12815-\t\tinsn_aux-\u003ekptr_struct_meta = struct_meta;\nkernel/bpf/verifier.c:12816:\t} else if (is_bpf_refcount_acquire_kfunc(meta-\u003efunc_id)) {\nkernel/bpf/verifier.c-12817-\t\tmark_reg_known_zero(env, regs, BPF_REG_0);\n--\nkernel/bpf/verifier.c=12898=static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\n--\nkernel/bpf/verifier.c-13118-\t\t !is_bpf_percpu_obj_new_kfunc(meta.func_id) \u0026\u0026\nkernel/bpf/verifier.c:13119:\t\t !is_bpf_refcount_acquire_kfunc(meta.func_id))) {\nkernel/bpf/verifier.c-13120-\t\t\tverbose(env, \"acquire kernel function does not return PTR_TO_BTF_ID\\n\");\n--\nkernel/bpf/verifier.c=19574=int bpf_fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\n--\nkernel/bpf/verifier.c-19622-\t\t is_bpf_percpu_obj_drop_kfunc(desc-\u003efunc_id) ||\nkernel/bpf/verifier.c:19623:\t\t is_bpf_refcount_acquire_kfunc(desc-\u003efunc_id)) {\nkernel/bpf/verifier.c-19624-\t\tstruct btf_struct_meta *kptr_struct_meta = env-\u003einsn_aux_data[insn_idx].kptr_struct_meta;\n--\nkernel/bpf/verifier.c-19632-\nkernel/bpf/verifier.c:19633:\t\tif (is_bpf_refcount_acquire_kfunc(desc-\u003efunc_id) \u0026\u0026 !kptr_struct_meta) {\nkernel/bpf/verifier.c-19634-\t\t\tverifier_bug(env, \"kptr_struct_meta expected at insn_idx %d\",\n--\ntools/sched_ext/include/scx/common.bpf.h=384=struct bpf_rb_node *bpf_rbtree_first(struct bpf_rb_root *root) __ksym;\ntools/sched_ext/include/scx/common.bpf.h-385-\ntools/sched_ext/include/scx/common.bpf.h:386:void *bpf_refcount_acquire_impl(void *kptr, void *meta) __ksym;\ntools/sched_ext/include/scx/common.bpf.h:387:#define bpf_refcount_acquire(kptr) bpf_refcount_acquire_impl(kptr, NULL)\ntools/sched_ext/include/scx/common.bpf.h-388-\n--\ntools/testing/selftests/bpf/progs/bpf_qdisc_fq.c=303=int BPF_PROG(bpf_fq_enqueue, struct sk_buff *skb, struct Qdisc *sch,\n--\ntools/testing/selftests/bpf/progs/bpf_qdisc_fq.c-344-\t\tif (fq_flow_is_detached(flow)) {\ntools/testing/selftests/bpf/progs/bpf_qdisc_fq.c:345:\t\t\tflow_copy = bpf_refcount_acquire(flow);\ntools/testing/selftests/bpf/progs/bpf_qdisc_fq.c-346-\n--\ntools/testing/selftests/bpf/progs/local_kptr_stash.c=234=long refcount_acquire_without_unstash(void *ctx)\n--\ntools/testing/selftests/bpf/progs/local_kptr_stash.c-249-\ntools/testing/selftests/bpf/progs/local_kptr_stash.c:250:\tp = bpf_refcount_acquire(s-\u003estashed);\ntools/testing/selftests/bpf/progs/local_kptr_stash.c-251-\tif (!p)\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c=53=long rbtree_search(void *ctx)\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c-64-\ntools/testing/selftests/bpf/progs/rbtree_search.c:65:\t\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/rbtree_search.c-66-\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c-108-\ntools/testing/selftests/bpf/progs/rbtree_search.c:109:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/rbtree_search.c-110-\tbpf_spin_unlock(\u0026glock0);\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c=156=long test_##op##_spinlock_##dolock(void *ctx)\t\t\\\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c-168-\tn = rb_entry(rb_n, struct node_data, r0);\t\\\ntools/testing/selftests/bpf/progs/rbtree_search.c:169:\tn = bpf_refcount_acquire(n);\t\t\t\\\ntools/testing/selftests/bpf/progs/rbtree_search.c-170-\tbpf_spin_unlock(\u0026glock0);\t\t\t\\\n--\ntools/testing/selftests/bpf/progs/rbtree_search_kptr.c=155=long rbtree_search_kptr_ref(void *ctx)\n--\ntools/testing/selftests/bpf/progs/rbtree_search_kptr.c-182-\t\t/* Unused reference */\ntools/testing/selftests/bpf/progs/rbtree_search_kptr.c:183:\t\ttnode_m = bpf_refcount_acquire(tnode_r);\ntools/testing/selftests/bpf/progs/rbtree_search_kptr.c-184-\t\tif (!tnode_m)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=73=static long __insert_in_tree_and_list(struct bpf_list_head *head,\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-82-\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:83:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-84-\tm-\u003ekey = 123;\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=106=static long __stash_map_insert_tree(int idx, int val, struct bpf_rb_root *root,\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-120-\tn-\u003ekey = val;\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:121:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-122-\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=399=static struct node_data *__add_in_list(struct bpf_list_head *head,\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-407-\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:408:\tnode_ref = bpf_refcount_acquire(node_new);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-409-\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=793=long rbtree_refcounted_node_ref_escapes(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-802-\tbpf_rbtree_add(\u0026aroot, \u0026n-\u003enode, less_a);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:803:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-804-\tbpf_spin_unlock(\u0026alock);\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=815=long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-822-\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:823:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-824-\tm-\u003ekey = 2;\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=852=long rbtree_wrong_owner_remove_fail_a1(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-858-\t\treturn 1;\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:859:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-860-\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=1002=static int __insert_in_list(struct bpf_list_head *head, struct bpf_spin_lock *lock,\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-1010-\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:1011:\tnode_ref = bpf_refcount_acquire(node_new);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-1012-\tnode_old = bpf_kptr_xchg(node, node_new);\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=57=long rbtree_refcounted_node_ref_escapes(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-67-\t/* m becomes an owning ref but is never drop'd or added to a tree */\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:68:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-69-\tbpf_spin_unlock(\u0026glock);\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=79=long refcount_acquire_maybe_null(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-86-\t */\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:87:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-88-\tif (m)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=98=long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-106-\t/* m becomes an owning ref but is never drop'd or added to a tree */\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:107:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-108-\tm-\u003ekey = 2;\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=119=long refcount_acquire_list_node_offset(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-135-\tbase = container_of(list_node, struct node_refcounted, list);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:136:\tref = bpf_refcount_acquire(list_node);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-137-\tif (ref)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=145=long refcount_acquire_rbtree_node_offset(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-165-\tbase = container_of(rb_node, struct node_refcounted, rb);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:166:\tref = bpf_refcount_acquire(rb_node);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-167-\tif (ref)\n"
} |
| 7/2 | 2026/06/22 02:48 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11288 output: 21 thoughts: 311 Thoughts: **Analyzing the Restriction on `bpf_refcount_acquire` with Refcounted KPTRs** Okay, so I'm looking at this patch and tracing through the implications for `bpf_refcount_acquire`. The core change centers around the `KF_ARG_PTR_TO_REFCOUNTED_KPTR` argument type and how it interacts with the verifier. It seems the commit explicitly modifies `check_kfunc_args` to ensure `btf_id_fixed_off_ok` is `false` when dealing with `KF_ARG_PTR_TO_REFCOUNTED_KPTR`. This is pretty crucial. What this *actually* means is that we're preventing `bpf_refcount_acquire` from being called with any non-zero fixed offset, which is by design, obviously, for security reasons. Now, the added tests in `tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c` are a nice confirmation of this restriction. Passing things like `list_node` or `rb_node`, both of which have those forbidden offsets within the `struct node_refcounted` structure, will now be correctly rejected during verification. This is a good sanity check and also gives examples of the forbidden operations. Therefore, the key pieces of code I need to really understand this are: `check_kfunc_args`, `__check_func_arg_reg_off`, and obviously, `bpf_refcount_acquire` itself. I need to see how the verifier makes sure the offset is zero. I know the code for these functions is in `kernel/bpf/verifier.c` and `kernel/bpf/helpers.c`, so I'll check there. I'm assuming that the BPF subsystem is enabled via `CONFIG_BPF_SYSCALL`, but I need to make sure. I'll need to double check the kernel config for that, and perhaps look around `kernel/bpf/Kconfig` or even `init/Kconfig` to see if there are any other configuration dependencies or flags that might be relevant to this specific functionality. Just to be sure. |
| 8/2 | 2026/06/22 02:48 | tool | grepper |
0mArgs:{
"Expression": "config BPF_SYSCALL"
}Results: {
"Output": "kernel/bpf/Kconfig=25=menu \"BPF subsystem\"\nkernel/bpf/Kconfig-26-\nkernel/bpf/Kconfig:27:config BPF_SYSCALL\nkernel/bpf/Kconfig-28-\tbool \"Enable bpf() system call\"\n"
} |
| 9/2 | 2026/06/22 02:48 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 12169 output: 21 thoughts: 62 Thoughts: **Kernel BPF Considerations** Okay, so I'm thinking about BPF syscalls, and `CONFIG_BPF_SYSCALL` immediately springs to mind as the pivotal configuration option. However, I need to consider the broader context here. I'm wondering if `bpf_refcount_acquire` is something that's always available, or if it's dependent on the program type or some other factor. To be absolutely certain, I really need to drill down and examine the implementation. I'll need to check the function definition in `kernel/bpf/helpers.c`. That's where the answer is going to be. |
| 10/2 | 2026/06/22 02:48 | tool | grepper |
0mArgs:{
"Expression": "bpf_refcount_acquire"
}Results: {
"Output": "include/linux/bpf_verifier.h=1441=struct bpf_kfunc_call_arg_meta {\n--\ninclude/linux/bpf_verifier.h-1463-\t * Record the local kptr type to be drop'd\ninclude/linux/bpf_verifier.h:1464:\t * bpf_refcount_acquire (via KF_ARG_PTR_TO_REFCOUNTED_KPTR arg type)\ninclude/linux/bpf_verifier.h-1465-\t * Record the local kptr type to be refcount_incr'd and use\n--\nkernel/bpf/helpers.c=2449=__bpf_kfunc void bpf_percpu_obj_drop_impl(void *p__alloc, void *meta__ign)\n--\nkernel/bpf/helpers.c-2454-/**\nkernel/bpf/helpers.c:2455: * bpf_refcount_acquire() - turn a local kptr into an owning reference\nkernel/bpf/helpers.c-2456- * @p__refcounted_kptr: non-owning local kptr\n--\nkernel/bpf/helpers.c-2463- */\nkernel/bpf/helpers.c:2464:__bpf_kfunc void *bpf_refcount_acquire(void *p__refcounted_kptr, struct btf_struct_meta *meta)\nkernel/bpf/helpers.c-2465-{\n--\nkernel/bpf/helpers.c-2480-\nkernel/bpf/helpers.c:2481:__bpf_kfunc void *bpf_refcount_acquire_impl(void *p__refcounted_kptr, void *meta__ign)\nkernel/bpf/helpers.c-2482-{\nkernel/bpf/helpers.c:2483:\treturn bpf_refcount_acquire(p__refcounted_kptr, meta__ign);\nkernel/bpf/helpers.c-2484-}\n--\nkernel/bpf/helpers.c=4813=BTF_ID_FLAGS(func, bpf_percpu_obj_drop_impl, KF_RELEASE)\nkernel/bpf/helpers.c:4814:BTF_ID_FLAGS(func, bpf_refcount_acquire, KF_ACQUIRE | KF_RET_NULL | KF_RCU | KF_IMPLICIT_ARGS)\nkernel/bpf/helpers.c:4815:BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE | KF_RET_NULL | KF_RCU)\nkernel/bpf/helpers.c-4816-BTF_ID_FLAGS(func, bpf_list_push_front, KF_IMPLICIT_ARGS)\n--\nkernel/bpf/verifier.c=10989=enum special_kfunc_type {\n--\nkernel/bpf/verifier.c-10993-\tKF_bpf_obj_drop,\nkernel/bpf/verifier.c:10994:\tKF_bpf_refcount_acquire_impl,\nkernel/bpf/verifier.c:10995:\tKF_bpf_refcount_acquire,\nkernel/bpf/verifier.c-10996-\tKF_bpf_list_push_front_impl,\n--\nkernel/bpf/verifier.c=11066=BTF_ID(func, bpf_obj_drop)\nkernel/bpf/verifier.c:11067:BTF_ID(func, bpf_refcount_acquire_impl)\nkernel/bpf/verifier.c:11068:BTF_ID(func, bpf_refcount_acquire)\nkernel/bpf/verifier.c-11069-BTF_ID(func, bpf_list_push_front_impl)\n--\nkernel/bpf/verifier.c=11176=static bool is_bpf_percpu_obj_drop_kfunc(u32 func_id)\n--\nkernel/bpf/verifier.c-11181-\nkernel/bpf/verifier.c:11182:static bool is_bpf_refcount_acquire_kfunc(u32 func_id)\nkernel/bpf/verifier.c-11183-{\nkernel/bpf/verifier.c:11184:\treturn func_id == special_kfunc_list[KF_bpf_refcount_acquire] ||\nkernel/bpf/verifier.c:11185:\t func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl];\nkernel/bpf/verifier.c-11186-}\n--\nkernel/bpf/verifier.c=11209=static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta)\nkernel/bpf/verifier.c-11210-{\nkernel/bpf/verifier.c:11211:\tif (is_bpf_refcount_acquire_kfunc(meta-\u003efunc_id) \u0026\u0026 meta-\u003earg_owning_ref)\nkernel/bpf/verifier.c-11212-\t\treturn false;\n--\nkernel/bpf/verifier.c=11617=static bool is_bpf_graph_api_kfunc(u32 btf_id)\n--\nkernel/bpf/verifier.c-11620-\t is_bpf_rbtree_api_kfunc(btf_id) ||\nkernel/bpf/verifier.c:11621:\t is_bpf_refcount_acquire_kfunc(btf_id);\nkernel/bpf/verifier.c-11622-}\n--\nkernel/bpf/verifier.c=12727=static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_call_arg_meta *meta,\n--\nkernel/bpf/verifier.c-12815-\t\tinsn_aux-\u003ekptr_struct_meta = struct_meta;\nkernel/bpf/verifier.c:12816:\t} else if (is_bpf_refcount_acquire_kfunc(meta-\u003efunc_id)) {\nkernel/bpf/verifier.c-12817-\t\tmark_reg_known_zero(env, regs, BPF_REG_0);\n--\nkernel/bpf/verifier.c=12898=static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\n--\nkernel/bpf/verifier.c-13118-\t\t !is_bpf_percpu_obj_new_kfunc(meta.func_id) \u0026\u0026\nkernel/bpf/verifier.c:13119:\t\t !is_bpf_refcount_acquire_kfunc(meta.func_id))) {\nkernel/bpf/verifier.c-13120-\t\t\tverbose(env, \"acquire kernel function does not return PTR_TO_BTF_ID\\n\");\n--\nkernel/bpf/verifier.c=19574=int bpf_fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,\n--\nkernel/bpf/verifier.c-19622-\t\t is_bpf_percpu_obj_drop_kfunc(desc-\u003efunc_id) ||\nkernel/bpf/verifier.c:19623:\t\t is_bpf_refcount_acquire_kfunc(desc-\u003efunc_id)) {\nkernel/bpf/verifier.c-19624-\t\tstruct btf_struct_meta *kptr_struct_meta = env-\u003einsn_aux_data[insn_idx].kptr_struct_meta;\n--\nkernel/bpf/verifier.c-19632-\nkernel/bpf/verifier.c:19633:\t\tif (is_bpf_refcount_acquire_kfunc(desc-\u003efunc_id) \u0026\u0026 !kptr_struct_meta) {\nkernel/bpf/verifier.c-19634-\t\t\tverifier_bug(env, \"kptr_struct_meta expected at insn_idx %d\",\n--\ntools/sched_ext/include/scx/common.bpf.h=384=struct bpf_rb_node *bpf_rbtree_first(struct bpf_rb_root *root) __ksym;\ntools/sched_ext/include/scx/common.bpf.h-385-\ntools/sched_ext/include/scx/common.bpf.h:386:void *bpf_refcount_acquire_impl(void *kptr, void *meta) __ksym;\ntools/sched_ext/include/scx/common.bpf.h:387:#define bpf_refcount_acquire(kptr) bpf_refcount_acquire_impl(kptr, NULL)\ntools/sched_ext/include/scx/common.bpf.h-388-\n--\ntools/testing/selftests/bpf/progs/bpf_qdisc_fq.c=303=int BPF_PROG(bpf_fq_enqueue, struct sk_buff *skb, struct Qdisc *sch,\n--\ntools/testing/selftests/bpf/progs/bpf_qdisc_fq.c-344-\t\tif (fq_flow_is_detached(flow)) {\ntools/testing/selftests/bpf/progs/bpf_qdisc_fq.c:345:\t\t\tflow_copy = bpf_refcount_acquire(flow);\ntools/testing/selftests/bpf/progs/bpf_qdisc_fq.c-346-\n--\ntools/testing/selftests/bpf/progs/local_kptr_stash.c=234=long refcount_acquire_without_unstash(void *ctx)\n--\ntools/testing/selftests/bpf/progs/local_kptr_stash.c-249-\ntools/testing/selftests/bpf/progs/local_kptr_stash.c:250:\tp = bpf_refcount_acquire(s-\u003estashed);\ntools/testing/selftests/bpf/progs/local_kptr_stash.c-251-\tif (!p)\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c=53=long rbtree_search(void *ctx)\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c-64-\ntools/testing/selftests/bpf/progs/rbtree_search.c:65:\t\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/rbtree_search.c-66-\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c-108-\ntools/testing/selftests/bpf/progs/rbtree_search.c:109:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/rbtree_search.c-110-\tbpf_spin_unlock(\u0026glock0);\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c=156=long test_##op##_spinlock_##dolock(void *ctx)\t\t\\\n--\ntools/testing/selftests/bpf/progs/rbtree_search.c-168-\tn = rb_entry(rb_n, struct node_data, r0);\t\\\ntools/testing/selftests/bpf/progs/rbtree_search.c:169:\tn = bpf_refcount_acquire(n);\t\t\t\\\ntools/testing/selftests/bpf/progs/rbtree_search.c-170-\tbpf_spin_unlock(\u0026glock0);\t\t\t\\\n--\ntools/testing/selftests/bpf/progs/rbtree_search_kptr.c=155=long rbtree_search_kptr_ref(void *ctx)\n--\ntools/testing/selftests/bpf/progs/rbtree_search_kptr.c-182-\t\t/* Unused reference */\ntools/testing/selftests/bpf/progs/rbtree_search_kptr.c:183:\t\ttnode_m = bpf_refcount_acquire(tnode_r);\ntools/testing/selftests/bpf/progs/rbtree_search_kptr.c-184-\t\tif (!tnode_m)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=73=static long __insert_in_tree_and_list(struct bpf_list_head *head,\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-82-\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:83:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-84-\tm-\u003ekey = 123;\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=106=static long __stash_map_insert_tree(int idx, int val, struct bpf_rb_root *root,\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-120-\tn-\u003ekey = val;\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:121:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-122-\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=399=static struct node_data *__add_in_list(struct bpf_list_head *head,\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-407-\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:408:\tnode_ref = bpf_refcount_acquire(node_new);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-409-\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=793=long rbtree_refcounted_node_ref_escapes(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-802-\tbpf_rbtree_add(\u0026aroot, \u0026n-\u003enode, less_a);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:803:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-804-\tbpf_spin_unlock(\u0026alock);\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=815=long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-822-\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:823:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-824-\tm-\u003ekey = 2;\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=852=long rbtree_wrong_owner_remove_fail_a1(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-858-\t\treturn 1;\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:859:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-860-\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c=1002=static int __insert_in_list(struct bpf_list_head *head, struct bpf_spin_lock *lock,\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-1010-\ntools/testing/selftests/bpf/progs/refcounted_kptr.c:1011:\tnode_ref = bpf_refcount_acquire(node_new);\ntools/testing/selftests/bpf/progs/refcounted_kptr.c-1012-\tnode_old = bpf_kptr_xchg(node, node_new);\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=57=long rbtree_refcounted_node_ref_escapes(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-67-\t/* m becomes an owning ref but is never drop'd or added to a tree */\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:68:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-69-\tbpf_spin_unlock(\u0026glock);\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=79=long refcount_acquire_maybe_null(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-86-\t */\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:87:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-88-\tif (m)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=98=long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-106-\t/* m becomes an owning ref but is never drop'd or added to a tree */\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:107:\tm = bpf_refcount_acquire(n);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-108-\tm-\u003ekey = 2;\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=119=long refcount_acquire_list_node_offset(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-135-\tbase = container_of(list_node, struct node_refcounted, list);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:136:\tref = bpf_refcount_acquire(list_node);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-137-\tif (ref)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c=145=long refcount_acquire_rbtree_node_offset(void *ctx)\n--\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-165-\tbase = container_of(rb_node, struct node_refcounted, rb);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c:166:\tref = bpf_refcount_acquire(rb_node);\ntools/testing/selftests/bpf/progs/refcounted_kptr_fail.c-167-\tif (ref)\n"
} |
| 11/2 | 2026/06/22 02:48 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17535 output: 147 thoughts: 173 Thoughts: **My Assessment of the BPF Verifier Patch** Okay, so the essential configuration here boils down to `BPF_SYSCALL`. I need to synthesize a summary of the approach for the fuzzing. My thinking is this: The key aspects to fuzzing are straightforward, which makes me think of the overall approach to this particular patch. * **WorthFuzzing:** True, definitely. This is critical BPF verifier logic, which can be reached via the `bpf()` syscall. Changes at this level are always good candidates for fuzzing. * **FocusSymbols:** I'll be targeting `__check_func_arg_reg_off`, `check_kfunc_args`, and `bpf_refcount_acquire`. These are the functions directly affected by the offset restriction for `KF_ARG_PTR_TO_REFCOUNTED_KPTR` arguments. I need to specifically test the boundary conditions. * **EnableConfigs:** Confirmed: `BPF_SYSCALL`. This is how userspace interacts with the verifier, so it's the right focus. * **Reasoning:** The patch is altering the verifier's behavior regarding offset restrictions for a specific type of kernel function argument. The aim is to make sure it functions correctly, rejecting incorrect offsets and allowing valid offsets. I have to fuzz to see the patch's changes don't introduce errors in valid cases or miss incorrect cases. This change is security-sensitive, so thorough testing is important. I'll be using `set-results` to record and return the fuzzing outcomes. This summarizes the fuzzing strategy pretty well, so I'm now ready to start setting up the fuzzing environment. |
| 12/2 | 2026/06/22 02:48 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"__check_func_arg_reg_off",
"check_kfunc_args",
"bpf_refcount_acquire"
],
"Reasoning": "The patch modifies the BPF verifier to restrict the allowed offset for KF_ARG_PTR_TO_REFCOUNTED_KPTR arguments to 0. This is a functional change in the core BPF verifier logic, reachable from userspace via the bpf() syscall, and should be fuzzed to ensure it correctly rejects invalid offsets without breaking valid use cases.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"__check_func_arg_reg_off",
"check_kfunc_args",
"bpf_refcount_acquire"
],
"Reasoning": "The patch modifies the BPF verifier to restrict the allowed offset for KF_ARG_PTR_TO_REFCOUNTED_KPTR arguments to 0. This is a functional change in the core BPF verifier logic, reachable from userspace via the bpf() syscall, and should be fuzzed to ensure it correctly rejects invalid offsets without breaking valid use cases.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|