| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/08 05:23 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"check_ptr_to_btf_access"
],
"Reasoning": "The patch modifies the BPF verifier to reject writes to untrusted BTF pointers, which is a functional security/correctness fix in the core BPF logic.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/08 05:23 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit b9db5be8a9cb17b08024f867619e6b46f48463e3\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Jul 8 05:23:29 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c\nindex 3193b473762ba4..7cf555a7026cc1 100644\n--- a/kernel/bpf/verifier.c\n+++ b/kernel/bpf/verifier.c\n@@ -5813,6 +5813,11 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,\n \t\treturn -EACCES;\n \t}\n \n+\tif (atype != BPF_READ \u0026\u0026 (type_flag(reg-\u003etype) \u0026 PTR_UNTRUSTED)) {\n+\t\tverbose(env, \"only read is supported\\n\");\n+\t\treturn -EACCES;\n+\t}\n+\n \tif (env-\u003eops-\u003ebtf_struct_access \u0026\u0026 !type_is_alloc(reg-\u003etype) \u0026\u0026 atype == BPF_WRITE) {\n \t\tif (!btf_is_kernel(reg-\u003ebtf)) {\n \t\t\tverifier_bug(env, \"reg-\u003ebtf must be kernel btf\");\n@@ -5825,8 +5830,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,\n \t\t\t\treg_arg_name(env, argno), tname, off, size);\n \t} else {\n \t\t/* Writes are permitted with default btf_struct_access for\n-\t\t * program allocated objects (which always have id \u003e 0),\n-\t\t * but not for untrusted PTR_TO_BTF_ID | MEM_ALLOC.\n+\t\t * program allocated objects (which always have id \u003e 0).\n \t\t */\n \t\tif (atype != BPF_READ \u0026\u0026 !type_is_ptr_alloc_obj(reg-\u003etype)) {\n \t\t\tverbose(env, \"only read is supported\\n\");\ndiff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c\nindex fe30181e63367d..eb05fc82f81ba6 100644\n--- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c\n+++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c\n@@ -14,6 +14,7 @@\n #include \"tcp_ca_incompl_cong_ops.skel.h\"\n #include \"tcp_ca_unsupp_cong_op.skel.h\"\n #include \"tcp_ca_kfunc.skel.h\"\n+#include \"tcp_ca_untrusted_btf_write.skel.h\"\n #include \"bpf_cc_cubic.skel.h\"\n \n static const unsigned int total_bytes = 10 * 1024 * 1024;\n@@ -579,6 +580,15 @@ static void test_tcp_ca_kfunc(void)\n \ttcp_ca_kfunc__destroy(skel);\n }\n \n+static void test_untrusted_btf_write(void)\n+{\n+\tstruct tcp_ca_untrusted_btf_write *skel;\n+\n+\tskel = tcp_ca_untrusted_btf_write__open_and_load();\n+\tASSERT_ERR_PTR(skel, \"tcp_ca_untrusted_btf_write__open_and_load\");\n+\ttcp_ca_untrusted_btf_write__destroy(skel);\n+}\n+\n static void test_cc_cubic(void)\n {\n \tstruct cb_opts cb_opts = {\n@@ -637,6 +647,8 @@ void test_bpf_tcp_ca(void)\n \t\ttest_link_replace();\n \tif (test__start_subtest(\"tcp_ca_kfunc\"))\n \t\ttest_tcp_ca_kfunc();\n+\tif (test__start_subtest(\"untrusted_btf_write\"))\n+\t\ttest_untrusted_btf_write();\n \tif (test__start_subtest(\"cc_cubic\"))\n \t\ttest_cc_cubic();\n \tif (test__start_subtest(\"dctcp_autoattach_map\"))\ndiff --git a/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c\nnew file mode 100644\nindex 00000000000000..eda4697aac80b6\n--- /dev/null\n+++ b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c\n@@ -0,0 +1,26 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \"bpf_tracing_net.h\"\n+#include \u003cbpf/bpf_core_read.h\u003e\n+#include \u003cbpf/bpf_helpers.h\u003e\n+#include \u003cbpf/bpf_tracing.h\u003e\n+\n+char _license[] SEC(\"license\") = \"GPL\";\n+\n+SEC(\"struct_ops\")\n+void BPF_PROG(untrusted_btf_write_init, struct sock *sk)\n+{\n+\tstruct tcp_sock *tp;\n+\tint v = 1;\n+\tvoid *p;\n+\n+\tp = bpf_rdonly_cast(\u0026v, 0);\n+\ttp = bpf_rdonly_cast(p, bpf_core_type_id_kernel(struct tcp_sock));\n+\ttp-\u003esnd_cwnd = 1;\n+}\n+\n+SEC(\".struct_ops\")\n+struct tcp_congestion_ops untrusted_btf_write = {\n+\t.init = (void *)untrusted_btf_write_init,\n+\t.name = \"bpf_ro_btf\",\n+};\n"
} |
| 2/1 | 2026/07/08 05:23 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"check_ptr_to_btf_access"
],
"Reasoning": "The patch modifies the BPF verifier to reject writes to untrusted BTF pointers, which is a functional security/correctness fix in the core BPF logic.",
"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 b9db5be8a9cb17b08024f867619e6b46f48463e3
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Jul 8 05:23:29 2026 +0000
syz-cluster: applied patch under review
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 3193b473762ba4..7cf555a7026cc1 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5813,6 +5813,11 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
return -EACCES;
}
+ if (atype != BPF_READ && (type_flag(reg->type) & PTR_UNTRUSTED)) {
+ verbose(env, "only read is supported\n");
+ return -EACCES;
+ }
+
if (env->ops->btf_struct_access && !type_is_alloc(reg->type) && atype == BPF_WRITE) {
if (!btf_is_kernel(reg->btf)) {
verifier_bug(env, "reg->btf must be kernel btf");
@@ -5825,8 +5830,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
reg_arg_name(env, argno), tname, off, size);
} else {
/* Writes are permitted with default btf_struct_access for
- * program allocated objects (which always have id > 0),
- * but not for untrusted PTR_TO_BTF_ID | MEM_ALLOC.
+ * program allocated objects (which always have id > 0).
*/
if (atype != BPF_READ && !type_is_ptr_alloc_obj(reg->type)) {
verbose(env, "only read is supported\n");
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
index fe30181e63367d..eb05fc82f81ba6 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
@@ -14,6 +14,7 @@
#include "tcp_ca_incompl_cong_ops.skel.h"
#include "tcp_ca_unsupp_cong_op.skel.h"
#include "tcp_ca_kfunc.skel.h"
+#include "tcp_ca_untrusted_btf_write.skel.h"
#include "bpf_cc_cubic.skel.h"
static const unsigned int total_bytes = 10 * 1024 * 1024;
@@ -579,6 +580,15 @@ static void test_tcp_ca_kfunc(void)
tcp_ca_kfunc__destroy(skel);
}
+static void test_untrusted_btf_write(void)
+{
+ struct tcp_ca_untrusted_btf_write *skel;
+
+ skel = tcp_ca_untrusted_btf_write__open_and_load();
+ ASSERT_ERR_PTR(skel, "tcp_ca_untrusted_btf_write__open_and_load");
+ tcp_ca_untrusted_btf_write__destroy(skel);
+}
+
static void test_cc_cubic(void)
{
struct cb_opts cb_opts = {
@@ -637,6 +647,8 @@ void test_bpf_tcp_ca(void)
test_link_replace();
if (test__start_subtest("tcp_ca_kfunc"))
test_tcp_ca_kfunc();
+ if (test__start_subtest("untrusted_btf_write"))
+ test_untrusted_btf_write();
if (test__start_subtest("cc_cubic"))
test_cc_cubic();
if (test__start_subtest("dctcp_autoattach_map"))
diff --git a/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
new file mode 100644
index 00000000000000..eda4697aac80b6
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "bpf_tracing_net.h"
+#include <bpf/bpf_core_read.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+char _license[] SEC("license") = "GPL";
+
+SEC("struct_ops")
+void BPF_PROG(untrusted_btf_write_init, struct sock *sk)
+{
+ struct tcp_sock *tp;
+ int v = 1;
+ void *p;
+
+ p = bpf_rdonly_cast(&v, 0);
+ tp = bpf_rdonly_cast(p, bpf_core_type_id_kernel(struct tcp_sock));
+ tp->snd_cwnd = 1;
+}
+
+SEC(".struct_ops")
+struct tcp_congestion_ops untrusted_btf_write = {
+ .init = (void *)untrusted_btf_write_init,
+ .name = "bpf_ro_btf",
+};
|
| 3/2 | 2026/07/08 05:23 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 3122 output: 38 thoughts: 577 Thoughts: **My Analysis of the BPF Verifier Change** Okay, so I'm looking at this patch and my initial thought is, this is a pretty straightforward security hardening measure within the BPF verifier. The core of the change is in `kernel/bpf/verifier.c`, specifically around the `check_ptr_to_btf_access` function. Essentially, it's now blocking write access to pointers marked as `PTR_UNTRUSTED`. The existing logic already handles access control, but this adds an extra layer of protection, limiting untrusted pointers to read-only operations. That's good, that's what we want. Specifically, the code now checks if the access type `atype` is not `BPF_READ`, *and* if the register's type has the `PTR_UNTRUSTED` flag set. If both conditions are true, it returns an error, specifically `-EACCES`, essentially denying the write. Previously, writes were permitted to program-allocated objects, but this change now restricts writes to `PTR_UNTRUSTED` pointers. This is a functional change; it alters the behavior of the verifier. Since this touches the verifier, I need to make sure this is fuzzed. The focus should definitely be on `check_ptr_to_btf_access`. I need to ensure that the fuzzing harnesses the new restrictions thoroughly. Now, let's see, what configs are relevant here? Ah, it looks like `kernel/bpf/verifier.c` is compiled when `CONFIG_BPF_SYSCALL` is enabled. Okay, good. That means I need to make sure I'm testing with that config enabled. I need to specifically look at `check_ptr_to_btf_access`, and I want to make sure I can reproduce this behavior, and I also want to make sure there are no regressions. |
| 4/2 | 2026/07/08 05:23 | tool | grepper |
0mArgs:{
"Expression": "check_ptr_to_btf_access",
"PathPrefix": "kernel/bpf/verifier.c"
}Results: {
"Output": "kernel/bpf/verifier.c=5745=static bool type_is_trusted_or_null(struct bpf_verifier_env *env,\n--\nkernel/bpf/verifier.c-5756-\nkernel/bpf/verifier.c:5757:static int check_ptr_to_btf_access(struct bpf_verifier_env *env,\nkernel/bpf/verifier.c-5758-\t\t\t\t struct bpf_reg_state *regs, struct bpf_reg_state *reg,\n--\nkernel/bpf/verifier.c=6106=static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct bpf_reg_state *reg, argno_t argno,\n--\nkernel/bpf/verifier.c-6319-\t\t !type_may_be_null(reg-\u003etype)) {\nkernel/bpf/verifier.c:6320:\t\terr = check_ptr_to_btf_access(env, regs, reg, argno, off, size, t,\nkernel/bpf/verifier.c-6321-\t\t\t\t\t value_regno);\n--\nkernel/bpf/verifier.c=6769=static int check_helper_mem_access(struct bpf_verifier_env *env, struct bpf_reg_state *reg, argno_t argno,\n--\nkernel/bpf/verifier.c-6826-\tcase PTR_TO_BTF_ID:\nkernel/bpf/verifier.c:6827:\t\treturn check_ptr_to_btf_access(env, regs, reg, argno, 0,\nkernel/bpf/verifier.c-6828-\t\t\t\t\t access_size, access_type, -1);\n"
} |
| 5/2 | 2026/07/08 05:23 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 4586 output: 29 thoughts: 51 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **Investigating BPF Verifier Access** Right, so `check_ptr_to_btf_access`, that function is definitely in `kernel/bpf/verifier.c`. No surprise there, that's where the verifier logic lives. Now, given that context, I need to check something related to the build configuration… Let's see, I immediately want to confirm that `CONFIG_BPF_SYSCALL` is enabled. Time to quickly glance at the `kernel/bpf/Makefile` to confirm the presence and value of that variable. It's a key factor here in how that verifier function operates, so I need to make sure I know the build environment I'm working with. That Makefile will give me the answer I need. |
| 6/2 | 2026/07/08 05:23 | tool | grepper |
0mArgs:{
"Expression": "verifier.o",
"PathPrefix": "kernel/bpf/Makefile"
}Results: {
"Output": "kernel/bpf/Makefile=7=CFLAGS_core.o += -Wno-override-init $(cflags-nogcse-yy)\nkernel/bpf/Makefile-8-\nkernel/bpf/Makefile:9:obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o cnum.o log.o token.o liveness.o const_fold.o\nkernel/bpf/Makefile-10-obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o\n"
} |
| 7/2 | 2026/07/08 05:23 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 5012 output: 85 thoughts: 111 Thoughts: **My Assessment of the BPF Fix** Okay, so I've confirmed it: `CONFIG_BPF_SYSCALL` is the crucial configuration option here. This patch is a functional fix; it's addressing a tangible vulnerability or bug where the system was susceptible to writing to memory locations based on untrusted pointers. That's a classic scenario, and the fact that it's in the BPF core logic immediately makes it a high priority for thorough fuzzing. My primary focus in reviewing the code will be the `check_ptr_to_btf_access` symbol, as that's where the vulnerability appears to be addressed. The fix, from what I can tell, modifies the BPF verifier. This makes perfect sense; the verifier is the gatekeeper, and tightening its checks regarding untrusted BTF pointers is precisely the type of solution I'd expect. The functional fix is clear as it stops writes to BTF pointers. Given all of this, enabling `BPF_SYSCALL` is the correct approach to implement this patch. This is a solid security and correctness improvement. |
| 8/2 | 2026/07/08 05:23 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"check_ptr_to_btf_access"
],
"Reasoning": "The patch modifies the BPF verifier to reject writes to untrusted BTF pointers, which is a functional security/correctness fix in the core BPF logic.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"BPF_SYSCALL"
],
"FocusSymbols": [
"check_ptr_to_btf_access"
],
"Reasoning": "The patch modifies the BPF verifier to reject writes to untrusted BTF pointers, which is a functional security/correctness fix in the core BPF logic.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|