| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/10/31 13:00 | flow | patch-triage |
2mArgs:null Results: {
"EnableConfigs": [
"BPF_SYSCALL",
"BPF_STREAM_PARSER",
"CGROUP_BPF"
],
"FocusSymbols": [
"sock_map_link",
"sock_map_del_link",
"sock_map_unref",
"sock_map_psock_get_checked",
"sock_map_update_elem_sys",
"sock_map_update_common",
"sock_hash_update_common",
"sock_map_sk_is_suitable",
"sock_map_delete_elem",
"sock_hash_delete_elem"
],
"KMSANReasoning": "The patch addresses race conditions and synchronization issues in sockmap when concurrently inserting and deleting sockets with attached verdict/parser BPF programs (fixing data races on sk-\u003esk_prot via READ_ONCE and ensuring proper locking via sk_callback_lock during link removal and protocol initialization). \n\nThese changes address concurrency and state management bugs, which fall under the domain of KASAN, LOCKDEP, and KCSAN (e.g., use-after-free, data races, deadlocks). The patch does not introduce any new allocations, does not modify any buffers or copy_to_user operations, and does not read or expose uninitialized memory. Therefore, dedicated KMSAN fuzzing is not required.",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies synchronization and concurrency logic in BPF sockmap/sockhash management (net/core/sock_map.c). Specifically, it expands the critical section protected by sk-\u003esk_callback_lock across sock_map_init_proto in sock_map_link, alters the stopping conditions in sock_map_del_link, and adds READ_ONCE guards when checking sk-\u003esk_prot. These paths are directly reachable and exercise core networking/BPF socket-redirection mechanisms via standard bpf() system calls.",
"WorthFuzzing": true
} |
| 1/1 | 2026/10/31 13:00 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 0141ff2361ad32060a297df2adf6322a51bd47b3\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sat Oct 31 13:00:04 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/net/core/sock_map.c b/net/core/sock_map.c\nindex 057e2f3c0265ed..efe49551caba9e 100644\n--- a/net/core/sock_map.c\n+++ b/net/core/sock_map.c\n@@ -152,11 +152,11 @@ static void sock_map_del_link(struct sock *sk,\n \t\t\tstruct bpf_map *map = link-\u003emap;\n \t\t\tstruct sk_psock_progs *progs = sock_map_progs(map);\n \n-\t\t\tif (psock-\u003esaved_data_ready \u0026\u0026 progs-\u003estream_parser)\n+\t\t\tif (progs-\u003estream_parser)\n \t\t\t\tstrp_stop = true;\n-\t\t\tif (psock-\u003esaved_data_ready \u0026\u0026 progs-\u003estream_verdict)\n+\t\t\tif (progs-\u003estream_verdict)\n \t\t\t\tverdict_stop = true;\n-\t\t\tif (psock-\u003esaved_data_ready \u0026\u0026 progs-\u003eskb_verdict)\n+\t\t\tif (progs-\u003eskb_verdict)\n \t\t\t\tverdict_stop = true;\n \t\t\tlist_del(\u0026link-\u003elist);\n \t\t\tsk_psock_free_link(link);\n@@ -164,8 +164,11 @@ static void sock_map_del_link(struct sock *sk,\n \t\t}\n \t}\n \tspin_unlock_bh(\u0026psock-\u003elink_lock);\n-\tif (strp_stop || verdict_stop) {\n-\t\twrite_lock_bh(\u0026sk-\u003esk_callback_lock);\n+\tif (!strp_stop \u0026\u0026 !verdict_stop)\n+\t\treturn;\n+\n+\twrite_lock_bh(\u0026sk-\u003esk_callback_lock);\n+\tif (psock-\u003esaved_data_ready) {\n \t\tif (strp_stop)\n \t\t\tsk_psock_stop_strp(sk, psock);\n \t\tif (verdict_stop)\n@@ -173,8 +176,8 @@ static void sock_map_del_link(struct sock *sk,\n \n \t\tif (psock-\u003epsock_update_sk_prot)\n \t\t\tpsock-\u003epsock_update_sk_prot(sk, psock, false);\n-\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n \t}\n+\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n }\n \n static void sock_map_unref(struct sock *sk, void *link_raw)\n@@ -202,7 +205,7 @@ static struct sk_psock *sock_map_psock_get_checked(struct sock *sk)\n \trcu_read_lock();\n \tpsock = sk_psock(sk);\n \tif (psock) {\n-\t\tif (sk-\u003esk_prot-\u003eclose != sock_map_close) {\n+\t\tif (READ_ONCE(sk-\u003esk_prot)-\u003eclose != sock_map_close) {\n \t\t\tpsock = ERR_PTR(-EBUSY);\n \t\t\tgoto out;\n \t\t}\n@@ -284,6 +287,7 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)\n \t\t}\n \t}\n \n+\twrite_lock_bh(\u0026sk-\u003esk_callback_lock);\n \tif (msg_parser)\n \t\tpsock_set_prog(\u0026psock-\u003eprogs.msg_parser, msg_parser);\n \tif (stream_parser)\n@@ -298,11 +302,11 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)\n \t */\n \tret = sock_map_init_proto(sk, psock);\n \tif (ret \u003c 0) {\n+\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n \t\tsk_psock_put(sk, psock);\n \t\tgoto out;\n \t}\n \n-\twrite_lock_bh(\u0026sk-\u003esk_callback_lock);\n \tif (stream_parser \u0026\u0026 stream_verdict \u0026\u0026 !psock-\u003esaved_data_ready) {\n \t\tif (sk_is_tcp(sk))\n \t\t\tret = sk_psock_init_strp(sk, psock);\n@@ -536,7 +540,7 @@ static bool sock_map_redirect_allowed(const struct sock *sk)\n \n static bool sock_map_sk_is_suitable(const struct sock *sk)\n {\n-\treturn !!sk-\u003esk_prot-\u003epsock_update_sk_prot;\n+\treturn !!READ_ONCE(sk-\u003esk_prot)-\u003epsock_update_sk_prot;\n }\n \n static bool sock_map_sk_state_allowed(const struct sock *sk)\ndiff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c\nindex 235e1d56f044f2..dca1f0de92e0ee 100644\n--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c\n+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c\n@@ -646,6 +646,82 @@ static void test_race_insert_listen(struct test_sockmap_listen *skel __always_un\n \txclose(s);\n }\n \n+struct update_delete_ctx {\n+\tunsigned int nr_iter;\n+\tunsigned int done;\n+\tint mapfd;\n+};\n+\n+static void *delete_elem_thread(void *arg)\n+{\n+\tstruct update_delete_ctx *ctx = arg;\n+\tunsigned int i;\n+\n+\tfor (i = 0; i \u003c ctx-\u003enr_iter; i++) {\n+\t\t/* Expecting EINVAL (sockmap) or ENOENT (sockhash) when the\n+\t\t * entry is already gone.\n+\t\t */\n+\t\tif (bpf_map_delete_elem(ctx-\u003emapfd, \u0026(u32){0}) \u0026\u0026\n+\t\t errno != EINVAL \u0026\u0026 errno != ENOENT) {\n+\t\t\tFAIL_ERRNO(\"map_delete\");\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tWRITE_ONCE(ctx-\u003edone, 1);\n+\treturn NULL;\n+}\n+\n+/* One thread keeps inserting a socket into a sockmap with an attached\n+ * verdict program while another thread deletes the same map entry.\n+ */\n+static void test_update_delete_with_prog(struct test_sockmap_listen *skel,\n+\t\t\t\t\t int family, int sotype, int mapfd)\n+{\n+\tstruct update_delete_ctx ctx = { 0 };\n+\tint err, s, verdict;\n+\tpthread_t t;\n+\tu64 value;\n+\n+\tverdict = bpf_program__fd(skel-\u003eprogs.prog_skb_verdict);\n+\terr = xbpf_prog_attach(verdict, mapfd, BPF_SK_SKB_VERDICT, 0);\n+\tif (err)\n+\t\treturn;\n+\n+\ts = xsocket(family, sotype, 0);\n+\tif (s \u003c 0)\n+\t\tgoto detach;\n+\n+\terr = xlisten(s, 1);\n+\tif (err)\n+\t\tgoto close;\n+\n+\tctx.mapfd = mapfd;\n+\tctx.nr_iter = 10000;\n+\n+\terr = xpthread_create(\u0026t, NULL, delete_elem_thread, \u0026ctx);\n+\tif (err)\n+\t\tgoto close;\n+\n+\tvalue = s;\n+\twhile (!READ_ONCE(ctx.done)) {\n+\t\t/* Expecting EBUSY while a deleted socket's psock still\n+\t\t * holds the verdict program.\n+\t\t */\n+\t\terr = bpf_map_update_elem(mapfd, \u0026(u32){0}, \u0026value, BPF_ANY);\n+\t\tif (err \u0026\u0026 errno != EBUSY) {\n+\t\t\tFAIL_ERRNO(\"map_update\");\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\txpthread_join(t, NULL);\n+close:\n+\txclose(s);\n+detach:\n+\txbpf_prog_detach2(verdict, mapfd, BPF_SK_SKB_VERDICT);\n+}\n+\n static void zero_verdict_count(int mapfd)\n {\n \tunsigned int zero = 0;\n@@ -1289,6 +1365,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,\n \t\tTEST(test_destroy_orphan_child, SOCK_STREAM),\n \t\tTEST(test_syn_recv_insert_delete, SOCK_STREAM),\n \t\tTEST(test_race_insert_listen, SOCK_STREAM),\n+\t\tTEST(test_update_delete_with_prog, SOCK_STREAM),\n \t\t/* child clone */\n \t\tTEST(test_clone_after_delete, SOCK_STREAM),\n \t\tTEST(test_accept_after_delete, SOCK_STREAM),\n"
} |
| 2/1 | 2026/10/31 13:00 | agent | patch-evaluator |
1mModel:core Args: null Results: {
"EnableConfigs": [
"BPF_SYSCALL",
"BPF_STREAM_PARSER",
"CGROUP_BPF"
],
"FocusSymbols": [
"sock_map_link",
"sock_map_del_link",
"sock_map_unref",
"sock_map_psock_get_checked",
"sock_map_update_elem_sys",
"sock_map_update_common",
"sock_hash_update_common",
"sock_map_sk_is_suitable",
"sock_map_delete_elem",
"sock_hash_delete_elem"
],
"Reasoning": "The patch modifies synchronization and concurrency logic in BPF sockmap/sockhash management (net/core/sock_map.c). Specifically, it expands the critical section protected by sk-\u003esk_callback_lock across sock_map_init_proto in sock_map_link, alters the stopping conditions in sock_map_del_link, and adds READ_ONCE guards when checking sk-\u003esk_prot. These paths are directly reachable and exercise core networking/BPF socket-redirection mechanisms via standard bpf() system calls.",
"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 0141ff2361ad32060a297df2adf6322a51bd47b3
Author: syz-cluster <triage@syzkaller.com>
Date: Sat Oct 31 13:00:04 2026 +0000
syz-cluster: applied patch under review
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index 057e2f3c0265ed..efe49551caba9e 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -152,11 +152,11 @@ static void sock_map_del_link(struct sock *sk,
struct bpf_map *map = link->map;
struct sk_psock_progs *progs = sock_map_progs(map);
- if (psock->saved_data_ready && progs->stream_parser)
+ if (progs->stream_parser)
strp_stop = true;
- if (psock->saved_data_ready && progs->stream_verdict)
+ if (progs->stream_verdict)
verdict_stop = true;
- if (psock->saved_data_ready && progs->skb_verdict)
+ if (progs->skb_verdict)
verdict_stop = true;
list_del(&link->list);
sk_psock_free_link(link);
@@ -164,8 +164,11 @@ static void sock_map_del_link(struct sock *sk,
}
}
spin_unlock_bh(&psock->link_lock);
- if (strp_stop || verdict_stop) {
- write_lock_bh(&sk->sk_callback_lock);
+ if (!strp_stop && !verdict_stop)
+ return;
+
+ write_lock_bh(&sk->sk_callback_lock);
+ if (psock->saved_data_ready) {
if (strp_stop)
sk_psock_stop_strp(sk, psock);
if (verdict_stop)
@@ -173,8 +176,8 @@ static void sock_map_del_link(struct sock *sk,
if (psock->psock_update_sk_prot)
psock->psock_update_sk_prot(sk, psock, false);
- write_unlock_bh(&sk->sk_callback_lock);
}
+ write_unlock_bh(&sk->sk_callback_lock);
}
static void sock_map_unref(struct sock *sk, void *link_raw)
@@ -202,7 +205,7 @@ static struct sk_psock *sock_map_psock_get_checked(struct sock *sk)
rcu_read_lock();
psock = sk_psock(sk);
if (psock) {
- if (sk->sk_prot->close != sock_map_close) {
+ if (READ_ONCE(sk->sk_prot)->close != sock_map_close) {
psock = ERR_PTR(-EBUSY);
goto out;
}
@@ -284,6 +287,7 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)
}
}
+ write_lock_bh(&sk->sk_callback_lock);
if (msg_parser)
psock_set_prog(&psock->progs.msg_parser, msg_parser);
if (stream_parser)
@@ -298,11 +302,11 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)
*/
ret = sock_map_init_proto(sk, psock);
if (ret < 0) {
+ write_unlock_bh(&sk->sk_callback_lock);
sk_psock_put(sk, psock);
goto out;
}
- write_lock_bh(&sk->sk_callback_lock);
if (stream_parser && stream_verdict && !psock->saved_data_ready) {
if (sk_is_tcp(sk))
ret = sk_psock_init_strp(sk, psock);
@@ -536,7 +540,7 @@ static bool sock_map_redirect_allowed(const struct sock *sk)
static bool sock_map_sk_is_suitable(const struct sock *sk)
{
- return !!sk->sk_prot->psock_update_sk_prot;
+ return !!READ_ONCE(sk->sk_prot)->psock_update_sk_prot;
}
static bool sock_map_sk_state_allowed(const struct sock *sk)
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
index 235e1d56f044f2..dca1f0de92e0ee 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
@@ -646,6 +646,82 @@ static void test_race_insert_listen(struct test_sockmap_listen *skel __always_un
xclose(s);
}
+struct update_delete_ctx {
+ unsigned int nr_iter;
+ unsigned int done;
+ int mapfd;
+};
+
+static void *delete_elem_thread(void *arg)
+{
+ struct update_delete_ctx *ctx = arg;
+ unsigned int i;
+
+ for (i = 0; i < ctx->nr_iter; i++) {
+ /* Expecting EINVAL (sockmap) or ENOENT (sockhash) when the
+ * entry is already gone.
+ */
+ if (bpf_map_delete_elem(ctx->mapfd, &(u32){0}) &&
+ errno != EINVAL && errno != ENOENT) {
+ FAIL_ERRNO("map_delete");
+ break;
+ }
+ }
+
+ WRITE_ONCE(ctx->done, 1);
+ return NULL;
+}
+
+/* One thread keeps inserting a socket into a sockmap with an attached
+ * verdict program while another thread deletes the same map entry.
+ */
+static void test_update_delete_with_prog(struct test_sockmap_listen *skel,
+ int family, int sotype, int mapfd)
+{
+ struct update_delete_ctx ctx = { 0 };
+ int err, s, verdict;
+ pthread_t t;
+ u64 value;
+
+ verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
+ err = xbpf_prog_attach(verdict, mapfd, BPF_SK_SKB_VERDICT, 0);
+ if (err)
+ return;
+
+ s = xsocket(family, sotype, 0);
+ if (s < 0)
+ goto detach;
+
+ err = xlisten(s, 1);
+ if (err)
+ goto close;
+
+ ctx.mapfd = mapfd;
+ ctx.nr_iter = 10000;
+
+ err = xpthread_create(&t, NULL, delete_elem_thread, &ctx);
+ if (err)
+ goto close;
+
+ value = s;
+ while (!READ_ONCE(ctx.done)) {
+ /* Expecting EBUSY while a deleted socket's psock still
+ * holds the verdict program.
+ */
+ err = bpf_map_update_elem(mapfd, &(u32){0}, &value, BPF_ANY);
+ if (err && errno != EBUSY) {
+ FAIL_ERRNO("map_update");
+ break;
+ }
+ }
+
+ xpthread_join(t, NULL);
+close:
+ xclose(s);
+detach:
+ xbpf_prog_detach2(verdict, mapfd, BPF_SK_SKB_VERDICT);
+}
+
static void zero_verdict_count(int mapfd)
{
unsigned int zero = 0;
@@ -1289,6 +1365,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
TEST(test_destroy_orphan_child, SOCK_STREAM),
TEST(test_syn_recv_insert_delete, SOCK_STREAM),
TEST(test_race_insert_listen, SOCK_STREAM),
+ TEST(test_update_delete_with_prog, SOCK_STREAM),
/* child clone */
TEST(test_clone_after_delete, SOCK_STREAM),
TEST(test_accept_after_delete, SOCK_STREAM),
|
| 3/2 | 2026/10/31 13:00 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 5088 output: 37 thoughts: 129 Thoughts: Here's my thought process, as if I were analyzing this patch: **Analyzing the Sockmap Patch** Okay, let's break this down systematically. My immediate approach is to understand the scope and intent of this patch. First, I need to identify the core modifications. It looks like we're dealing with two key files: `net/core/sock_map.c` and `tools/testing/selftests/bpf/prog_tests/sockmap_listen.c`. This suggests changes to the core sockmap implementation itself, along with potential test suite updates to validate the functionality. I'll start with the heart of the matter – `net/core/sock_map.c`. I need to zero in on the areas where the fundamental changes are happening. I'll focus my attention on lines 150-320 and 535-550. This usually involves understanding data structures, function calls, and any control flow alterations within those ranges. Using `read-file` will allow me to check and understand the context better. I'll need to pay close attention to the data structures involved, the locks being used, and any new functions or changes to existing ones. The goal is to fully grasp the 'what' and 'why' of the core logic changes. |
| 4/2 | 2026/10/31 13:00 | tool | read-file |
0mArgs:{
"File": "net/core/sock_map.c",
"FirstLine": 145,
"LineCount": 50
}Results: {
"Contents": " 145:\t{\n 146:\t\tbool strp_stop = false, verdict_stop = false;\n 147:\t\tstruct sk_psock_link *link, *tmp;\n 148:\t\n 149:\t\tspin_lock_bh(\u0026psock-\u003elink_lock);\n 150:\t\tlist_for_each_entry_safe(link, tmp, \u0026psock-\u003elink, list) {\n 151:\t\t\tif (link-\u003elink_raw == link_raw) {\n 152:\t\t\t\tstruct bpf_map *map = link-\u003emap;\n 153:\t\t\t\tstruct sk_psock_progs *progs = sock_map_progs(map);\n 154:\t\n 155:\t\t\t\tif (progs-\u003estream_parser)\n 156:\t\t\t\t\tstrp_stop = true;\n 157:\t\t\t\tif (progs-\u003estream_verdict)\n 158:\t\t\t\t\tverdict_stop = true;\n 159:\t\t\t\tif (progs-\u003eskb_verdict)\n 160:\t\t\t\t\tverdict_stop = true;\n 161:\t\t\t\tlist_del(\u0026link-\u003elist);\n 162:\t\t\t\tsk_psock_free_link(link);\n 163:\t\t\t\tbreak;\n 164:\t\t\t}\n 165:\t\t}\n 166:\t\tspin_unlock_bh(\u0026psock-\u003elink_lock);\n 167:\t\tif (!strp_stop \u0026\u0026 !verdict_stop)\n 168:\t\t\treturn;\n 169:\t\n 170:\t\twrite_lock_bh(\u0026sk-\u003esk_callback_lock);\n 171:\t\tif (psock-\u003esaved_data_ready) {\n 172:\t\t\tif (strp_stop)\n 173:\t\t\t\tsk_psock_stop_strp(sk, psock);\n 174:\t\t\tif (verdict_stop)\n 175:\t\t\t\tsk_psock_stop_verdict(sk, psock);\n 176:\t\n 177:\t\t\tif (psock-\u003epsock_update_sk_prot)\n 178:\t\t\t\tpsock-\u003epsock_update_sk_prot(sk, psock, false);\n 179:\t\t}\n 180:\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n 181:\t}\n 182:\t\n 183:\tstatic void sock_map_unref(struct sock *sk, void *link_raw)\n 184:\t{\n 185:\t\tstruct sk_psock *psock = sk_psock(sk);\n 186:\t\n 187:\t\tif (likely(psock)) {\n 188:\t\t\tsock_map_del_link(sk, psock, link_raw);\n 189:\t\t\tsk_psock_put(sk, psock);\n 190:\t\t}\n 191:\t}\n 192:\t\n 193:\tstatic int sock_map_init_proto(struct sock *sk, struct sk_psock *psock)\n 194:\t{\n"
} |
| 5/2 | 2026/10/31 13:00 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 6326 output: 38 thoughts: 25 Thoughts: Okay, here's my attempt at summarizing the thought process, as requested, targeting an expert audience and using the first person: **Diving into `net/core/sock_map.c`** Right, let's get down to brass tacks. I need to get a handle on how this `sock_map` thing works, so I'm going to jump straight into the code. Specifically, lines 200 through 320 in `net/core/sock_map.c`. That chunk should give me a good initial impression of what's happening. I expect to find some fundamental data structure definitions in there – maybe the struct for the map itself, any associated metadata, and hopefully a glimpse into how entries are added and looked up. I'm mentally preparing for potential complexities. There's a good chance this involves locking mechanisms, given it's shared network data. I'll be looking for any hints about concurrency protection – spinlocks, mutexes, RCU, anything of that nature. I'll also be on the lookout for memory management aspects; is it dynamically allocated, are there any specialized allocators in play? And of course, performance is always a concern in networking, so I'll be checking for any clues about optimization strategies, like hashing, caching, or potentially even lockless data structures. The goal here is a quick but thorough overview, enough to start forming a mental model of this critical component. From this brief section of code, I hope to begin grasping its interactions with other kernel subsystems and networking protocols. |
| 6/2 | 2026/10/31 13:00 | tool | read-file |
0mArgs:{
"File": "net/core/sock_map.c",
"FirstLine": 195,
"LineCount": 100
}Results: {
"Contents": " 195:\t\tif (!sk-\u003esk_prot-\u003epsock_update_sk_prot)\n 196:\t\t\treturn -EINVAL;\n 197:\t\tpsock-\u003epsock_update_sk_prot = sk-\u003esk_prot-\u003epsock_update_sk_prot;\n 198:\t\treturn sk-\u003esk_prot-\u003epsock_update_sk_prot(sk, psock, false);\n 199:\t}\n 200:\t\n 201:\tstatic struct sk_psock *sock_map_psock_get_checked(struct sock *sk)\n 202:\t{\n 203:\t\tstruct sk_psock *psock;\n 204:\t\n 205:\t\trcu_read_lock();\n 206:\t\tpsock = sk_psock(sk);\n 207:\t\tif (psock) {\n 208:\t\t\tif (READ_ONCE(sk-\u003esk_prot)-\u003eclose != sock_map_close) {\n 209:\t\t\t\tpsock = ERR_PTR(-EBUSY);\n 210:\t\t\t\tgoto out;\n 211:\t\t\t}\n 212:\t\n 213:\t\t\tif (!refcount_inc_not_zero(\u0026psock-\u003erefcnt))\n 214:\t\t\t\tpsock = ERR_PTR(-EBUSY);\n 215:\t\t}\n 216:\tout:\n 217:\t\trcu_read_unlock();\n 218:\t\treturn psock;\n 219:\t}\n 220:\t\n 221:\tstatic int sock_map_link(struct bpf_map *map, struct sock *sk)\n 222:\t{\n 223:\t\tstruct sk_psock_progs *progs = sock_map_progs(map);\n 224:\t\tstruct bpf_prog *stream_verdict = NULL;\n 225:\t\tstruct bpf_prog *stream_parser = NULL;\n 226:\t\tstruct bpf_prog *skb_verdict = NULL;\n 227:\t\tstruct bpf_prog *msg_parser = NULL;\n 228:\t\tstruct sk_psock *psock;\n 229:\t\tint ret;\n 230:\t\n 231:\t\tstream_verdict = READ_ONCE(progs-\u003estream_verdict);\n 232:\t\tif (stream_verdict) {\n 233:\t\t\tstream_verdict = bpf_prog_inc_not_zero(stream_verdict);\n 234:\t\t\tif (IS_ERR(stream_verdict))\n 235:\t\t\t\treturn PTR_ERR(stream_verdict);\n 236:\t\t}\n 237:\t\n 238:\t\tstream_parser = READ_ONCE(progs-\u003estream_parser);\n 239:\t\tif (stream_parser) {\n 240:\t\t\tstream_parser = bpf_prog_inc_not_zero(stream_parser);\n 241:\t\t\tif (IS_ERR(stream_parser)) {\n 242:\t\t\t\tret = PTR_ERR(stream_parser);\n 243:\t\t\t\tgoto out_put_stream_verdict;\n 244:\t\t\t}\n 245:\t\t}\n 246:\t\n 247:\t\tmsg_parser = READ_ONCE(progs-\u003emsg_parser);\n 248:\t\tif (msg_parser) {\n 249:\t\t\tmsg_parser = bpf_prog_inc_not_zero(msg_parser);\n 250:\t\t\tif (IS_ERR(msg_parser)) {\n 251:\t\t\t\tret = PTR_ERR(msg_parser);\n 252:\t\t\t\tgoto out_put_stream_parser;\n 253:\t\t\t}\n 254:\t\t}\n 255:\t\n 256:\t\tskb_verdict = READ_ONCE(progs-\u003eskb_verdict);\n 257:\t\tif (skb_verdict) {\n 258:\t\t\tskb_verdict = bpf_prog_inc_not_zero(skb_verdict);\n 259:\t\t\tif (IS_ERR(skb_verdict)) {\n 260:\t\t\t\tret = PTR_ERR(skb_verdict);\n 261:\t\t\t\tgoto out_put_msg_parser;\n 262:\t\t\t}\n 263:\t\t}\n 264:\t\n 265:\t\tpsock = sock_map_psock_get_checked(sk);\n 266:\t\tif (IS_ERR(psock)) {\n 267:\t\t\tret = PTR_ERR(psock);\n 268:\t\t\tgoto out_progs;\n 269:\t\t}\n 270:\t\n 271:\t\tif (psock) {\n 272:\t\t\tif ((msg_parser \u0026\u0026 READ_ONCE(psock-\u003eprogs.msg_parser)) ||\n 273:\t\t\t (stream_parser \u0026\u0026 READ_ONCE(psock-\u003eprogs.stream_parser)) ||\n 274:\t\t\t (skb_verdict \u0026\u0026 READ_ONCE(psock-\u003eprogs.skb_verdict)) ||\n 275:\t\t\t (skb_verdict \u0026\u0026 READ_ONCE(psock-\u003eprogs.stream_verdict)) ||\n 276:\t\t\t (stream_verdict \u0026\u0026 READ_ONCE(psock-\u003eprogs.skb_verdict)) ||\n 277:\t\t\t (stream_verdict \u0026\u0026 READ_ONCE(psock-\u003eprogs.stream_verdict))) {\n 278:\t\t\t\tsk_psock_put(sk, psock);\n 279:\t\t\t\tret = -EBUSY;\n 280:\t\t\t\tgoto out_progs;\n 281:\t\t\t}\n 282:\t\t} else {\n 283:\t\t\tpsock = sk_psock_init(sk, map-\u003enuma_node);\n 284:\t\t\tif (IS_ERR(psock)) {\n 285:\t\t\t\tret = PTR_ERR(psock);\n 286:\t\t\t\tgoto out_progs;\n 287:\t\t\t}\n 288:\t\t}\n 289:\t\n 290:\t\twrite_lock_bh(\u0026sk-\u003esk_callback_lock);\n 291:\t\tif (msg_parser)\n 292:\t\t\tpsock_set_prog(\u0026psock-\u003eprogs.msg_parser, msg_parser);\n 293:\t\tif (stream_parser)\n 294:\t\t\tpsock_set_prog(\u0026psock-\u003eprogs.stream_parser, stream_parser);\n"
} |
| 7/2 | 2026/10/31 13:00 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 8386 output: 37 thoughts: 24 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person: **Diving into the `sock_map_link` Function** Alright, I need to get a deeper understanding of this function. Let's start by looking closely at `sock_map_link`, specifically from lines 295 to 350. That should give me a solid chunk of the logic. I want to see how the connection is established and the sock_map is linked. Understanding those lines will give me a better understanding of how the program functions. |
| 8/2 | 2026/10/31 13:00 | tool | read-file |
0mArgs:{
"File": "net/core/sock_map.c",
"FirstLine": 295,
"LineCount": 55
}Results: {
"Contents": " 295:\t\tif (stream_verdict)\n 296:\t\t\tpsock_set_prog(\u0026psock-\u003eprogs.stream_verdict, stream_verdict);\n 297:\t\tif (skb_verdict)\n 298:\t\t\tpsock_set_prog(\u0026psock-\u003eprogs.skb_verdict, skb_verdict);\n 299:\t\n 300:\t\t/* msg_* and stream_* programs references tracked in psock after this\n 301:\t\t * point. Reference dec and cleanup will occur through psock destructor\n 302:\t\t */\n 303:\t\tret = sock_map_init_proto(sk, psock);\n 304:\t\tif (ret \u003c 0) {\n 305:\t\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n 306:\t\t\tsk_psock_put(sk, psock);\n 307:\t\t\tgoto out;\n 308:\t\t}\n 309:\t\n 310:\t\tif (stream_parser \u0026\u0026 stream_verdict \u0026\u0026 !psock-\u003esaved_data_ready) {\n 311:\t\t\tif (sk_is_tcp(sk))\n 312:\t\t\t\tret = sk_psock_init_strp(sk, psock);\n 313:\t\t\telse\n 314:\t\t\t\tret = -EOPNOTSUPP;\n 315:\t\t\tif (ret) {\n 316:\t\t\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n 317:\t\t\t\tsk_psock_put(sk, psock);\n 318:\t\t\t\tgoto out;\n 319:\t\t\t}\n 320:\t\t\tsk_psock_start_strp(sk, psock);\n 321:\t\t} else if (!stream_parser \u0026\u0026 stream_verdict \u0026\u0026 !psock-\u003esaved_data_ready) {\n 322:\t\t\tsk_psock_start_verdict(sk,psock);\n 323:\t\t} else if (!stream_verdict \u0026\u0026 skb_verdict \u0026\u0026 !psock-\u003esaved_data_ready) {\n 324:\t\t\tsk_psock_start_verdict(sk, psock);\n 325:\t\t}\n 326:\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n 327:\t\treturn 0;\n 328:\tout_progs:\n 329:\t\tif (skb_verdict)\n 330:\t\t\tbpf_prog_put(skb_verdict);\n 331:\tout_put_msg_parser:\n 332:\t\tif (msg_parser)\n 333:\t\t\tbpf_prog_put(msg_parser);\n 334:\tout_put_stream_parser:\n 335:\t\tif (stream_parser)\n 336:\t\t\tbpf_prog_put(stream_parser);\n 337:\tout_put_stream_verdict:\n 338:\t\tif (stream_verdict)\n 339:\t\t\tbpf_prog_put(stream_verdict);\n 340:\tout:\n 341:\t\treturn ret;\n 342:\t}\n 343:\t\n 344:\tstatic void sock_map_free(struct bpf_map *map)\n 345:\t{\n 346:\t\tstruct bpf_stab *stab = container_of(map, struct bpf_stab, map);\n 347:\t\tint i;\n 348:\t\n 349:\t\t/* After the sync no updates or deletes will be in-flight so it\n"
} |
| 9/2 | 2026/10/31 13:00 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 9491 output: 31 thoughts: 1235 Thoughts: **Analyzing a Network Core BPF Sockmap Patch** Okay, let's dive into this commit. I need to understand what's happening. The message says "applied patch under review," so it's fresh. I don't have direct access to `git log` here, but that header gives me a starting point. Based on the header it looks like there's some networking / BPF code that has been changed. It looks like the patch modifies `net/core/sock_map.c`. A quick scan shows changes in several functions: `sock_map_del_link()`, `sock_map_psock_get_checked()`, `sock_map_link()`, and `sock_map_sk_is_suitable()`. The diffs are small but interesting. Essentially, there are modifications regarding how stream parser and verdict programs interact in `sock_map_del_link`. There are also changes to memory barriers when accessing `sk_prot`. The most interesting is the lock order change in `sock_map_link()`, moving the lock around the initialization of the protocol. Alright, `net/core/sock_map.c`... that's the heart of BPF sockmap and sockhash maps. That's reachable code, right? Yes! We're talking about `BPF_MAP_TYPE_SOCKMAP` and `BPF_MAP_TYPE_SOCKHASH`. User-space creates sockmaps via `bpf(BPF_MAP_CREATE, ...)` and manipulates sockets with `bpf(BPF_MAP_UPDATE_ELEM, ...)` and attaches BPF programs via `bpf(BPF_PROG_ATTACH, ...)`. This is something syzkaller is constantly fuzzing! Syzkaller has descriptions for all these BPF syscalls and it is known for finding all kinds of concurrency bugs in this area, so this patch is high priority. Okay, let's relate this to our triage guidelines. This patch definitely hits the "Core Subsystems" criteria: networking, specifically BPF. Also, there are changes to the locking. Specifically, `write_lock_bh(&sk->sk_callback_lock)` is now held across `sock_map_init_proto(sk, psock)`! This is interesting because this likely changes locking order. What does `sock_map_init_proto()` do? I need to understand what `psock_update_sk_prot` does and if `sock_map_init_proto` acquires any locks. I need to know if this code can deadlock or sleep. |
| 10/2 | 2026/10/31 13:00 | tool | grepper |
0mArgs:{
"Expression": "psock_update_sk_prot",
"PathPrefixes": [
"net/"
]
}Results: {
"Output": "net/core/sock_map.c=143=static void sock_map_del_link(struct sock *sk,\n--\nnet/core/sock_map.c-176-\nnet/core/sock_map.c:177:\t\tif (psock-\u003epsock_update_sk_prot)\nnet/core/sock_map.c:178:\t\t\tpsock-\u003epsock_update_sk_prot(sk, psock, false);\nnet/core/sock_map.c-179-\t}\n--\nnet/core/sock_map.c=193=static int sock_map_init_proto(struct sock *sk, struct sk_psock *psock)\nnet/core/sock_map.c-194-{\nnet/core/sock_map.c:195:\tif (!sk-\u003esk_prot-\u003epsock_update_sk_prot)\nnet/core/sock_map.c-196-\t\treturn -EINVAL;\nnet/core/sock_map.c:197:\tpsock-\u003epsock_update_sk_prot = sk-\u003esk_prot-\u003epsock_update_sk_prot;\nnet/core/sock_map.c:198:\treturn sk-\u003esk_prot-\u003epsock_update_sk_prot(sk, psock, false);\nnet/core/sock_map.c-199-}\n--\nnet/core/sock_map.c=541=static bool sock_map_sk_is_suitable(const struct sock *sk)\nnet/core/sock_map.c-542-{\nnet/core/sock_map.c:543:\treturn !!READ_ONCE(sk-\u003esk_prot)-\u003epsock_update_sk_prot;\nnet/core/sock_map.c-544-}\n--\nnet/ipv4/tcp_ipv4.c=3352=struct proto tcp_prot = {\n--\nnet/ipv4/tcp_ipv4.c-3377-#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/tcp_ipv4.c:3378:\t.psock_update_sk_prot\t= tcp_bpf_update_proto,\nnet/ipv4/tcp_ipv4.c-3379-#endif\n--\nnet/ipv4/udp.c=3176=struct proto udp_prot = {\n--\nnet/ipv4/udp.c-3197-#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/udp.c:3198:\t.psock_update_sk_prot\t= udp_bpf_update_proto,\nnet/ipv4/udp.c-3199-#endif\n--\nnet/ipv6/tcp_ipv6.c=2280=struct proto tcpv6_prot = {\n--\nnet/ipv6/tcp_ipv6.c-2305-#ifdef CONFIG_BPF_SYSCALL\nnet/ipv6/tcp_ipv6.c:2306:\t.psock_update_sk_prot\t= tcp_bpf_update_proto,\nnet/ipv6/tcp_ipv6.c-2307-#endif\n--\nnet/ipv6/udp.c=1902=struct proto udpv6_prot = {\n--\nnet/ipv6/udp.c-1923-#ifdef CONFIG_BPF_SYSCALL\nnet/ipv6/udp.c:1924:\t.psock_update_sk_prot\t= udp_bpf_update_proto,\nnet/ipv6/udp.c-1925-#endif\n--\nnet/mptcp/subflow.c=2198=void __init mptcp_subflow_init(void)\n--\nnet/mptcp/subflow.c-2221-\t/* Disable sockmap processing for subflows */\nnet/mptcp/subflow.c:2222:\ttcp_prot_override.psock_update_sk_prot = NULL;\nnet/mptcp/subflow.c-2223-#endif\n--\nnet/mptcp/subflow.c=2232=void __init mptcp_subflow_v6_init(void)\n--\nnet/mptcp/subflow.c-2268-\t/* Disable sockmap processing for subflows */\nnet/mptcp/subflow.c:2269:\ttcpv6_prot_override.psock_update_sk_prot = NULL;\nnet/mptcp/subflow.c-2270-#endif\n--\nnet/unix/af_unix.c=1070=struct proto unix_dgram_proto = {\n--\nnet/unix/af_unix.c-1076-#ifdef CONFIG_BPF_SYSCALL\nnet/unix/af_unix.c:1077:\t.psock_update_sk_prot\t= unix_dgram_bpf_update_proto,\nnet/unix/af_unix.c-1078-#endif\n--\nnet/unix/af_unix.c=1081=struct proto unix_stream_proto = {\n--\nnet/unix/af_unix.c-1087-#ifdef CONFIG_BPF_SYSCALL\nnet/unix/af_unix.c:1088:\t.psock_update_sk_prot\t= unix_stream_bpf_update_proto,\nnet/unix/af_unix.c-1089-#endif\n--\nnet/unix/unix_bpf.c=164=int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)\n--\nnet/unix/unix_bpf.c-177-\nnet/unix/unix_bpf.c:178:\t/* psock_update_sk_prot can be called multiple times if psock is\nnet/unix/unix_bpf.c-179-\t * added to multiple maps and/or slots in the same map. There is\nnet/unix/unix_bpf.c-180-\t * also an edge case where replacing a psock with itself can trigger\nnet/unix/unix_bpf.c:181:\t * an extra psock_update_sk_prot during the insert process. So it\nnet/unix/unix_bpf.c-182-\t * must be safe to do multiple calls. Here we need to ensure we don't\n--\nnet/vmw_vsock/af_vsock.c=182=struct proto vsock_proto = {\n--\nnet/vmw_vsock/af_vsock.c-187-#ifdef CONFIG_BPF_SYSCALL\nnet/vmw_vsock/af_vsock.c:188:\t.psock_update_sk_prot = vsock_bpf_update_proto,\nnet/vmw_vsock/af_vsock.c-189-#endif\n"
} |
| 11/2 | 2026/10/31 13:00 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 13009 output: 58 thoughts: 794 Thoughts: **Analyzing a Sockmap Patch for Fuzzing Potential** Okay, so I'm looking at this patch that modifies how sockmaps are handled, specifically the interaction with socket operations and protocols across TCP, UDP, UNIX, and VSOCK. My initial impression? This is prime fuzzing material. First, I see the changes in `sock_map_link()` and `sock_map_del_link()`. It looks like the locking order has been adjusted in `sock_map_link()`, moving the lock acquisition *before* calling `sock_map_init_proto()`. That's a classic sign of a potential race condition fix, and I know from experience that these types of fixes are often tricky and can introduce new, subtle bugs. The changes in `sock_map_del_link()` also involve locking and conditional logic related to `psock->saved_data_ready` and program execution (stream parsers and verdicts). The fact that they added a `psock->psock_update_sk_prot` callback call is significant. The addition of the selftest, `test_update_delete_with_prog`, confirms my suspicions: this is a race condition between map updates and deletes when a program is attached to the sockmap. It's a textbook case of a concurrency issue. Now, let's determine if this meets the "WorthFuzzing" criteria. Given that this patch touches the core networking subsystem (specifically BPF and synchronization/locking within `net/core/sock_map.c`), and involves restructuring of data access in a critical path, it's a clear yes. *WorthFuzzing = true*. Next, I need to pinpoint the `FocusSymbols`. I need to identify specific kernel functions that should be the focus of the fuzzing. To figure out the specific functions that are modified, I'll need to look at the relevant source file, `net/core/sock_map.c`. Based on what's in the patch, I want to pay attention to: `sock_map_del_link`, `sock_map_unref`, `sock_map_psock_get_checked`, `sock_map_link`, and `sock_map_sk_is_suitable`. Now, I need to check to see if these functions are static, and figure out the call sites. If they are used elsewhere, then these are definite targets for further investigation and fuzzing. I'll need to search for where these functions are called to ensure that I focus on the right code paths. |
| 12/2 | 2026/10/31 13:00 | tool | grepper |
0mArgs:{
"Expression": "sock_map_link|sock_map_del_link|sock_map_unref|sock_map_update_elem",
"PathPrefixes": [
"net/core/sock_map.c"
]
}Results: {
"Output": "net/core/sock_map.c=132=static void sock_map_add_link(struct sk_psock *psock,\n--\nnet/core/sock_map.c-142-\nnet/core/sock_map.c:143:static void sock_map_del_link(struct sock *sk,\nnet/core/sock_map.c-144-\t\t\t struct sk_psock *psock, void *link_raw)\n--\nnet/core/sock_map.c-182-\nnet/core/sock_map.c:183:static void sock_map_unref(struct sock *sk, void *link_raw)\nnet/core/sock_map.c-184-{\n--\nnet/core/sock_map.c-187-\tif (likely(psock)) {\nnet/core/sock_map.c:188:\t\tsock_map_del_link(sk, psock, link_raw);\nnet/core/sock_map.c-189-\t\tsk_psock_put(sk, psock);\n--\nnet/core/sock_map.c=201=static struct sk_psock *sock_map_psock_get_checked(struct sock *sk)\n--\nnet/core/sock_map.c-220-\nnet/core/sock_map.c:221:static int sock_map_link(struct bpf_map *map, struct sock *sk)\nnet/core/sock_map.c-222-{\n--\nnet/core/sock_map.c=344=static void sock_map_free(struct bpf_map *map)\n--\nnet/core/sock_map.c-362-\t\t\trcu_read_lock();\nnet/core/sock_map.c:363:\t\t\tsock_map_unref(sk, psk);\nnet/core/sock_map.c-364-\t\t\trcu_read_unlock();\n--\nnet/core/sock_map.c=420=static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test,\n--\nnet/core/sock_map.c-430-\tif (likely(sk))\nnet/core/sock_map.c:431:\t\tsock_map_unref(sk, psk);\nnet/core/sock_map.c-432-\telse\n--\nnet/core/sock_map.c=475=static int sock_map_update_common(struct bpf_map *map, u32 idx,\n--\nnet/core/sock_map.c-493-\nnet/core/sock_map.c:494:\tret = sock_map_link(map, sk);\nnet/core/sock_map.c-495-\tif (ret \u003c 0)\n--\nnet/core/sock_map.c-513-\tif (osk)\nnet/core/sock_map.c:514:\t\tsock_map_unref(osk, \u0026stab-\u003esks[idx]);\nnet/core/sock_map.c-515-\tspin_unlock_bh(\u0026stab-\u003elock);\n--\nnet/core/sock_map.c=560=static int sock_hash_update_common(struct bpf_map *map, void *key,\n--\nnet/core/sock_map.c-562-\nnet/core/sock_map.c:563:int sock_map_update_elem_sys(struct bpf_map *map, void *key, void *value,\nnet/core/sock_map.c-564-\t\t\t u64 flags)\n--\nnet/core/sock_map.c-603-\nnet/core/sock_map.c:604:static long sock_map_update_elem(struct bpf_map *map, void *key,\nnet/core/sock_map.c-605-\t\t\t\t void *value, u64 flags)\n--\nnet/core/sock_map.c=836=const struct bpf_map_ops sock_map_ops = {\n--\nnet/core/sock_map.c-841-\t.map_lookup_elem_sys_only = sock_map_lookup_sys,\nnet/core/sock_map.c:842:\t.map_update_elem\t= sock_map_update_elem,\nnet/core/sock_map.c-843-\t.map_delete_elem\t= sock_map_delete_elem,\n--\nnet/core/sock_map.c=923=static void sock_hash_delete_from_link(struct bpf_map *map, struct sock *sk,\n--\nnet/core/sock_map.c-941-\t\thlist_del_rcu(\u0026elem-\u003enode);\nnet/core/sock_map.c:942:\t\tsock_map_unref(elem-\u003esk, elem);\nnet/core/sock_map.c-943-\t\tsock_hash_free_elem(htab, elem);\n--\nnet/core/sock_map.c=948=static long sock_hash_delete_elem(struct bpf_map *map, void *key)\n--\nnet/core/sock_map.c-962-\t\thlist_del_rcu(\u0026elem-\u003enode);\nnet/core/sock_map.c:963:\t\tsock_map_unref(elem-\u003esk, elem);\nnet/core/sock_map.c-964-\t\tsock_hash_free_elem(htab, elem);\n--\nnet/core/sock_map.c=998=static int sock_hash_update_common(struct bpf_map *map, void *key,\n--\nnet/core/sock_map.c-1016-\nnet/core/sock_map.c:1017:\tret = sock_map_link(map, sk);\nnet/core/sock_map.c-1018-\tif (ret \u003c 0)\n--\nnet/core/sock_map.c-1049-\t\thlist_del_rcu(\u0026elem-\u003enode);\nnet/core/sock_map.c:1050:\t\tsock_map_unref(elem-\u003esk, elem);\nnet/core/sock_map.c-1051-\t\tsock_hash_free_elem(htab, elem);\n--\nnet/core/sock_map.c=1151=static void sock_hash_free(struct bpf_map *map)\n--\nnet/core/sock_map.c-1187-\t\t\trcu_read_lock();\nnet/core/sock_map.c:1188:\t\t\tsock_map_unref(elem-\u003esk, elem);\nnet/core/sock_map.c-1189-\t\t\trcu_read_unlock();\n--\nnet/core/sock_map.c=1452=const struct bpf_map_ops sock_hash_ops = {\n--\nnet/core/sock_map.c-1456-\t.map_get_next_key\t= sock_hash_get_next_key,\nnet/core/sock_map.c:1457:\t.map_update_elem\t= sock_map_update_elem,\nnet/core/sock_map.c-1458-\t.map_delete_elem\t= sock_hash_delete_elem,\n--\nnet/core/sock_map.c=1742=struct sockmap_link {\n--\nnet/core/sock_map.c-1746-\nnet/core/sock_map.c:1747:static void sock_map_link_release(struct bpf_link *link)\nnet/core/sock_map.c-1748-{\n--\nnet/core/sock_map.c-1763-\nnet/core/sock_map.c:1764:static int sock_map_link_detach(struct bpf_link *link)\nnet/core/sock_map.c-1765-{\nnet/core/sock_map.c:1766:\tsock_map_link_release(link);\nnet/core/sock_map.c-1767-\treturn 0;\n--\nnet/core/sock_map.c-1769-\nnet/core/sock_map.c:1770:static void sock_map_link_dealloc(struct bpf_link *link)\nnet/core/sock_map.c-1771-{\n--\nnet/core/sock_map.c-1778- */\nnet/core/sock_map.c:1779:static int sock_map_link_update_prog(struct bpf_link *link,\nnet/core/sock_map.c-1780-\t\t\t\t struct bpf_prog *prog,\n--\nnet/core/sock_map.c-1838-\nnet/core/sock_map.c:1839:static u32 sock_map_link_get_map_id(const struct sockmap_link *sockmap_link)\nnet/core/sock_map.c-1840-{\n--\nnet/core/sock_map.c-1849-\nnet/core/sock_map.c:1850:static int sock_map_link_fill_info(const struct bpf_link *link,\nnet/core/sock_map.c-1851-\t\t\t\t struct bpf_link_info *info)\n--\nnet/core/sock_map.c-1853-\tconst struct sockmap_link *sockmap_link = container_of(link, struct sockmap_link, link);\nnet/core/sock_map.c:1854:\tu32 map_id = sock_map_link_get_map_id(sockmap_link);\nnet/core/sock_map.c-1855-\n--\nnet/core/sock_map.c-1860-\nnet/core/sock_map.c:1861:static void sock_map_link_show_fdinfo(const struct bpf_link *link,\nnet/core/sock_map.c-1862-\t\t\t\t struct seq_file *seq)\n--\nnet/core/sock_map.c-1864-\tconst struct sockmap_link *sockmap_link = container_of(link, struct sockmap_link, link);\nnet/core/sock_map.c:1865:\tu32 map_id = sock_map_link_get_map_id(sockmap_link);\nnet/core/sock_map.c-1866-\n--\nnet/core/sock_map.c-1870-\nnet/core/sock_map.c:1871:static const struct bpf_link_ops sock_map_link_ops = {\nnet/core/sock_map.c:1872:\t.release = sock_map_link_release,\nnet/core/sock_map.c:1873:\t.dealloc = sock_map_link_dealloc,\nnet/core/sock_map.c:1874:\t.detach = sock_map_link_detach,\nnet/core/sock_map.c:1875:\t.update_prog = sock_map_link_update_prog,\nnet/core/sock_map.c:1876:\t.fill_link_info = sock_map_link_fill_info,\nnet/core/sock_map.c:1877:\t.show_fdinfo = sock_map_link_show_fdinfo,\nnet/core/sock_map.c-1878-};\nnet/core/sock_map.c-1879-\nnet/core/sock_map.c:1880:int sock_map_link_create(const union bpf_attr *attr, struct bpf_prog *prog)\nnet/core/sock_map.c-1881-{\n--\nnet/core/sock_map.c-1905-\tattach_type = attr-\u003elink_create.attach_type;\nnet/core/sock_map.c:1906:\tbpf_link_init(\u0026sockmap_link-\u003elink, BPF_LINK_TYPE_SOCKMAP, \u0026sock_map_link_ops, prog,\nnet/core/sock_map.c-1907-\t\t attach_type);\n"
} |
| 13/2 | 2026/10/31 13:00 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 17475 output: 29 thoughts: 783 Thoughts: **Analyzing Sockmap/Sockhash Function Calls for Updates and Deletions** Okay, let's dissect the function call graph within `sock_map.c` related to updating and deleting elements in sockmaps and sockhashes. My initial focus is on identifying the key functions involved, as this is critical for understanding the scope of any potential changes. I've noted the following: `sock_map_link` (static, called by `sock_map_update_common` and `sock_hash_update_common`), `sock_map_del_link` (static, called by `sock_map_unref`), `sock_map_unref` (static, called by several functions including `__sock_map_delete`, `sock_map_free`, `sock_hash_delete_elem`, and others), `sock_map_update_common` (static, called by `sock_map_update_elem_sys` and `sock_map_update_elem`), `sock_hash_update_common` (static, called by `sock_map_update_elem_sys` and `sock_map_update_elem`), `sock_map_update_elem_sys` (non-static), `sock_map_update_elem` (static, an operation in `sock_map_ops` and `sock_hash_ops`), `sock_map_delete_elem` (static, an operation in `sock_map_ops`), `sock_hash_delete_elem` (static, an operation in `sock_hash_ops`), `sock_map_psock_get_checked` (static, modified by the patch), and `sock_map_sk_is_suitable` (static, also modified by the patch). Now, a crucial question arises regarding the inclusion of static functions in the `FocusSymbols` list. If a static function isn't inlined, it should be a distinct symbol in the vmlinux, right? I want to confirm that gcc/clang are preserving them. My understanding is that, normally, static functions in .c files *are* symbols in vmlinux, unless explicitly inlined. The documentation specifically addresses "STATIC INLINE FUNCTIONS IN HEADERS (.h)" but also mentions non-static API entrypoints. The key here is to differentiate between the two. The rule emphasizes looking for non-static caller functions, in .c files that exercise those static inline helpers, and I need to distinguish this from the static functions in this `.c` file. To further refine this, I'm going to determine what functions have been directly modified by the patch: `sock_map_del_link`, `sock_map_psock_get_checked`, `sock_map_link`, and `sock_map_sk_is_suitable`. These are the ones where the changes are focused. And now I need to determine the *direct* callers, or entrypoints, to these functions. Those include: `sock_map_update_elem_sys`, `sock_map_update_common`, `sock_hash_update_common`, `sock_map_delete_elem`, `sock_hash_delete_elem` and `sock_map_unref`. These are the functions where I need to look for calls to the modified function. Finally, just to be thorough and to understand the context of this code, I'll quickly check the Kconfig options that enable `net/core/sock_map.c` and take a look at `net/core/Makefile` to see how it's integrated into the build process. This will ensure I have a complete picture of the dependencies and potential impacts of these changes. |
| 14/2 | 2026/10/31 13:00 | tool | grepper |
0mArgs:{
"Expression": "sock_map",
"PathPrefixes": [
"net/core/Makefile"
]
}Results: {
"Output": "net/core/Makefile=44=obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o\nnet/core/Makefile:45:obj-$(CONFIG_BPF_SYSCALL) += sock_map.o\nnet/core/Makefile-46-obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o\n"
} |
| 15/2 | 2026/10/31 13:00 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 19168 output: 32 thoughts: 63 Thoughts: Okay, here's what's going through my mind as I analyze this: **Deep Dive into `sock_map.o` Dependency** Right, so I'm looking at `net/core/Makefile` and I see this line: `obj-$(CONFIG_BPF_SYSCALL) += sock_map.o`. Okay, so `sock_map.o` is being included when `CONFIG_BPF_SYSCALL` is enabled. Seems straightforward enough at first glance. But hang on a minute... is *that* the only dependency? Is `CONFIG_BPF_SYSCALL` the *only* pre-requisite for `sock_map.o` to be compiled into the kernel? It's important to be sure, I don't want to miss some nuance here. To be absolutely certain I'm not missing anything, let's double-check the source code for `sock_map.c`. I need to scan that file for any other conditional compilation directives, specifically looking for any `#ifdef CONFIG_...` statements that might introduce additional requirements or dependencies. It's easy to overlook things like this, especially in large codebases, so a thorough check is always worth the effort. |
| 16/2 | 2026/10/31 13:01 | tool | grepper |
0mArgs:{
"Expression": "CONFIG_",
"PathPrefixes": [
"net/core/sock_map.c"
]
}Results: {
"Output": "net/core/sock_map.c=1482=static int sock_map_prog_link_lookup(struct bpf_map *map, struct bpf_prog ***pprog,\n--\nnet/core/sock_map.c-1496-\t\tbreak;\nnet/core/sock_map.c:1497:#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)\nnet/core/sock_map.c-1498-\tcase BPF_SK_SKB_STREAM_PARSER:\n"
} |
| 17/2 | 2026/10/31 13:01 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 19665 output: 21 thoughts: 49 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Analyzing Kernel Configuration for BPF Stream Parser** Alright, *there* it is! I see the `IS_ENABLED(CONFIG_BPF_STREAM_PARSER)` macro in the code. My brain immediately jumps into investigation mode. I recognize this as a critical piece of information. The first thing I'm going to do is figure out what's enabling this specific feature. My next reflex is to reach for the familiar tools. I'm going to kick off a `grep` session. I'll search through the `Kconfig` files looking for references to both `CONFIG_BPF_STREAM_PARSER` and just `BPF_STREAM_PARSER`. I want to understand: 1) where this configuration option is defined, its dependencies, default values, and description, and 2) if `BPF_STREAM_PARSER` is used as a plain C define which might be set by the Kconfig. I want the complete picture: who is using it? What other features need to be enabled? Which dependencies are relevant? What's the impact on the kernel image size or performance? I want to understand if it's a configurable option and how. A deep-dive into the configuration is essential before I even *think* about looking at the BPF stream parser code itself. This initial check can make sure I have the full picture. |
| 18/2 | 2026/10/31 13:01 | tool | grepper |
0mArgs:{
"Expression": "BPF_STREAM_PARSER"
}Results: {
"Output": "arch/loongarch/configs/loongson32_defconfig=364=CONFIG_CGROUP_NET_PRIO=y\narch/loongarch/configs/loongson32_defconfig:365:CONFIG_BPF_STREAM_PARSER=y\narch/loongarch/configs/loongson32_defconfig-366-CONFIG_BT=m\n--\narch/loongarch/configs/loongson64_defconfig=380=CONFIG_CGROUP_NET_PRIO=y\narch/loongarch/configs/loongson64_defconfig:381:CONFIG_BPF_STREAM_PARSER=y\narch/loongarch/configs/loongson64_defconfig-382-CONFIG_BT=m\n--\ninclude/linux/skmsg.h=84=struct sk_psock {\n--\ninclude/linux/skmsg.h-92-\tstruct sk_psock_progs\t\tprogs;\ninclude/linux/skmsg.h:93:#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)\ninclude/linux/skmsg.h-94-\tstruct strparser\t\tstrp;\n--\ninclude/linux/skmsg.h=437=void sk_psock_stop(struct sk_psock *psock);\ninclude/linux/skmsg.h-438-\ninclude/linux/skmsg.h:439:#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)\ninclude/linux/skmsg.h-440-int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock);\n--\ninclude/net/tcp.h=2886=void tcp_bpf_clone(const struct sock *sk, struct sock *newsk);\ninclude/net/tcp.h:2887:#ifdef CONFIG_BPF_STREAM_PARSER\ninclude/net/tcp.h-2888-struct strparser;\ninclude/net/tcp.h=2889=int tcp_bpf_strp_read_sock(struct strparser *strp, read_descriptor_t *desc,\ninclude/net/tcp.h-2890-\t\t\t sk_read_actor_t recv_actor);\ninclude/net/tcp.h:2891:#endif /* CONFIG_BPF_STREAM_PARSER */\ninclude/net/tcp.h-2892-#endif /* CONFIG_BPF_SYSCALL */\n--\nnet/Kconfig=353=config BQL\n--\nnet/Kconfig-359-\nnet/Kconfig:360:config BPF_STREAM_PARSER\nnet/Kconfig-361-\tbool \"enable BPF STREAM_PARSER\"\n--\nnet/core/skmsg.c=545=static int sk_psock_skb_ingress_enqueue(struct sk_buff *skb,\n--\nnet/core/skmsg.c-573-\nnet/core/skmsg.c:574:#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)\nnet/core/skmsg.c-575-\tpsock-\u003eingress_bytes += len;\n--\nnet/core/skmsg.c=1061=static void sk_psock_write_space(struct sock *sk)\n--\nnet/core/skmsg.c-1077-\nnet/core/skmsg.c:1078:#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)\nnet/core/skmsg.c-1079-static void sk_psock_strp_read(struct strparser *strp, struct sk_buff *skb)\n--\nnet/core/skmsg.c=1197=static void sk_psock_done_strp(struct sk_psock *psock)\n--\nnet/core/skmsg.c-1199-}\nnet/core/skmsg.c:1200:#endif /* CONFIG_BPF_STREAM_PARSER */\nnet/core/skmsg.c-1201-\n--\nnet/core/sock_map.c=1482=static int sock_map_prog_link_lookup(struct bpf_map *map, struct bpf_prog ***pprog,\n--\nnet/core/sock_map.c-1496-\t\tbreak;\nnet/core/sock_map.c:1497:#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)\nnet/core/sock_map.c-1498-\tcase BPF_SK_SKB_STREAM_PARSER:\n--\nnet/ipv4/tcp_bpf.c=677=static int tcp_bpf_assert_proto_ops(struct proto *ops)\n--\nnet/ipv4/tcp_bpf.c-686-\nnet/ipv4/tcp_bpf.c:687:#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)\nnet/ipv4/tcp_bpf.c-688-int tcp_bpf_strp_read_sock(struct strparser *strp, read_descriptor_t *desc,\n--\nnet/ipv4/tcp_bpf.c-720-}\nnet/ipv4/tcp_bpf.c:721:#endif /* CONFIG_BPF_STREAM_PARSER */\nnet/ipv4/tcp_bpf.c-722-\n--\ntools/bpf/bpftool/feature.c=328=static void probe_kernel_image_config(const char *define_prefix)\n--\ntools/bpf/bpftool/feature.c-392-\t\t/* BPF stream parser and BPF socket maps */\ntools/bpf/bpftool/feature.c:393:\t\t{ \"CONFIG_BPF_STREAM_PARSER\", },\ntools/bpf/bpftool/feature.c-394-\t\t/* xt_bpf module for passing BPF programs to netfilter */\n--\ntools/testing/selftests/bpf/config=9=CONFIG_BPF_LSM=y\ntools/testing/selftests/bpf/config:10:CONFIG_BPF_STREAM_PARSER=y\ntools/testing/selftests/bpf/config-11-CONFIG_BPF_SYSCALL=y\n--\ntools/testing/selftests/hid/config=7=CONFIG_BPF_PRELOAD=y\ntools/testing/selftests/hid/config:8:CONFIG_BPF_STREAM_PARSER=y\ntools/testing/selftests/hid/config-9-CONFIG_BPF_SYSCALL=y\n"
} |
| 19/2 | 2026/10/31 13:01 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 21668 output: 32 thoughts: 35 Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective: **Diving into the Kernel Configuration for BPF Stream Parser Dependencies** Alright, time to dig into the kernel configuration. I need to understand the dependencies and/or selections influencing `CONFIG_BPF_STREAM_PARSER`. I know roughly where it should be defined, so let's jump straight to `net/Kconfig`, around line 360 – that's usually a good starting point for network-related Kconfig entries. This should tell me quickly whether it depends on or is selected by something else. Knowing this helps tremendously with debugging or changing related code. Time to get the lay of the land! |
| 20/2 | 2026/10/31 13:01 | tool | read-file |
0mArgs:{
"File": "net/Kconfig",
"FirstLine": 355,
"LineCount": 25
}Results: {
"Contents": " 355:\t\tprompt \"Enable Byte Queue Limits\"\n 356:\t\tdepends on SYSFS\n 357:\t\tselect DQL\n 358:\t\tdefault y\n 359:\t\n 360:\tconfig BPF_STREAM_PARSER\n 361:\t\tbool \"enable BPF STREAM_PARSER\"\n 362:\t\tdepends on INET\n 363:\t\tdepends on BPF_SYSCALL\n 364:\t\tdepends on CGROUP_BPF\n 365:\t\tselect STREAM_PARSER\n 366:\t\tselect NET_SOCK_MSG\n 367:\t\thelp\n 368:\t\t Enabling this allows a TCP stream parser to be used with\n 369:\t\t BPF_MAP_TYPE_SOCKMAP.\n 370:\t\n 371:\tconfig NET_FLOW_LIMIT\n 372:\t\tbool \"Net flow limit\"\n 373:\t\tdepends on RPS\n 374:\t\tdefault y\n 375:\t\thelp\n 376:\t\t The network stack has to drop packets when a receive processing CPU's\n 377:\t\t backlog reaches netdev_max_backlog. If a few out of many active flows\n 378:\t\t generate the vast majority of load, drop their traffic earlier to\n 379:\t\t maintain capacity for the other flows. This feature provides servers\n"
} |
| 21/2 | 2026/10/31 13:01 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 22240 output: 28 thoughts: 79 Thoughts: Okay, here's my breakdown of what's going on, thinking it through from a kernel expert's perspective: **Kernel Configuration Dependencies: Deciphering the BPF Stream Parser** Alright, so `CONFIG_BPF_STREAM_PARSER`... that's our starting point. Right off the bat, I see it's pulling in `NET_SOCK_MSG` and `STREAM_PARSER`, and it's also dependent on `INET`, `BPF_SYSCALL`, and `CGROUP_BPF`. Makes sense, BPF stream parsing is usually network-centric, and needs syscall and cgroup integration. But hold on a second... `NET_SOCK_MSG`... why is *that* being pulled in? I need to understand the relationship and *why*. I can't just assume anything, so I'm going to jump straight to the source. Let me go check `net/Kconfig` to see the dependencies that select `NET_SOCK_MSG`. Understanding its dependencies is the key to understanding this entire thing. |
| 22/2 | 2026/10/31 13:01 | tool | grepper |
0mArgs:{
"Expression": "NET_SOCK_MSG",
"PathPrefixes": [
"net/"
]
}Results: {
"Output": "net/Kconfig=360=config BPF_STREAM_PARSER\n--\nnet/Kconfig-365-\tselect STREAM_PARSER\nnet/Kconfig:366:\tselect NET_SOCK_MSG\nnet/Kconfig-367-\thelp\n--\nnet/Kconfig=474=config NET_SELFTESTS\n--\nnet/Kconfig-477-\nnet/Kconfig:478:config NET_SOCK_MSG\nnet/Kconfig-479-\tbool\n--\nnet/Kconfig-481-\thelp\nnet/Kconfig:482:\t The NET_SOCK_MSG provides a framework for plain sockets (e.g. TCP) or\nnet/Kconfig-483-\t ULPs (upper layer modules, e.g. TLS) to process L7 application data\n--\nnet/core/Makefile=43=obj-$(CONFIG_FAILOVER) += failover.o\nnet/core/Makefile:44:obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o\nnet/core/Makefile-45-obj-$(CONFIG_BPF_SYSCALL) += sock_map.o\n--\nnet/ipv4/Kconfig=382=config INET_ESPINTCP\n--\nnet/ipv4/Kconfig-385-\tselect STREAM_PARSER\nnet/ipv4/Kconfig:386:\tselect NET_SOCK_MSG\nnet/ipv4/Kconfig-387-\tselect XFRM_ESPINTCP\n--\nnet/ipv4/Makefile=63=obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o\nnet/ipv4/Makefile:64:obj-$(CONFIG_NET_SOCK_MSG) += tcp_bpf.o\nnet/ipv4/Makefile-65-obj-$(CONFIG_BPF_SYSCALL) += udp_bpf.o\n--\nnet/ipv6/Kconfig=90=config INET6_ESPINTCP\n--\nnet/ipv6/Kconfig-93-\tselect STREAM_PARSER\nnet/ipv6/Kconfig:94:\tselect NET_SOCK_MSG\nnet/ipv6/Kconfig-95-\tselect XFRM_ESPINTCP\n--\nnet/tls/Kconfig=5=config TLS\n--\nnet/tls/Kconfig-10-\tselect CRYPTO_GCM\nnet/tls/Kconfig:11:\tselect NET_SOCK_MSG\nnet/tls/Kconfig-12-\tdefault n\n"
} |
| 23/2 | 2026/10/31 13:01 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 23191 output: 23 thoughts: 1502 Thoughts: **Analyzing BPF STREAM_PARSER and Sockmap Configuration** Okay, so here's what I've got in mind. It starts with `CONFIG_BPF_STREAM_PARSER` selecting `NET_SOCK_MSG`. And that's important because, looking at `net/ipv4/Makefile`, `tcp_bpf.o` gets included only if `CONFIG_NET_SOCK_MSG` is set, and this in turn pulls in `tcp_bpf_update_proto` which sets `psock_update_sk_prot`. The very compilation of `tcp_bpf.o` depends on this selection. I see that `CONFIG_BPF_STREAM_PARSER` is a configurable boolean, depending on `INET`, `BPF_SYSCALL`, and `CGROUP_BPF`. It also selects `STREAM_PARSER` and `NET_SOCK_MSG`. Now, in the diff, I'm noticing that the `sk_psock_stop_strp` function, which seems related to stream parsing, is called conditionally based on the `progs->stream_parser` flag. The same applies for other stream verdict-related flags and functions. `sk_psock_stop_strp` is called if `strp_stop`, which is related to `BPF_STREAM_PARSER`. Okay, so `CONFIG_BPF_SYSCALL` is also significant. That compiles `net/core/sock_map.o`. So, it looks like `NET_SOCK_MSG` or `BPF_STREAM_PARSER` enables `skmsg.o` and `tcp_bpf.o`, which further hints at the connection. Now, I should confirm where `BPF_SYSCALL` and `CGROUP_BPF` are defined - `init/Kconfig` it is. So, if I enable `CONFIG_BPF_SYSCALL`, `CONFIG_BPF_STREAM_PARSER` (and `CGROUP_BPF`, `INET`), I'm enabling stream parser and sockmap, no question about it. Now, can `NET_SOCK_MSG` be enabled directly? No, since it's a non-prompt option (a boolean without a prompt string), it can only be selected by other configurations such as `BPF_STREAM_PARSER` or `TLS`. So, that's it: `BPF_STREAM_PARSER` is the key to enabling both the stream parser and `sock_msg` features, and `BPF_SYSCALL` activates the BPF system call and `sock_map.c`. Now, let's establish which configs are relevant here: `CONFIG_NET` and `CONFIG_INET` are standard, but I need to make sure to enable `CONFIG_BPF_SYSCALL` and `CONFIG_BPF_STREAM_PARSER` if I want stream parsing within the sockmap. Alright, let's think about the `FocusSymbols`. What functions are important here? I should identify the functions that are either modified or directly call the modified logic. I think I have it: * `sock_map_link` * `sock_map_del_link` * `sock_map_unref` * `sock_map_psock_get_checked` * `sock_map_sk_is_suitable` * `sock_map_update_elem_sys` * `sock_map_update_elem` * `sock_map_update_common` * `sock_hash_update_common` * `sock_map_delete_elem` * `sock_hash_delete_elem` Now, let me check the rule about ubiquitous lifecycle hot-paths. None of these functions are generic or ubiquitous. These `sock_map` functions are specifically involved in BPF map operations on sockmap / sockhash. They are not called elsewhere. Specifically, these are feature specific logic, so they are suitable symbols for focusing. Let's quickly check whether `sock_map_link` and `sock_map_del_link` are static. Yes, they are static functions within `net/core/sock_map.c`. However, even static functions, if not inlined and are separate C functions, have their symbols in ELF. Now, `sock_map_update_elem_sys` is a global function and exported for bpf syscall/verifier interaction. So, these should be what I'm looking for as entrypoints. Let me check where `sock_map_update_elem_sys` is declared and used in more detail. That should be a good starting point. |
| 24/2 | 2026/10/31 13:01 | tool | grepper |
0mArgs:{
"Expression": "sock_map_update_elem_sys"
}Results: {
"Output": "include/linux/bpf.h=3855=int sock_map_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype);\ninclude/linux/bpf.h:3856:int sock_map_update_elem_sys(struct bpf_map *map, void *key, void *value, u64 flags);\ninclude/linux/bpf.h-3857-int sock_map_bpf_prog_query(const union bpf_attr *attr,\n--\ninclude/linux/bpf.h=3945=static inline int sock_map_prog_detach(const union bpf_attr *attr,\n--\ninclude/linux/bpf.h-3950-\ninclude/linux/bpf.h:3951:static inline int sock_map_update_elem_sys(struct bpf_map *map, void *key, void *value,\ninclude/linux/bpf.h-3952-\t\t\t\t\t u64 flags)\n--\nkernel/bpf/syscall.c=250=static int bpf_map_update_value(struct bpf_map *map, struct file *map_file,\n--\nkernel/bpf/syscall.c-263-\t\t map-\u003emap_type == BPF_MAP_TYPE_SOCKMAP) {\nkernel/bpf/syscall.c:264:\t\treturn sock_map_update_elem_sys(map, key, value, flags);\nkernel/bpf/syscall.c-265-\t} else if (IS_FD_PROG_ARRAY(map)) {\n--\nnet/core/sock_map.c=560=static int sock_hash_update_common(struct bpf_map *map, void *key,\n--\nnet/core/sock_map.c-562-\nnet/core/sock_map.c:563:int sock_map_update_elem_sys(struct bpf_map *map, void *key, void *value,\nnet/core/sock_map.c-564-\t\t\t u64 flags)\n"
} |
| 25/2 | 2026/10/31 13:01 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 26256 output: 44 thoughts: 83 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience: **Kernel BPF Map Update for Sockmap/Sockhash: Key Call Flow** Alright, so the initial thought is crystal clear. I'm zeroing in on the critical `sock_map_update_elem_sys` function. I know immediately it's the direct handler for `BPF_MAP_UPDATE_ELEM` when dealing with `BPF_MAP_TYPE_SOCKMAP` and `BPF_MAP_TYPE_SOCKHASH`. That makes sense, given the context of what those map types do within the networking stack. I need to keep the high-level picture in mind: these maps manage sockets, so I expect a strong link to network-related code. But now, I need to complete the picture. I need to address the other side of map management: what's going on with deletions? I am going to have to make sure I completely understand the call flows, so, next up, I will check the `BPF_MAP_DELETE_ELEM` operation in `kernel/bpf/syscall.c` and make sure I know how it's handled. Is it a separate function? Does it use the same one with a flag? What's going on?! Gotta confirm what's happening at the `kernel/bpf/syscall.c` level regarding deletion. Understanding the full picture of both update and delete is essential. |
| 26/2 | 2026/10/31 13:01 | tool | grepper |
0mArgs:{
"Expression": "sock_map_delete|sock_hash_delete",
"PathPrefixes": [
"kernel/bpf/",
"net/core/"
]
}Results: {
"Output": "net/core/sock_map.c=405=static void *sock_map_lookup_sys(struct bpf_map *map, void *key)\n--\nnet/core/sock_map.c-419-\nnet/core/sock_map.c:420:static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test,\nnet/core/sock_map.c-421-\t\t\t struct sock **psk)\n--\nnet/core/sock_map.c-438-\nnet/core/sock_map.c:439:static void sock_map_delete_from_link(struct bpf_map *map, struct sock *sk,\nnet/core/sock_map.c-440-\t\t\t\t void *link_raw)\n--\nnet/core/sock_map.c-443-\nnet/core/sock_map.c:444:\t__sock_map_delete(stab, sk, link_raw);\nnet/core/sock_map.c-445-}\nnet/core/sock_map.c-446-\nnet/core/sock_map.c:447:static long sock_map_delete_elem(struct bpf_map *map, void *key)\nnet/core/sock_map.c-448-{\n--\nnet/core/sock_map.c-456-\tpsk = \u0026stab-\u003esks[i];\nnet/core/sock_map.c:457:\treturn __sock_map_delete(stab, NULL, psk);\nnet/core/sock_map.c-458-}\n--\nnet/core/sock_map.c=836=const struct bpf_map_ops sock_map_ops = {\n--\nnet/core/sock_map.c-842-\t.map_update_elem\t= sock_map_update_elem,\nnet/core/sock_map.c:843:\t.map_delete_elem\t= sock_map_delete_elem,\nnet/core/sock_map.c-844-\t.map_lookup_elem\t= sock_map_lookup,\n--\nnet/core/sock_map.c=916=static void sock_hash_free_elem(struct bpf_shtab *htab,\n--\nnet/core/sock_map.c-922-\nnet/core/sock_map.c:923:static void sock_hash_delete_from_link(struct bpf_map *map, struct sock *sk,\nnet/core/sock_map.c-924-\t\t\t\t void *link_raw)\n--\nnet/core/sock_map.c-947-\nnet/core/sock_map.c:948:static long sock_hash_delete_elem(struct bpf_map *map, void *key)\nnet/core/sock_map.c-949-{\n--\nnet/core/sock_map.c=1151=static void sock_hash_free(struct bpf_map *map)\n--\nnet/core/sock_map.c-1167-\nnet/core/sock_map.c:1168:\t\t/* We are racing with sock_hash_delete_from_link to\nnet/core/sock_map.c-1169-\t\t * enter the spin-lock critical section. Every socket on\n--\nnet/core/sock_map.c=1452=const struct bpf_map_ops sock_hash_ops = {\n--\nnet/core/sock_map.c-1457-\t.map_update_elem\t= sock_map_update_elem,\nnet/core/sock_map.c:1458:\t.map_delete_elem\t= sock_hash_delete_elem,\nnet/core/sock_map.c-1459-\t.map_lookup_elem\t= sock_hash_lookup,\n--\nnet/core/sock_map.c=1626=static void sock_map_unlink(struct sock *sk, struct sk_psock_link *link)\n--\nnet/core/sock_map.c-1629-\tcase BPF_MAP_TYPE_SOCKMAP:\nnet/core/sock_map.c:1630:\t\treturn sock_map_delete_from_link(link-\u003emap, sk,\nnet/core/sock_map.c-1631-\t\t\t\t\t\t link-\u003elink_raw);\nnet/core/sock_map.c-1632-\tcase BPF_MAP_TYPE_SOCKHASH:\nnet/core/sock_map.c:1633:\t\treturn sock_hash_delete_from_link(link-\u003emap, sk,\nnet/core/sock_map.c-1634-\t\t\t\t\t\t link-\u003elink_raw);\n"
} |
| 27/2 | 2026/10/31 13:01 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 27878 output: 32 thoughts: 512 Thoughts: **My Analysis of the Socket Map Code and Dependencies** Okay, let's break this down. From what I'm seeing, `sock_map_ops.map_delete_elem` is, naturally, implemented as `sock_map_delete_elem`, and similarly, `sock_hash_ops.map_delete_elem` corresponds to `sock_hash_delete_elem`. The unlink operations, specifically `sock_map_unlink`, appear to be calling `sock_map_delete_from_link` and `sock_hash_delete_from_link`. It seems all these delete pathways ultimately converge into `sock_map_unref`, which then calls `sock_map_del_link`. So the central functions in this code, as I understand it, are: * `sock_map_link` * `sock_map_del_link` * `sock_map_unref` * `sock_map_psock_get_checked` * `sock_map_update_elem_sys` * `sock_map_update_common` * `sock_hash_update_common` * `sock_map_delete_elem` * `sock_hash_delete_elem` * `sock_map_sk_is_suitable` Now, let's ensure the necessary kernel configs are in place. I need to verify that `BPF_SYSCALL`, `BPF_STREAM_PARSER`, and `NET_SOCK_MSG` are enabled. I understand `NET_SOCK_MSG` is a dependency of `BPF_STREAM_PARSER`, but it's always good to be thorough and confirm. Wait, are there specific dependencies that might require `CGROUP_BPF`? I need to check. Let's look at `BPF_STREAM_PARSER`: Yes, there it is! `BPF_STREAM_PARSER` explicitly depends on `CGROUP_BPF`, in addition to `INET` and `BPF_SYSCALL`. So, I need to make sure that `CGROUP_BPF`, `BPF_SYSCALL`, and `BPF_STREAM_PARSER` are all enabled for this to function correctly. Just to be sure, let me double-check the dependencies of `CGROUP_BPF` in the kernel configuration files. |
| 28/2 | 2026/10/31 13:01 | tool | grepper |
0mArgs:{
"Expression": "config CGROUP_BPF",
"PathPrefixes": [
"init/Kconfig"
]
}Results: {
"Output": "init/Kconfig=1149=config CGROUP_PERF\n--\ninit/Kconfig-1159-\ninit/Kconfig:1160:config CGROUP_BPF\ninit/Kconfig-1161-\tbool \"Support for eBPF programs attached to cgroups\"\n"
} |
| 29/2 | 2026/10/31 13:01 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 29033 output: 33 thoughts: 22 Thoughts: Here's my take on those lines from `init/Kconfig`, considering my own expertise: **Examining Kconfig Configuration for Initialization** Alright, let's dive into lines 1160-1175 within `init/Kconfig`. Based on my understanding of the system architecture and boot process, I'm expecting to see configuration options that directly impact the initialization phase. Given the naming convention and location, I'd anticipate seeing options related to early boot parameters, potentially defining how the kernel handles early hardware detection or initial filesystem setup. I will be looking closely for dependencies and defaults that affect other configuration variables. My goal is to understand how these specific settings influence the core system initialization and whether they align with my current understanding of the intended system configuration and boot procedure. The implications of these settings could be very important, so let's check them. |
| 30/2 | 2026/10/31 13:01 | tool | read-file |
0mArgs:{
"File": "init/Kconfig",
"FirstLine": 1160,
"LineCount": 15
}Results: {
"Contents": "1160:\tconfig CGROUP_BPF\n1161:\t\tbool \"Support for eBPF programs attached to cgroups\"\n1162:\t\tdepends on BPF_SYSCALL\n1163:\t\tselect SOCK_CGROUP_DATA\n1164:\t\thelp\n1165:\t\t Allow attaching eBPF programs to a cgroup using the bpf(2)\n1166:\t\t syscall command BPF_PROG_ATTACH.\n1167:\t\n1168:\t\t In which context these programs are accessed depends on the type\n1169:\t\t of attachment. For instance, programs that are attached using\n1170:\t\t BPF_CGROUP_INET_INGRESS will be executed on the ingress path of\n1171:\t\t inet sockets.\n1172:\t\n1173:\tconfig CGROUP_MISC\n1174:\t\tbool \"Misc resource controller\"\n"
} |
| 31/2 | 2026/10/31 13:01 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 29513 output: 272 thoughts: 658 Thoughts: **Fuzzing Verdict: BPF Socket Map Core** Okay, let's break this down for the `set-results` call. I've analyzed the dependencies and the code changes to determine the optimal configuration and fuzzing targets. First, the configuration. It looks like `CGROUP_BPF` is solely dependent on `BPF_SYSCALL`, and `BPF_STREAM_PARSER` depends on `INET`, `BPF_SYSCALL`, and `CGROUP_BPF`. Based on the evidence, the core configuration settings required should be: `BPF_SYSCALL`, `BPF_STREAM_PARSER`, `CGROUP_BPF`, and since `BPF_STREAM_PARSER` also depends on `NET` or `INET`, we can be reasonably confident we have them covered. The analysis of `net/core/Makefile` confirms `BPF_SYSCALL` is used by `sock_map.c`. Also, `CONFIG_BPF_STREAM_PARSER` selects `NET_SOCK_MSG` and `STREAM_PARSER`, which further supports the conclusions of the config dependencies. Now, let's talk about the fuzzing targets. The most important area is `net/core/sock_map.c` itself. The patch is modifying the locking and race conditions within `net/core/sock_map.c` during link insertion and removal. Specifically, I see changes to how `sk->sk_callback_lock` is handled, the inclusion of `READ_ONCE` for `sk->sk_prot` reads, and restructuring of conditions around parser/verdict handlers and protocol updates. This is directly related to core BPF socket map code accessible through the `bpf()` syscall and socket operations, which can be called both by unprivileged and privileged operations. So, the focus is squarely on the socket map code, and I've identified the key symbols to target: - `sock_map_link` - `sock_map_del_link` - `sock_map_update_elem_sys` - `sock_map_unref` - `sock_map_psock_get_checked` - `sock_map_update_common` - `sock_hash_update_common` - `sock_map_sk_is_suitable` - `sock_map_delete_elem` - `sock_hash_delete_elem` I've also checked for other modified files, but it appears the changes are isolated to `net/core/sock_map.c` with the only other related change being in `tools/testing/selftests/bpf/prog_tests/sockmap_listen.c`, which is only for selftests and doesn't affect the core fuzzing target. Therefore, I'm confident in the `set-results` parameters. We should set `WorthFuzzing` to `true`, the `EnableConfigs` to `["BPF_SYSCALL", "BPF_STREAM_PARSER", "CGROUP_BPF"]`, and `FocusSymbols` to the list of core functions I've just outlined. The reasoning should be concise, reflecting the core focus of locking and race conditions within the critical BPF socket map code, exposed by the patch. |
| 32/2 | 2026/10/31 13:01 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"BPF_SYSCALL",
"BPF_STREAM_PARSER",
"CGROUP_BPF"
],
"FocusSymbols": [
"sock_map_link",
"sock_map_del_link",
"sock_map_unref",
"sock_map_psock_get_checked",
"sock_map_update_elem_sys",
"sock_map_update_common",
"sock_hash_update_common",
"sock_map_sk_is_suitable",
"sock_map_delete_elem",
"sock_hash_delete_elem"
],
"Reasoning": "The patch modifies synchronization and concurrency logic in BPF sockmap/sockhash management (net/core/sock_map.c). Specifically, it expands the critical section protected by sk-\u003esk_callback_lock across sock_map_init_proto in sock_map_link, alters the stopping conditions in sock_map_del_link, and adds READ_ONCE guards when checking sk-\u003esk_prot. These paths are directly reachable and exercise core networking/BPF socket-redirection mechanisms via standard bpf() system calls.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"BPF_SYSCALL",
"BPF_STREAM_PARSER",
"CGROUP_BPF"
],
"FocusSymbols": [
"sock_map_link",
"sock_map_del_link",
"sock_map_unref",
"sock_map_psock_get_checked",
"sock_map_update_elem_sys",
"sock_map_update_common",
"sock_hash_update_common",
"sock_map_sk_is_suitable",
"sock_map_delete_elem",
"sock_hash_delete_elem"
],
"Reasoning": "The patch modifies synchronization and concurrency logic in BPF sockmap/sockhash management (net/core/sock_map.c). Specifically, it expands the critical section protected by sk-\u003esk_callback_lock across sock_map_init_proto in sock_map_link, alters the stopping conditions in sock_map_del_link, and adds READ_ONCE guards when checking sk-\u003esk_prot. These paths are directly reachable and exercise core networking/BPF socket-redirection mechanisms via standard bpf() system calls.",
"WorthFuzzing": true
} |
| 33/1 | 2026/10/31 13:01 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 34/2 | 2026/10/31 13:01 | agent | kmsan-evaluator |
0mModel:core Args: null Results: {
"KMSANReasoning": "The patch addresses race conditions and synchronization issues in sockmap when concurrently inserting and deleting sockets with attached verdict/parser BPF programs (fixing data races on sk-\u003esk_prot via READ_ONCE and ensuring proper locking via sk_callback_lock during link removal and protocol initialization). \n\nThese changes address concurrency and state management bugs, which fall under the domain of KASAN, LOCKDEP, and KCSAN (e.g., use-after-free, data races, deadlocks). The patch does not introduce any new allocations, does not modify any buffers or copy_to_user operations, and does not read or expose uninitialized memory. 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 0141ff2361ad32060a297df2adf6322a51bd47b3
Author: syz-cluster <triage@syzkaller.com>
Date: Sat Oct 31 13:00:04 2026 +0000
syz-cluster: applied patch under review
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index 057e2f3c0265ed..efe49551caba9e 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -152,11 +152,11 @@ static void sock_map_del_link(struct sock *sk,
struct bpf_map *map = link->map;
struct sk_psock_progs *progs = sock_map_progs(map);
- if (psock->saved_data_ready && progs->stream_parser)
+ if (progs->stream_parser)
strp_stop = true;
- if (psock->saved_data_ready && progs->stream_verdict)
+ if (progs->stream_verdict)
verdict_stop = true;
- if (psock->saved_data_ready && progs->skb_verdict)
+ if (progs->skb_verdict)
verdict_stop = true;
list_del(&link->list);
sk_psock_free_link(link);
@@ -164,8 +164,11 @@ static void sock_map_del_link(struct sock *sk,
}
}
spin_unlock_bh(&psock->link_lock);
- if (strp_stop || verdict_stop) {
- write_lock_bh(&sk->sk_callback_lock);
+ if (!strp_stop && !verdict_stop)
+ return;
+
+ write_lock_bh(&sk->sk_callback_lock);
+ if (psock->saved_data_ready) {
if (strp_stop)
sk_psock_stop_strp(sk, psock);
if (verdict_stop)
@@ -173,8 +176,8 @@ static void sock_map_del_link(struct sock *sk,
if (psock->psock_update_sk_prot)
psock->psock_update_sk_prot(sk, psock, false);
- write_unlock_bh(&sk->sk_callback_lock);
}
+ write_unlock_bh(&sk->sk_callback_lock);
}
static void sock_map_unref(struct sock *sk, void *link_raw)
@@ -202,7 +205,7 @@ static struct sk_psock *sock_map_psock_get_checked(struct sock *sk)
rcu_read_lock();
psock = sk_psock(sk);
if (psock) {
- if (sk->sk_prot->close != sock_map_close) {
+ if (READ_ONCE(sk->sk_prot)->close != sock_map_close) {
psock = ERR_PTR(-EBUSY);
goto out;
}
@@ -284,6 +287,7 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)
}
}
+ write_lock_bh(&sk->sk_callback_lock);
if (msg_parser)
psock_set_prog(&psock->progs.msg_parser, msg_parser);
if (stream_parser)
@@ -298,11 +302,11 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)
*/
ret = sock_map_init_proto(sk, psock);
if (ret < 0) {
+ write_unlock_bh(&sk->sk_callback_lock);
sk_psock_put(sk, psock);
goto out;
}
- write_lock_bh(&sk->sk_callback_lock);
if (stream_parser && stream_verdict && !psock->saved_data_ready) {
if (sk_is_tcp(sk))
ret = sk_psock_init_strp(sk, psock);
@@ -536,7 +540,7 @@ static bool sock_map_redirect_allowed(const struct sock *sk)
static bool sock_map_sk_is_suitable(const struct sock *sk)
{
- return !!sk->sk_prot->psock_update_sk_prot;
+ return !!READ_ONCE(sk->sk_prot)->psock_update_sk_prot;
}
static bool sock_map_sk_state_allowed(const struct sock *sk)
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
index 235e1d56f044f2..dca1f0de92e0ee 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
@@ -646,6 +646,82 @@ static void test_race_insert_listen(struct test_sockmap_listen *skel __always_un
xclose(s);
}
+struct update_delete_ctx {
+ unsigned int nr_iter;
+ unsigned int done;
+ int mapfd;
+};
+
+static void *delete_elem_thread(void *arg)
+{
+ struct update_delete_ctx *ctx = arg;
+ unsigned int i;
+
+ for (i = 0; i < ctx->nr_iter; i++) {
+ /* Expecting EINVAL (sockmap) or ENOENT (sockhash) when the
+ * entry is already gone.
+ */
+ if (bpf_map_delete_elem(ctx->mapfd, &(u32){0}) &&
+ errno != EINVAL && errno != ENOENT) {
+ FAIL_ERRNO("map_delete");
+ break;
+ }
+ }
+
+ WRITE_ONCE(ctx->done, 1);
+ return NULL;
+}
+
+/* One thread keeps inserting a socket into a sockmap with an attached
+ * verdict program while another thread deletes the same map entry.
+ */
+static void test_update_delete_with_prog(struct test_sockmap_listen *skel,
+ int family, int sotype, int mapfd)
+{
+ struct update_delete_ctx ctx = { 0 };
+ int err, s, verdict;
+ pthread_t t;
+ u64 value;
+
+ verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
+ err = xbpf_prog_attach(verdict, mapfd, BPF_SK_SKB_VERDICT, 0);
+ if (err)
+ return;
+
+ s = xsocket(family, sotype, 0);
+ if (s < 0)
+ goto detach;
+
+ err = xlisten(s, 1);
+ if (err)
+ goto close;
+
+ ctx.mapfd = mapfd;
+ ctx.nr_iter = 10000;
+
+ err = xpthread_create(&t, NULL, delete_elem_thread, &ctx);
+ if (err)
+ goto close;
+
+ value = s;
+ while (!READ_ONCE(ctx.done)) {
+ /* Expecting EBUSY while a deleted socket's psock still
+ * holds the verdict program.
+ */
+ err = bpf_map_update_elem(mapfd, &(u32){0}, &value, BPF_ANY);
+ if (err && errno != EBUSY) {
+ FAIL_ERRNO("map_update");
+ break;
+ }
+ }
+
+ xpthread_join(t, NULL);
+close:
+ xclose(s);
+detach:
+ xbpf_prog_detach2(verdict, mapfd, BPF_SK_SKB_VERDICT);
+}
+
static void zero_verdict_count(int mapfd)
{
unsigned int zero = 0;
@@ -1289,6 +1365,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
TEST(test_destroy_orphan_child, SOCK_STREAM),
TEST(test_syn_recv_insert_delete, SOCK_STREAM),
TEST(test_race_insert_listen, SOCK_STREAM),
+ TEST(test_update_delete_with_prog, SOCK_STREAM),
/* child clone */
TEST(test_clone_after_delete, SOCK_STREAM),
TEST(test_accept_after_delete, SOCK_STREAM),
|
| 35/3 | 2026/10/31 13:01 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 4300 output: 37 thoughts: 796 Thoughts: **Analyzing the Sockmap Changes** Okay, so this patch is touching `net/core/sock_map.c` and also adding a selftest. Let's start by digging into `net/core/sock_map.c`. From what I can see, the changes are centered around the interaction between the sockmap and the socket's protocol handlers, and how they interact. Specifically, in `sock_map_del_link`, it looks like there's a refinement in the logic that handles stopping stream parsers and verdicts when a link is being removed. Before, the check for `psock->saved_data_ready` was entangled with stopping the parser/verdict, this has now been streamlined to check the programs directly, which is logical. Further, the original code had a conditional lock/unlock for `sk->sk_callback_lock`, now the lock is held unconditionally, and the checks within the lock context. I'll need to check the exact semantics, this change appears to be adding a return early to optimize the code by bypassing the locks if neither are needed. This is an improvement. The code also seems to handle the `psock_update_sk_prot` function to update the socket protocol. The change in `sock_map_psock_get_checked` is just a safe read on `sk->sk_prot->close`. This use of `READ_ONCE` is a standard way to avoid potential data races and ensure the compiler doesn't optimize it away. No surprises here. In `sock_map_link`, the code now acquires a write lock (`sk->sk_callback_lock`) before setting up the programs on the socket. This ensures proper synchronization when associating programs with a socket. It also includes the necessary unlock when returning from an error. The change in `sock_map_sk_is_suitable` mirrors the use of `READ_ONCE` in the prior function, which is again, just a safe read on `sk->sk_prot->psock_update_sk_prot` for the same reasons. I'll need to use `read-file` or `grepper` to examine the surrounding code and understand the context better. I want to see if these changes are isolated or if they imply broader changes in how sockmaps are handled, or the intent of these functions. Overall, the changes seem focused on improving synchronization and making the control flow clearer within the sockmap interaction with socket protocols. |
| 36/3 | 2026/10/31 13:02 | tool | read-file |
0mArgs:{
"File": "net/core/sock_map.c",
"FirstLine": 140,
"LineCount": 50
}Results: {
"Contents": " 140:\t\tspin_unlock_bh(\u0026psock-\u003elink_lock);\n 141:\t}\n 142:\t\n 143:\tstatic void sock_map_del_link(struct sock *sk,\n 144:\t\t\t\t struct sk_psock *psock, void *link_raw)\n 145:\t{\n 146:\t\tbool strp_stop = false, verdict_stop = false;\n 147:\t\tstruct sk_psock_link *link, *tmp;\n 148:\t\n 149:\t\tspin_lock_bh(\u0026psock-\u003elink_lock);\n 150:\t\tlist_for_each_entry_safe(link, tmp, \u0026psock-\u003elink, list) {\n 151:\t\t\tif (link-\u003elink_raw == link_raw) {\n 152:\t\t\t\tstruct bpf_map *map = link-\u003emap;\n 153:\t\t\t\tstruct sk_psock_progs *progs = sock_map_progs(map);\n 154:\t\n 155:\t\t\t\tif (progs-\u003estream_parser)\n 156:\t\t\t\t\tstrp_stop = true;\n 157:\t\t\t\tif (progs-\u003estream_verdict)\n 158:\t\t\t\t\tverdict_stop = true;\n 159:\t\t\t\tif (progs-\u003eskb_verdict)\n 160:\t\t\t\t\tverdict_stop = true;\n 161:\t\t\t\tlist_del(\u0026link-\u003elist);\n 162:\t\t\t\tsk_psock_free_link(link);\n 163:\t\t\t\tbreak;\n 164:\t\t\t}\n 165:\t\t}\n 166:\t\tspin_unlock_bh(\u0026psock-\u003elink_lock);\n 167:\t\tif (!strp_stop \u0026\u0026 !verdict_stop)\n 168:\t\t\treturn;\n 169:\t\n 170:\t\twrite_lock_bh(\u0026sk-\u003esk_callback_lock);\n 171:\t\tif (psock-\u003esaved_data_ready) {\n 172:\t\t\tif (strp_stop)\n 173:\t\t\t\tsk_psock_stop_strp(sk, psock);\n 174:\t\t\tif (verdict_stop)\n 175:\t\t\t\tsk_psock_stop_verdict(sk, psock);\n 176:\t\n 177:\t\t\tif (psock-\u003epsock_update_sk_prot)\n 178:\t\t\t\tpsock-\u003epsock_update_sk_prot(sk, psock, false);\n 179:\t\t}\n 180:\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n 181:\t}\n 182:\t\n 183:\tstatic void sock_map_unref(struct sock *sk, void *link_raw)\n 184:\t{\n 185:\t\tstruct sk_psock *psock = sk_psock(sk);\n 186:\t\n 187:\t\tif (likely(psock)) {\n 188:\t\t\tsock_map_del_link(sk, psock, link_raw);\n 189:\t\t\tsk_psock_put(sk, psock);\n"
} |
| 37/3 | 2026/10/31 13:02 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 6466 output: 37 thoughts: 23 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Diving into the `sock_map_link` Function** Okay, time to dig into the details. I need to understand how this is working, so let's start by examining the `sock_map_link` function. I'm going to head straight over to `net/core/sock_map.c`. That's where I expect to find the core logic for managing the socket maps and how connections get linked. I'm particularly interested in seeing the underlying data structures and the locking strategy. I'm assuming that it involves something more intricate than a simple hash map, maybe something that is lock-free, or uses a sophisticated rcu mechanism. I need to understand how the linking works, which means looking at the data structures for how the various sockets are tracked, and how the interaction with other parts of the networking stack works. And, of course, I'll pay close attention to the error handling. I need to assess how it handles concurrency and potential race conditions, because I know that is always a major concern. |
| 38/3 | 2026/10/31 13:02 | tool | read-file |
0mArgs:{
"File": "net/core/sock_map.c",
"FirstLine": 275,
"LineCount": 60
}Results: {
"Contents": " 275:\t\t\t (skb_verdict \u0026\u0026 READ_ONCE(psock-\u003eprogs.stream_verdict)) ||\n 276:\t\t\t (stream_verdict \u0026\u0026 READ_ONCE(psock-\u003eprogs.skb_verdict)) ||\n 277:\t\t\t (stream_verdict \u0026\u0026 READ_ONCE(psock-\u003eprogs.stream_verdict))) {\n 278:\t\t\t\tsk_psock_put(sk, psock);\n 279:\t\t\t\tret = -EBUSY;\n 280:\t\t\t\tgoto out_progs;\n 281:\t\t\t}\n 282:\t\t} else {\n 283:\t\t\tpsock = sk_psock_init(sk, map-\u003enuma_node);\n 284:\t\t\tif (IS_ERR(psock)) {\n 285:\t\t\t\tret = PTR_ERR(psock);\n 286:\t\t\t\tgoto out_progs;\n 287:\t\t\t}\n 288:\t\t}\n 289:\t\n 290:\t\twrite_lock_bh(\u0026sk-\u003esk_callback_lock);\n 291:\t\tif (msg_parser)\n 292:\t\t\tpsock_set_prog(\u0026psock-\u003eprogs.msg_parser, msg_parser);\n 293:\t\tif (stream_parser)\n 294:\t\t\tpsock_set_prog(\u0026psock-\u003eprogs.stream_parser, stream_parser);\n 295:\t\tif (stream_verdict)\n 296:\t\t\tpsock_set_prog(\u0026psock-\u003eprogs.stream_verdict, stream_verdict);\n 297:\t\tif (skb_verdict)\n 298:\t\t\tpsock_set_prog(\u0026psock-\u003eprogs.skb_verdict, skb_verdict);\n 299:\t\n 300:\t\t/* msg_* and stream_* programs references tracked in psock after this\n 301:\t\t * point. Reference dec and cleanup will occur through psock destructor\n 302:\t\t */\n 303:\t\tret = sock_map_init_proto(sk, psock);\n 304:\t\tif (ret \u003c 0) {\n 305:\t\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n 306:\t\t\tsk_psock_put(sk, psock);\n 307:\t\t\tgoto out;\n 308:\t\t}\n 309:\t\n 310:\t\tif (stream_parser \u0026\u0026 stream_verdict \u0026\u0026 !psock-\u003esaved_data_ready) {\n 311:\t\t\tif (sk_is_tcp(sk))\n 312:\t\t\t\tret = sk_psock_init_strp(sk, psock);\n 313:\t\t\telse\n 314:\t\t\t\tret = -EOPNOTSUPP;\n 315:\t\t\tif (ret) {\n 316:\t\t\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n 317:\t\t\t\tsk_psock_put(sk, psock);\n 318:\t\t\t\tgoto out;\n 319:\t\t\t}\n 320:\t\t\tsk_psock_start_strp(sk, psock);\n 321:\t\t} else if (!stream_parser \u0026\u0026 stream_verdict \u0026\u0026 !psock-\u003esaved_data_ready) {\n 322:\t\t\tsk_psock_start_verdict(sk,psock);\n 323:\t\t} else if (!stream_verdict \u0026\u0026 skb_verdict \u0026\u0026 !psock-\u003esaved_data_ready) {\n 324:\t\t\tsk_psock_start_verdict(sk, psock);\n 325:\t\t}\n 326:\t\twrite_unlock_bh(\u0026sk-\u003esk_callback_lock);\n 327:\t\treturn 0;\n 328:\tout_progs:\n 329:\t\tif (skb_verdict)\n 330:\t\t\tbpf_prog_put(skb_verdict);\n 331:\tout_put_msg_parser:\n 332:\t\tif (msg_parser)\n 333:\t\t\tbpf_prog_put(msg_parser);\n 334:\tout_put_stream_parser:\n"
} |
| 39/3 | 2026/10/31 13:02 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 7822 output: 171 thoughts: 1145 Thoughts: **Analyzing the Sockmap Concurrency Fix** Okay, let's dive into this commit. My initial thought is to understand what concurrency issue this patch is addressing within the sockmap implementation. I'm focusing on the interaction between map update and delete operations, especially when programs are attached. I've reviewed the code and the commit message and, as I suspected, this revolves around a race condition. The selftest `test_update_delete_with_prog` is particularly illuminating. It highlights the core problem: one thread inserting a socket with a verdict program while another thread deletes the same entry. The expected error codes (EBUSY, EINVAL, ENOENT) signal the race. The crux of the issue lies in `sock_map_del_link`. The previous implementation had a problematic check for `psock->saved_data_ready` *within* the loop, under `psock->link_lock`, *before* setting `strp_stop` or `verdict_stop`. This meant, if `sock_map_link` was running concurrently, or `psock->saved_data_ready` hadn't been initialized yet, the stop signals would remain `false`, preventing the correct cleanup and restoration of the protocol. The fix now moves the `write_lock_bh(&sk->sk_callback_lock)` earlier in `sock_map_link` to cover setting `progs` and `sock_map_init_proto`. It also adds `READ_ONCE(sk->sk_prot)` to protect against data races on `sk->sk_prot`. These changes suggest a focus on ensuring proper locking and ordering, which is the correct approach to addressing this type of concurrency issue. Now, let's consider potential KMSAN implications. My first check is for uninitialized memory issues. I'm looking for: 1. Kernel structures sent to user space where uninitialized fields could be leaked. Not present here. 2. Conditional logic that depends on potentially uninitialized variables. `strp_stop` and `verdict_stop` are initialized to false. `psock->saved_data_ready` is initialized on psock initialization, and `READ_ONCE(sk->sk_prot)` reads a pointer to the protocol which is always initialized. 3. New allocations of complex data structures with uninitialized fields. No new allocations. 4. Bounds checks or logic that could lead to uninitialized bytes being accessed. No buffer manipulation here. Essentially, this patch is *not* touching anything that would cause KMSAN to flag uninitialized reads or leaks. It's solely focused on fixing a concurrency issue through better locking and synchronization. Let me re-emphasize the race condition fixes: These synchronization issues can lead to use-after-free, concurrent access (data races), or invalid state transitions, which are monitored by KASAN and LOCKDEP. KMSAN, however, is designed to detect reads from uninitialized memory (stack, heap, or page allocations) and leaks of uninitialized kernel data to userspace, which this patch does not introduce or modify. Therefore, NeedsKMSAN must be false. I'm confident in my analysis. I think we're ready to proceed with `set-results`. |
| 40/3 | 2026/10/31 13:02 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch addresses race conditions and synchronization issues in sockmap when concurrently inserting and deleting sockets with attached verdict/parser BPF programs (fixing data races on sk-\u003esk_prot via READ_ONCE and ensuring proper locking via sk_callback_lock during link removal and protocol initialization). \n\nThese changes address concurrency and state management bugs, which fall under the domain of KASAN, LOCKDEP, and KCSAN (e.g., use-after-free, data races, deadlocks). The patch does not introduce any new allocations, does not modify any buffers or copy_to_user operations, and does not read or expose uninitialized memory. Therefore, dedicated KMSAN fuzzing is not required.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch addresses race conditions and synchronization issues in sockmap when concurrently inserting and deleting sockets with attached verdict/parser BPF programs (fixing data races on sk-\u003esk_prot via READ_ONCE and ensuring proper locking via sk_callback_lock during link removal and protocol initialization). \n\nThese changes address concurrency and state management bugs, which fall under the domain of KASAN, LOCKDEP, and KCSAN (e.g., use-after-free, data races, deadlocks). The patch does not introduce any new allocations, does not modify any buffers or copy_to_user operations, and does not read or expose uninitialized memory. 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) |
|---|