| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/11/01 14:16 | flow | patch-triage |
5mArgs:null Results: {
"EnableConfigs": [
"IPV6",
"IPV6_SEG6_LWTUNNEL",
"IPV6_SEG6_BPF"
],
"FocusSymbols": [
"ipv6_srh_rcv",
"seg6_update_csum",
"ipv6_rthdr_rcv",
"seg6_do_srh",
"seg6_input",
"seg6_output",
"advance_nextseg",
"seg6_next_csid_advance_arg",
"input_action_end_bpf",
"seg6_local_input"
],
"KMSANReasoning": "The patch series addresses CHECKSUM_COMPLETE maintenance and checksum update formulas in IPv6 Segment Routing (SRv6). Specifically:\n1. It corrects the math in `update_csum_diff4` and `update_csum_diff16` by removing incorrect 1's complement inversions in `csum_partial`.\n2. It adds differential checksum updates (`update_csum_diff4` / `update_csum_diff16`) when modifying hop limit or destination addresses in `ipv6_srh_rcv`, `advance_nextseg`, and `seg6_next_csid_advance_arg`.\n3. It switches `skb_push` to `skb_push_rcsum` in `seg6_iptunnel.c` and calls `skb_checksum_complete_unset(skb)` in `seg6_local.c` after End.BPF actions.\n4. It adds selftests for CHECKSUM_COMPLETE validation under SRv6.\n\nNone of these changes introduce or expose uninitialized memory risks:\n- All new stack variables (`old`, `diff`) are immediately and fully initialized before read.\n- Packet accesses operate on verified, existing packet header buffers.\n- No data structures or padding bytes are copied to userspace or leaked.\n- Control flow branching does not depend on uninitialized variables.\n\nAny potential packet buffer boundary issues or memory corruptions are within the scope of standard KASAN/network stack checks. Thus, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false,
"Reasoning": "The patch series modifies checksum update logic for IPv6 Segment Routing (SRv6) when packets carry CHECKSUM_COMPLETE. Specifically, it corrects the complement arithmetic in update_csum_diff4() and update_csum_diff16(), adds missing checksum updates when updating the hop limit in ipv6_srh_rcv(), updates skb-\u003ecsum when advancing segments in advance_nextseg() and seg6_next_csid_advance_arg(), uses skb_push_rcsum() in seg6_do_srh(), and clears CHECKSUM_COMPLETE in input_action_end_bpf(). This code is part of core IPv6 routing and lightweight tunnel encapsulation, fully reachable in standard virtualized QEMU/GCE environments via standard IPv6 sockets, loopback/veth interfaces, and netlink route encapsulation configs. Fuzzing is warranted to detect regressions, improper checksum handling, or packet corruption.",
"WorthFuzzing": true
} |
| 1/1 | 2026/11/01 14:16 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 7ed98965b2ad5b10d241ec5fc25b58517ece0a7e\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sun Nov 1 14:16:31 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/include/net/seg6.h b/include/net/seg6.h\nindex 82b3fbbcbb9351..01d8034e48fcab 100644\n--- a/include/net/seg6.h\n+++ b/include/net/seg6.h\n@@ -19,7 +19,7 @@ static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,\n {\n \t__be32 diff[] = { ~from, to };\n \n-\tskb-\u003ecsum = ~csum_partial((char *)diff, sizeof(diff), ~skb-\u003ecsum);\n+\tskb-\u003ecsum = csum_partial(diff, sizeof(diff), skb-\u003ecsum);\n }\n \n static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,\n@@ -30,7 +30,7 @@ static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,\n \t\tto[0], to[1], to[2], to[3],\n \t};\n \n-\tskb-\u003ecsum = ~csum_partial((char *)diff, sizeof(diff), ~skb-\u003ecsum);\n+\tskb-\u003ecsum = csum_partial(diff, sizeof(diff), skb-\u003ecsum);\n }\n \n struct seg6_pernet_data {\ndiff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c\nindex 96c8402a27a549..9d3ba310065a1b 100644\n--- a/net/ipv6/exthdrs.c\n+++ b/net/ipv6/exthdrs.c\n@@ -460,6 +460,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n \t}\n \n \tif (skb_dst_dev(skb)-\u003eflags \u0026 IFF_LOOPBACK) {\n+\t\t/* payload_len, nexthdr and hop_limit */\n+\t\t__be32 *hlim_word = (__be32 *)ipv6_hdr(skb) + 1;\n+\t\t__be32 old;\n+\n \t\tif (ipv6_hdr(skb)-\u003ehop_limit \u003c= 1) {\n \t\t\t__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);\n \t\t\ticmpv6_send(skb, ICMPV6_TIME_EXCEED,\n@@ -467,8 +471,12 @@ static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n \t\t\tkfree_skb_reason(skb, SKB_DROP_REASON_IP_TTL_EXCEEDED);\n \t\t\treturn -1;\n \t\t}\n+\t\told = *hlim_word;\n \t\tipv6_hdr(skb)-\u003ehop_limit--;\n \n+\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\n+\t\t\tupdate_csum_diff4(skb, old, *hlim_word);\n+\n \t\tskb_pull(skb, skb_transport_offset(skb));\n \t\tgoto looped_back;\n \t}\ndiff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c\nindex 0d39a38a5dd299..3821d8e1409e71 100644\n--- a/net/ipv6/seg6_iptunnel.c\n+++ b/net/ipv6/seg6_iptunnel.c\n@@ -456,7 +456,7 @@ static int seg6_do_srh(struct sk_buff *skb, struct dst_entry *cache_dst)\n \t\t\treturn err;\n \n \t\tskb_mac_header_rebuild(skb);\n-\t\tskb_push(skb, skb-\u003emac_len);\n+\t\tskb_push_rcsum(skb, skb-\u003emac_len);\n \n \t\tif (tinfo-\u003emode == SEG6_IPTUN_MODE_L2ENCAP)\n \t\t\terr = __seg6_do_srh_encap(skb, tinfo-\u003esrh,\ndiff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c\nindex 0c3d1be7f1299e..3045a351f4e92f 100644\n--- a/net/ipv6/seg6_local.c\n+++ b/net/ipv6/seg6_local.c\n@@ -291,7 +291,9 @@ static struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,\n \t\t\t\t\t struct ipv6_sr_hdr *srh,\n \t\t\t\t\t enum skb_drop_reason *reason)\n {\n+\tstruct in6_addr *daddr;\n \tstruct in6_addr *addr;\n+\t__be32 old;\n \tint srhoff;\n \tint wlen;\n \n@@ -309,10 +311,19 @@ static struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,\n \n \t/* skb_ensure_writable() may change skb pointers; evaluate srh again */\n \tsrh = (struct ipv6_sr_hdr *)(skb-\u003edata + srhoff);\n+\tdaddr = \u0026ipv6_hdr(skb)-\u003edaddr;\n+\t/* nexthdr, hdrlen, type and segments_left */\n+\told = *(__be32 *)srh;\n \n \tsrh-\u003esegments_left--;\n \taddr = srh-\u003esegments + srh-\u003esegments_left;\n-\tipv6_hdr(skb)-\u003edaddr = *addr;\n+\n+\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE) {\n+\t\tupdate_csum_diff4(skb, old, *(__be32 *)srh);\n+\t\tupdate_csum_diff16(skb, (__be32 *)daddr, (__be32 *)addr);\n+\t}\n+\n+\t*daddr = *addr;\n \n \treturn srh;\n }\n@@ -427,11 +438,13 @@ seg6_next_csid_advance_arg(struct sk_buff *skb,\n \t__u8 fnc_octects = seg6_flv_lcnode_func_octects(finfo);\n \t__u8 blk_octects = seg6_flv_lcblock_octects(finfo);\n \tstruct in6_addr *addr;\n+\tstruct in6_addr old;\n \n \tif (unlikely(skb_ensure_writable(skb, sizeof(struct ipv6hdr))))\n \t\treturn SKB_DROP_REASON_NOMEM;\n \n \taddr = \u0026ipv6_hdr(skb)-\u003edaddr;\n+\told = *addr;\n \n \t/* advance DA.Argument */\n \tmemmove(\u0026addr-\u003es6_addr[blk_octects],\n@@ -440,6 +453,9 @@ seg6_next_csid_advance_arg(struct sk_buff *skb,\n \n \tmemset(\u0026addr-\u003es6_addr[16 - fnc_octects], 0x00, fnc_octects);\n \n+\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\n+\t\tupdate_csum_diff16(skb, (__be32 *)\u0026old, (__be32 *)addr);\n+\n \treturn SKB_NOT_DROPPED_YET;\n }\n \n@@ -1566,6 +1582,12 @@ static int input_action_end_bpf(struct sk_buff *skb,\n \t\tgoto drop;\n \t}\n \n+\t/* The program may have changed the packet and seg6_bpf_has_valid_srh()\n+\t * may rewrite the SRH Hdr Ext Len below.\n+\t * skb-\u003ecsum may then no longer be the checksum of the full packet.\n+\t */\n+\tskb_checksum_complete_unset(skb);\n+\n \tif (srh_state-\u003esrh \u0026\u0026 !seg6_bpf_has_valid_srh(skb))\n \t\tgoto drop;\n \tlocal_unlock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\ndiff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile\nindex df215e1a62621b..16e9fbf889fd1b 100644\n--- a/tools/testing/selftests/net/Makefile\n+++ b/tools/testing/selftests/net/Makefile\n@@ -92,6 +92,7 @@ TEST_PROGS := \\\n \trxtimestamp.sh \\\n \tsctp_vrf.sh \\\n \tskf_net_off.sh \\\n+\tsrv6_csum_complete_test.sh \\\n \tsrv6_encap_lookup_l3vpn_test.sh \\\n \tsrv6_end_dt46_l3vpn_test.sh \\\n \tsrv6_end_dt4_l3vpn_test.sh \\\ndiff --git a/tools/testing/selftests/net/srv6_csum_complete.bpf.c b/tools/testing/selftests/net/srv6_csum_complete.bpf.c\nnew file mode 100644\nindex 00000000000000..281b0361f97693\n--- /dev/null\n+++ b/tools/testing/selftests/net/srv6_csum_complete.bpf.c\n@@ -0,0 +1,65 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Author: Andrea Mayer \u003candrea.mayer@uniroma2.it\u003e\n+ */\n+#include \u003cstddef.h\u003e\n+#include \u003clinux/bpf.h\u003e\n+#include \u003clinux/if_ether.h\u003e\n+#include \u003clinux/ipv6.h\u003e\n+#include \u003clinux/pkt_cls.h\u003e\n+#include \u003clinux/seg6.h\u003e\n+#include \u003cbpf/bpf_helpers.h\u003e\n+#include \u003cbpf/bpf_endian.h\u003e\n+\n+/* On the tc ingress, skb-\u003edata points to the Ethernet header */\n+#define TC_IPV6_OFF\t\tETH_HLEN\n+/* Byte with the lowest 8 bits of the Flow Label */\n+#define TC_FLOW_LBL_OFF\t\t(TC_IPV6_OFF + \\\n+\t\t\t\t offsetof(struct ipv6hdr, flow_lbl) + 2)\n+/* Bit of the Flow Label changed in the control datagram */\n+#define CTRL_FLOW_LBL_BIT\t0x01\n+\n+/* In End.BPF, skb-\u003edata points to the IPv6 header, followed by the SRH */\n+#define SRH_TAG_OFF\t\t(sizeof(struct ipv6hdr) + \\\n+\t\t\t\t offsetof(struct ipv6_sr_hdr, tag))\n+/* Value written in the SRH Tag, test case (vi) */\n+#define SRH_TAG\t\t\t0x1234\n+\n+/* Test case (v) of srv6_csum_complete_test.sh. The program runs on the tc\n+ * ingress of rt, after the ct action, only for the control datagram. It\n+ * changes one bit of the Flow Label, without updating the receive checksum\n+ * (skb-\u003ecsum). The Flow Label is not part of the UDP checksum, which stays\n+ * correct. UDP must drop the datagram because the receive checksum no longer\n+ * matches the packet.\n+ */\n+SEC(\"tc\")\n+int ctrl_flow_label(struct __sk_buff *skb)\n+{\n+\t__u8 lbl;\n+\n+\t/* Read the byte with the lowest 8 bits of the Flow Label */\n+\tif (bpf_skb_load_bytes(skb, TC_FLOW_LBL_OFF, \u0026lbl, sizeof(lbl)))\n+\t\treturn TC_ACT_SHOT;\n+\n+\tlbl ^= CTRL_FLOW_LBL_BIT;\n+\n+\t/* Write the byte back, flags 0 do not update the receive checksum */\n+\tif (bpf_skb_store_bytes(skb, TC_FLOW_LBL_OFF, \u0026lbl, sizeof(lbl), 0))\n+\t\treturn TC_ACT_SHOT;\n+\n+\treturn TC_ACT_OK;\n+}\n+\n+/* Test case (vi), the End.BPF program writes the SRH Tag */\n+SEC(\"lwt_seg6local\")\n+int end_bpf_tag(struct __sk_buff *skb)\n+{\n+\t__u16 tag = bpf_htons(SRH_TAG);\n+\n+\tif (bpf_lwt_seg6_store_bytes(skb, SRH_TAG_OFF, \u0026tag, sizeof(tag)))\n+\t\treturn BPF_DROP;\n+\n+\treturn BPF_OK;\n+}\n+\n+char _license[] SEC(\"license\") = \"GPL\";\ndiff --git a/tools/testing/selftests/net/srv6_csum_complete_test.sh b/tools/testing/selftests/net/srv6_csum_complete_test.sh\nnew file mode 100755\nindex 00000000000000..0b9c929313620f\n--- /dev/null\n+++ b/tools/testing/selftests/net/srv6_csum_complete_test.sh\n@@ -0,0 +1,642 @@\n+#!/bin/bash\n+# SPDX-License-Identifier: GPL-2.0\n+#\n+# author: Andrea Mayer \u003candrea.mayer@uniroma2.it\u003e\n+\n+# This test checks the receive checksum of an SRv6 packet that is processed and\n+# then delivered on the same node. The node changes the Segments Left and the\n+# destination address of the packet, and can also change the Hop Limit.\n+#\n+# The receive checksum (CHECKSUM_COMPLETE) is the checksum of the whole packet,\n+# kept with the received packet. When the node changes the packet, it must also\n+# update this sum, or discard it.\n+#\n+# Network topology\n+# ================\n+#\n+# The test uses a host (hs) and a router (rt) connected through a veth pair. In\n+# each test case, hs sends one UDP datagram to an address of rt.\n+#\n+# +--------------------+ +--------------------------+\n+# | hs | | rt |\n+# | | | |\n+# | veth-hs +--------------------+ veth-rt |\n+# | fd00::1/64 | | fd00::2/64 |\n+# | tx checksum off | | tc ingress: ct, then bpf |\n+# +--------------------+ | |\n+# | lo: fc00::1 ... fc00::4 |\n+# | cafe::1 ... cafe::6 |\n+# +--------------------------+\n+#\n+# Receive checksum\n+# ================\n+#\n+# veth does not provide the receive checksum. For this reason, a tc ct action\n+# runs on the ingress of rt. The ct action checks the UDP checksum, and in this\n+# way computes the receive checksum in software. If the receive checksum does\n+# not match the packet, UDP drops the datagram as a checksum error.\n+#\n+# The ct action computes the receive checksum when hs computes the UDP checksum\n+# in software, before the datagram crosses the veth. For this reason, hs has\n+# transmit checksumming off.\n+#\n+# Each datagram is longer than 76 bytes, UDP header included. For datagrams of\n+# 76 bytes or less, UDP computes the checksum again from the packet, and accepts\n+# the datagram even with a wrong receive checksum.\n+#\n+# UDP counters\n+# ============\n+#\n+# Each datagram goes to a port with no listener. If the UDP checksum check\n+# passes, rt counts the datagram in Udp6NoPorts. If it fails, rt counts it in\n+# Udp6InCsumErrors.\n+#\n+# Control datagram\n+# ================\n+#\n+# A control datagram checks that the test detects a wrong receive checksum after\n+# a change to the packet. After the ct action, a tc bpf filter on rt changes one\n+# bit of its Flow Label, without updating the receive checksum. The Flow Label\n+# is not part of the UDP checksum, which stays correct. UDP must drop the\n+# datagram because the receive checksum no longer matches the packet. If UDP\n+# accepts it, the test cannot detect a wrong receive checksum. The other test\n+# cases may then pass even when their receive checksum is wrong, and for this\n+# reason the test fails.\n+#\n+# Routes and tc filters\n+# =====================\n+#\n+# hs: encap (main table)\n+# +---------+-----------------------------------------------------+\n+# | dst | action |\n+# +---------+-----------------------------------------------------+\n+# | cafe::1 | via fd00::2 |\n+# | cafe::2 | encap seg6 mode inline segs fc00::1,fc00::2 |\n+# | cafe::3 | encap seg6 mode inline segs fcbb:0:0200:: |\n+# | cafe::4 | encap seg6 mode inline segs fcbb:0:0100:0200:: |\n+# | cafe::5 | encap seg6 mode inline segs fc00::3,fc00::4 |\n+# | cafe::6 | encap seg6 mode inline segs fc00::b0,fcbb:0:0200:: |\n+# +---------+-----------------------------------------------------+\n+#\n+# rt: SRv6 behaviors (main table)\n+# +------------------+------------------------------------------------+\n+# | SID | action |\n+# +------------------+------------------------------------------------+\n+# | fcbb:0:0100::/48 | End flavors next-csid lblen 32 nflen 16 |\n+# | fcbb:0:0200::/48 | End.B6.Encaps srh segs fc00::d6 |\n+# | fc00::d6 | End.DT6 table 255 (local) |\n+# | fc00::b0 | End.BPF, the program writes the SRH Tag |\n+# +------------------+------------------------------------------------+\n+#\n+# rt: tc ingress of veth-rt\n+# +-------+------+---------------------------------------------------+\n+# | chain | prio | filter |\n+# +-------+------+---------------------------------------------------+\n+# | 0 | 1 | matchall, action ct, goto chain 1 |\n+# | 1 | 1 | flower dst_ip fc00::3, goto chain 2 |\n+# | 2 | 1 | bpf, changes one bit of the Flow Label |\n+# +-------+------+---------------------------------------------------+\n+#\n+# Test cases\n+# ==========\n+#\n+# hs applies the SRv6 Policies in inline mode, i.e. the original destination\n+# becomes the last SID of the SID List.\n+#\n+# i) cafe::1, no SRH, used as a reference.\n+#\n+# ii) cafe::2, SID List=fc00::1,fc00::2,cafe::2\n+# fc00::1 and fc00::2 are addresses of rt. rt processes the SRH twice. Each\n+# time, it also decrements the Hop Limit.\n+#\n+# iii) cafe::3, SID List=fcbb:0:0200::,cafe::3\n+# End.B6.Encaps advances the SRH and adds an outer IPv6 header with an SRH.\n+# The outer header goes to the End.DT6 SID fc00::d6, which removes it.\n+#\n+# iv) cafe::4, SID List=fcbb:0:0100:0200::,cafe::4\n+# End with the NEXT-C-SID flavor changes the DA to the next C-SID,\n+# fcbb:0:0200::. Then the datagram follows the same path as in (iii).\n+#\n+# v) cafe::5, SID List=fc00::3,fc00::4,cafe::5, control.\n+# The tc flower filter matches the first segment, fc00::3, and the tc bpf\n+# filter changes the Flow Label. Then rt processes the SRH as in (ii).\n+#\n+# vi) cafe::6, SID List=fc00::b0,fcbb:0:0200::,cafe::6\n+# End.BPF writes the SRH Tag. Then the datagram follows the same path as in\n+# (iii).\n+#\n+# In the test case (v), the datagram is expected to be dropped as a checksum\n+# error. In all the other test cases, the datagram is expected to be delivered\n+# on rt.\n+\n+# shellcheck source=lib.sh\n+source lib.sh\n+\n+readonly IPv6_RT_NETWORK=fd00\n+readonly IPv6_DST_NETWORK=cafe\n+readonly SID_LOCATOR=fc00\n+readonly CSID_BLOCK=fcbb:0\n+readonly CSID_LBLEN=32\n+readonly CSID_NFLEN=16\n+readonly CSID_BLOCK_FUNC_LEN=$((CSID_LBLEN + CSID_NFLEN))\n+readonly B6_FUNC=0200\n+readonly CSID_FUNC=0100\n+readonly DT6_FUNC=d6\n+readonly BPF_FUNC=b0\n+readonly DUMMY_DEVNAME=dum0\n+readonly UDP_PORT=9\n+readonly UDP_PAYLOAD_LEN=200\n+readonly WAIT_TIMEOUT_SEC=5\n+\n+# destination of the control datagram on the veth, test case (v)\n+readonly CTRL_DST=\"${SID_LOCATOR}::3\"\n+# tc chain of the flower filter that selects the control datagram\n+readonly CTRL_CHAIN=1\n+# tc chain of the bpf filter that changes the Flow Label\n+readonly BPF_CHAIN=2\n+\n+readonly BPF_FILE=srv6_csum_complete.bpf.o\n+readonly BPF_TC_SEC=tc\n+readonly BPF_END_SEC=lwt_seg6local\n+\n+# return values of check_udp_delivery()\n+readonly UDP_DELIVERED=0\n+readonly UDP_LOST=1\n+readonly UDP_CSUM_ERROR=2\n+\n+SETUP_ERR=1\n+\n+ret=${ksft_skip}\n+nsuccess=0\n+nfail=0\n+\n+log_test()\n+{\n+\tlog_test_expected \"$1\" \"$2\" \"$3\"\n+}\n+\n+print_log_test_results()\n+{\n+\tprintf \"\\nTests passed: %3d\\n\" \"${nsuccess}\"\n+\tprintf \"Tests failed: %3d\\n\" \"${nfail}\"\n+\n+\t# when a test fails, the value of 'ret' is set to 1 (error code).\n+\t# Conversely, when all tests are passed successfully, the 'ret' value\n+\t# is set to 0 (success code).\n+\tif [ \"${ret}\" -ne 1 ]; then\n+\t\tret=0\n+\tfi\n+}\n+\n+log_section()\n+{\n+\techo\n+\techo \"################################################################################\"\n+\techo \"TEST SECTION: $*\"\n+\techo \"################################################################################\"\n+}\n+\n+cleanup()\n+{\n+\tcleanup_all_ns\n+\n+\t# check whether the setup phase was completed successfully or not. In\n+\t# case of an error during the setup phase of the testing environment,\n+\t# the selftest is considered as \"skipped\".\n+\tif [ \"${SETUP_ERR}\" -ne 0 ]; then\n+\t\techo \"SKIP: Setting up the testing environment failed\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\texit \"${ret}\"\n+}\n+\n+# add on hs the SRv6 Policy for cafe::\u003cid\u003e, in inline mode\n+# args:\n+# $1 - destination id\n+# $2 - segments, comma separated\n+set_hs_policy()\n+{\n+\tlocal dstid=\"$1\"\n+\tlocal segs=\"$2\"\n+\n+\tip -netns \"${NS_HS}\" -6 route add \"${IPv6_DST_NETWORK}::${dstid}/128\" \\\n+\t\tencap seg6 mode inline segs \"${segs}\" \\\n+\t\tvia \"${IPv6_RT_NETWORK}::2\" dev veth-hs\n+}\n+\n+setup_hs()\n+{\n+\tip -netns \"${NS_HS}\" link set veth-hs up\n+\tip -netns \"${NS_HS}\" addr add \"${IPv6_RT_NETWORK}::1/64\" \\\n+\t\tdev veth-hs nodad\n+\n+\t# with transmit checksumming on, conntrack on rt does not compute the\n+\t# receive checksum\n+\tip netns exec \"${NS_HS}\" ethtool -K veth-hs tx off \u003e/dev/null\n+\n+\t# routes to the SIDs, used after the SRH is inserted\n+\tip -netns \"${NS_HS}\" -6 route add \"${SID_LOCATOR}::/16\" \\\n+\t\tvia \"${IPv6_RT_NETWORK}::2\" dev veth-hs\n+\tip -netns \"${NS_HS}\" -6 route add \"${CSID_BLOCK}::/${CSID_LBLEN}\" \\\n+\t\tvia \"${IPv6_RT_NETWORK}::2\" dev veth-hs\n+\n+\t# test case (i), the reference, no SRH\n+\tip -netns \"${NS_HS}\" -6 route add \"${IPv6_DST_NETWORK}::1/128\" \\\n+\t\tvia \"${IPv6_RT_NETWORK}::2\" dev veth-hs\n+\n+\t# the SRv6 Policies of the test cases (ii) to (vi)\n+\tset_hs_policy 2 \"${SID_LOCATOR}::1,${SID_LOCATOR}::2\"\n+\tset_hs_policy 3 \"${CSID_BLOCK}:${B6_FUNC}::\"\n+\tset_hs_policy 4 \"${CSID_BLOCK}:${CSID_FUNC}:${B6_FUNC}::\"\n+\tset_hs_policy 5 \"${SID_LOCATOR}::3,${SID_LOCATOR}::4\"\n+\tset_hs_policy 6 \"${SID_LOCATOR}::${BPF_FUNC},${CSID_BLOCK}:${B6_FUNC}::\"\n+}\n+\n+setup_rt()\n+{\n+\tlocal dstid\n+\tlocal dev\n+\n+\tip -netns \"${NS_RT}\" link set veth-rt up\n+\tip -netns \"${NS_RT}\" addr add \"${IPv6_RT_NETWORK}::2/64\" \\\n+\t\tdev veth-rt nodad\n+\n+\t# local segments of the test case (ii)\n+\tip -netns \"${NS_RT}\" addr add \"${SID_LOCATOR}::1/128\" dev lo nodad\n+\tip -netns \"${NS_RT}\" addr add \"${SID_LOCATOR}::2/128\" dev lo nodad\n+\t# local segments of the test case (v)\n+\tip -netns \"${NS_RT}\" addr add \"${SID_LOCATOR}::3/128\" dev lo nodad\n+\tip -netns \"${NS_RT}\" addr add \"${SID_LOCATOR}::4/128\" dev lo nodad\n+\tfor dstid in 1 2 3 4 5 6; do\n+\t\tip -netns \"${NS_RT}\" addr add \\\n+\t\t\t\"${IPv6_DST_NETWORK}::${dstid}/128\" dev lo nodad\n+\tdone\n+\n+\tfor dev in all veth-rt lo; do\n+\t\tip netns exec \"${NS_RT}\" sysctl -wq \\\n+\t\t\tnet.ipv6.conf.\"${dev}\".seg6_enabled=1\n+\tdone\n+\n+\t# SRv6 behaviors used by the test cases (iii), (iv) and (vi)\n+\tip -netns \"${NS_RT}\" -6 route \\\n+\t\tadd \"${CSID_BLOCK}:${CSID_FUNC}::/${CSID_BLOCK_FUNC_LEN}\" \\\n+\t\tencap seg6local action End flavors next-csid \\\n+\t\tlblen \"${CSID_LBLEN}\" nflen \"${CSID_NFLEN}\" dev veth-rt\n+\tip -netns \"${NS_RT}\" -6 route \\\n+\t\tadd \"${CSID_BLOCK}:${B6_FUNC}::/${CSID_BLOCK_FUNC_LEN}\" \\\n+\t\tencap seg6local action End.B6.Encaps \\\n+\t\tsrh segs \"${SID_LOCATOR}::${DT6_FUNC}\" dev veth-rt\n+\tip -netns \"${NS_RT}\" -6 route add \"${SID_LOCATOR}::${DT6_FUNC}/128\" \\\n+\t\tencap seg6local action End.DT6 table 255 dev veth-rt\n+\tip -netns \"${NS_RT}\" -6 route add \"${SID_LOCATOR}::${BPF_FUNC}/128\" \\\n+\t\tencap seg6local action End.BPF endpoint obj \"${BPF_FILE}\" \\\n+\t\tsec \"${BPF_END_SEC}\" dev veth-rt\n+\n+\ttc -netns \"${NS_RT}\" qdisc add dev veth-rt clsact\n+\t# the bpf filter changes the Flow Label of the control datagram\n+\ttc -netns \"${NS_RT}\" filter add dev veth-rt ingress \\\n+\t\tchain \"${BPF_CHAIN}\" prio 1 protocol ipv6 \\\n+\t\tbpf object-file \"${BPF_FILE}\" section \"${BPF_TC_SEC}\" \\\n+\t\tdirect-action\n+\t# the control datagram goes to the bpf filter\n+\ttc -netns \"${NS_RT}\" filter add dev veth-rt ingress \\\n+\t\tchain \"${CTRL_CHAIN}\" prio 1 protocol ipv6 \\\n+\t\tflower dst_ip \"${CTRL_DST}\" \\\n+\t\taction goto chain \"${BPF_CHAIN}\"\n+\t# every packet goes to the ct action, which computes the receive\n+\t# checksum, then to the chain of the flower filter\n+\ttc -netns \"${NS_RT}\" filter add dev veth-rt ingress prio 1 \\\n+\t\tprotocol ipv6 matchall \\\n+\t\taction ct pipe action goto chain \"${CTRL_CHAIN}\"\n+\tip netns exec \"${NS_RT}\" sysctl -wq \\\n+\t\tnet.netfilter.nf_conntrack_checksum=1\n+}\n+\n+setup()\n+{\n+\tsetup_ns NS_HS NS_RT\n+\n+\tip -netns \"${NS_HS}\" link add veth-hs type veth \\\n+\t\tpeer name veth-rt netns \"${NS_RT}\"\n+\n+\tsetup_hs\n+\tsetup_rt\n+\n+\t# testing environment was set up successfully\n+\tSETUP_ERR=0\n+}\n+\n+# print the value of a counter of rt in /proc/net/snmp6\n+# args:\n+# $1 - counter name in /proc/net/snmp6\n+get_rt_udp6_counter()\n+{\n+\tlocal name=\"$1\"\n+\n+\tip netns exec \"${NS_RT}\" cat /proc/net/snmp6 | \\\n+\t\tawk -v k=\"${name}\" '$1 == k { print $2 }'\n+}\n+\n+# number of datagrams that UDP on rt counted in Udp6NoPorts or Udp6InCsumErrors\n+get_rt_udp6_received()\n+{\n+\techo $(( $(get_rt_udp6_counter Udp6NoPorts) +\n+\t\t $(get_rt_udp6_counter Udp6InCsumErrors) ))\n+}\n+\n+check_hs_rt_connectivity()\n+{\n+\tip netns exec \"${NS_HS}\" ping -c 1 -W 1 \"${IPv6_RT_NETWORK}::2\" \\\n+\t\t\u003e/dev/null 2\u003e\u00261\n+}\n+\n+check_and_log_hs_rt_connectivity()\n+{\n+\tcheck_hs_rt_connectivity\n+\tlog_test $? 0 \"Connectivity: hs -\u003e rt\"\n+}\n+\n+connectivity_tests()\n+{\n+\tlog_section \"IPv6 connectivity test between host and router\"\n+\n+\tcheck_and_log_hs_rt_connectivity\n+}\n+\n+# Send one UDP datagram from hs to a port with no listener on rt.\n+# args:\n+# $1 - destination id\n+# return:\n+# - UDP_DELIVERED if rt counts the datagram as delivered\n+# - UDP_CSUM_ERROR if rt drops it for a bad checksum\n+# - UDP_LOST if the datagram cannot be sent, or if it does not arrive\n+check_udp_delivery()\n+{\n+\tlocal dstid=\"$1\"\n+\tlocal noports\n+\tlocal payload\n+\tlocal errors\n+\tlocal recv\n+\tlocal dst\n+\n+\tdst=\"${IPv6_DST_NETWORK}::${dstid}\"\n+\tnoports=\"$(get_rt_udp6_counter Udp6NoPorts)\"\n+\terrors=\"$(get_rt_udp6_counter Udp6InCsumErrors)\"\n+\trecv=$((noports + errors))\n+\tpayload=\"$(printf '%*s' \"${UDP_PAYLOAD_LEN}\" '')\"\n+\n+\t# send the datagram with the /dev/udp redirection of bash\n+\tif ! ip netns exec \"${NS_HS}\" bash -c \"printf '%s' '${payload}' \u003e \\\n+\t\t\t/dev/udp/${dst}/${UDP_PORT}\"; then\n+\t\treturn \"${UDP_LOST}\"\n+\tfi\n+\n+\t# wait until rt counts the datagram in Udp6NoPorts or Udp6InCsumErrors\n+\tif ! slowwait \"${WAIT_TIMEOUT_SEC}\" until_counter_is \\\n+\t\t\t\"\u003e= $((recv + 1))\" get_rt_udp6_received \u003e/dev/null; then\n+\t\treturn \"${UDP_LOST}\"\n+\tfi\n+\n+\tif [ \"$(get_rt_udp6_counter Udp6InCsumErrors)\" -ne \"${errors}\" ]; then\n+\t\treturn \"${UDP_CSUM_ERROR}\"\n+\tfi\n+\n+\tif [ \"$(get_rt_udp6_counter Udp6NoPorts)\" -ne \"$((noports + 1))\" ]; then\n+\t\treturn \"${UDP_LOST}\"\n+\tfi\n+\n+\treturn \"${UDP_DELIVERED}\"\n+}\n+\n+# check the delivery of a datagram to cafe::\u003cid\u003e and log the result\n+# args:\n+# $1 - destination id\n+# $2 - expected return value of check_udp_delivery()\n+# $3 - description of the path\n+check_and_log_udp_delivery()\n+{\n+\tlocal dstid=\"$1\"\n+\tlocal expected=\"$2\"\n+\tlocal desc=\"$3\"\n+\n+\tcheck_udp_delivery \"${dstid}\"\n+\tlog_test $? \"${expected}\" \\\n+\t\t\"UDP: hs -\u003e ${IPv6_DST_NETWORK}::${dstid} (${desc})\"\n+}\n+\n+udp_delivery_tests()\n+{\n+\tlog_section \"UDP delivery test with CHECKSUM_COMPLETE\"\n+\n+\tcheck_and_log_udp_delivery 1 \"${UDP_DELIVERED}\" \"no SRH\"\n+\tcheck_and_log_udp_delivery 2 \"${UDP_DELIVERED}\" \"SRH, local segments\"\n+\tcheck_and_log_udp_delivery 3 \"${UDP_DELIVERED}\" \"End.B6.Encaps, End.DT6\"\n+\tcheck_and_log_udp_delivery 4 \"${UDP_DELIVERED}\" \\\n+\t\t\"End next-csid, End.B6.Encaps, End.DT6\"\n+\tcheck_and_log_udp_delivery 5 \"${UDP_CSUM_ERROR}\" \"control, csum error\"\n+\tcheck_and_log_udp_delivery 6 \"${UDP_DELIVERED}\" \\\n+\t\t\"End.BPF, End.B6.Encaps, End.DT6\"\n+}\n+\n+test_command_or_ksft_skip()\n+{\n+\tlocal cmd=\"$1\"\n+\n+\tif [ ! -x \"$(command -v \"${cmd}\")\" ]; then\n+\t\techo \"SKIP: Could not run test without \\\"${cmd}\\\" tool\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+}\n+\n+test_dummy_dev_or_ksft_skip()\n+{\n+\tlocal test_netns\n+\n+\tsetup_ns test_netns\n+\n+\tmodprobe dummy \u0026\u003e/dev/null || true\n+\tif ! ip -netns \"${test_netns}\" link add \"${DUMMY_DEVNAME}\" \\\n+\t\t\ttype dummy; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: dummy dev not supported\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\tcleanup_ns \"${test_netns}\"\n+}\n+\n+test_iproute2_supp_or_ksft_skip()\n+{\n+\tif ! ip route help 2\u003e\u00261 | grep -qo next-csid; then\n+\t\techo \"SKIP: Missing SRv6 next-csid flavor support in iproute2\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+}\n+\n+test_kernel_supp_or_ksft_skip()\n+{\n+\tlocal test_netns\n+\n+\tsetup_ns test_netns\n+\n+\tip -netns \"${test_netns}\" link add \"${DUMMY_DEVNAME}\" type dummy\n+\tip -netns \"${test_netns}\" link set \"${DUMMY_DEVNAME}\" up\n+\n+\tif ! ip -netns \"${test_netns}\" -6 route \\\n+\t\t\tadd \"${CSID_BLOCK}::/${CSID_LBLEN}\" encap seg6local \\\n+\t\t\taction End flavors next-csid dev \"${DUMMY_DEVNAME}\" \\\n+\t\t\t2\u003e/dev/null; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: SRv6 next-csid flavor not supported\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\tcleanup_ns \"${test_netns}\"\n+}\n+\n+test_veth_tx_csum_off_or_ksft_skip()\n+{\n+\tlocal test_netns\n+\n+\tsetup_ns test_netns\n+\n+\tif ! ip -netns \"${test_netns}\" link add veth-t0 type veth \\\n+\t\t\tpeer name veth-t1 2\u003e/dev/null; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: veth dev not supported\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\t# setup_hs() turns off transmit checksumming on veth-hs. If it stays on,\n+\t# conntrack does not compute the receive checksum and the test cannot\n+\t# see the error.\n+\tip netns exec \"${test_netns}\" ethtool -K veth-t0 tx off \u003e/dev/null 2\u003e\u00261\n+\n+\tif ! ip netns exec \"${test_netns}\" ethtool -k veth-t0 | \\\n+\t\t\tgrep -q \"^tx-checksumming: off\"; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: Cannot turn off transmit checksumming on veth\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\tcleanup_ns \"${test_netns}\"\n+}\n+\n+test_bpf_file_or_ksft_skip()\n+{\n+\tif [ ! -f \"${BPF_FILE}\" ]; then\n+\t\techo \"SKIP: Missing ${BPF_FILE}, run 'make' first\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+}\n+\n+test_tc_or_ksft_skip()\n+{\n+\tlocal test_netns\n+\n+\tsetup_ns test_netns\n+\n+\tip -netns \"${test_netns}\" link add \"${DUMMY_DEVNAME}\" type dummy\n+\n+\tif ! tc -netns \"${test_netns}\" qdisc add dev \"${DUMMY_DEVNAME}\" \\\n+\t\t\tclsact 2\u003e/dev/null; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: tc clsact qdisc not supported\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\tif ! tc -netns \"${test_netns}\" filter add dev \"${DUMMY_DEVNAME}\" \\\n+\t\t\tingress chain \"${BPF_CHAIN}\" protocol ipv6 \\\n+\t\t\tbpf object-file \"${BPF_FILE}\" section \"${BPF_TC_SEC}\" \\\n+\t\t\tdirect-action 2\u003e/dev/null; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: tc bpf filter not supported\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\tif ! tc -netns \"${test_netns}\" filter add dev \"${DUMMY_DEVNAME}\" \\\n+\t\t\tingress chain \"${CTRL_CHAIN}\" protocol ipv6 \\\n+\t\t\tflower dst_ip \"${CTRL_DST}\" \\\n+\t\t\taction goto chain \"${BPF_CHAIN}\" 2\u003e/dev/null; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: tc flower filter or goto chain action not supported\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\tif ! tc -netns \"${test_netns}\" filter add dev \"${DUMMY_DEVNAME}\" \\\n+\t\t\tingress protocol ipv6 matchall \\\n+\t\t\taction ct pipe action goto chain \"${CTRL_CHAIN}\" \\\n+\t\t\t2\u003e/dev/null; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: tc matchall filter or ct action not supported\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\t# setup_rt() turns on nf_conntrack_checksum. If it is off, conntrack\n+\t# does not check the UDP checksum and does not compute the receive\n+\t# checksum. The test cannot see the error.\n+\tif ! ip netns exec \"${test_netns}\" sysctl -wq \\\n+\t\t\tnet.netfilter.nf_conntrack_checksum=1 2\u003e/dev/null; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: nf_conntrack_checksum sysctl not available\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\tcleanup_ns \"${test_netns}\"\n+}\n+\n+test_end_bpf_or_ksft_skip()\n+{\n+\tlocal test_netns\n+\n+\tsetup_ns test_netns\n+\n+\tip -netns \"${test_netns}\" link add \"${DUMMY_DEVNAME}\" type dummy\n+\tip -netns \"${test_netns}\" link set \"${DUMMY_DEVNAME}\" up\n+\n+\tif ! ip -netns \"${test_netns}\" -6 route \\\n+\t\t\tadd \"${SID_LOCATOR}::${BPF_FUNC}/128\" encap seg6local \\\n+\t\t\taction End.BPF endpoint obj \"${BPF_FILE}\" \\\n+\t\t\tsec \"${BPF_END_SEC}\" dev \"${DUMMY_DEVNAME}\" \\\n+\t\t\t2\u003e/dev/null; then\n+\t\tcleanup_ns \"${test_netns}\"\n+\t\techo \"SKIP: SRv6 End.BPF not supported\"\n+\t\texit \"${ksft_skip}\"\n+\tfi\n+\n+\tcleanup_ns \"${test_netns}\"\n+}\n+\n+if [ \"$(id -u)\" -ne 0 ]; then\n+\techo \"SKIP: Need root privileges\"\n+\texit \"${ksft_skip}\"\n+fi\n+\n+# required programs to carry out this selftest\n+test_command_or_ksft_skip ip\n+test_command_or_ksft_skip tc\n+test_command_or_ksft_skip ethtool\n+test_command_or_ksft_skip ping\n+test_command_or_ksft_skip sysctl\n+test_command_or_ksft_skip awk\n+test_command_or_ksft_skip grep\n+\n+test_dummy_dev_or_ksft_skip\n+test_iproute2_supp_or_ksft_skip\n+test_kernel_supp_or_ksft_skip\n+test_veth_tx_csum_off_or_ksft_skip\n+test_bpf_file_or_ksft_skip\n+test_tc_or_ksft_skip\n+test_end_bpf_or_ksft_skip\n+\n+set -e\n+trap cleanup EXIT\n+\n+setup\n+set +e\n+\n+connectivity_tests\n+udp_delivery_tests\n+\n+print_log_test_results\n"
} |
| 2/1 | 2026/11/01 14:16 | agent | patch-evaluator |
3mModel:core Args: null Results: {
"EnableConfigs": [
"IPV6",
"IPV6_SEG6_LWTUNNEL",
"IPV6_SEG6_BPF"
],
"FocusSymbols": [
"ipv6_srh_rcv",
"seg6_update_csum",
"ipv6_rthdr_rcv",
"seg6_do_srh",
"seg6_input",
"seg6_output",
"advance_nextseg",
"seg6_next_csid_advance_arg",
"input_action_end_bpf",
"seg6_local_input"
],
"Reasoning": "The patch series modifies checksum update logic for IPv6 Segment Routing (SRv6) when packets carry CHECKSUM_COMPLETE. Specifically, it corrects the complement arithmetic in update_csum_diff4() and update_csum_diff16(), adds missing checksum updates when updating the hop limit in ipv6_srh_rcv(), updates skb-\u003ecsum when advancing segments in advance_nextseg() and seg6_next_csid_advance_arg(), uses skb_push_rcsum() in seg6_do_srh(), and clears CHECKSUM_COMPLETE in input_action_end_bpf(). This code is part of core IPv6 routing and lightweight tunnel encapsulation, fully reachable in standard virtualized QEMU/GCE environments via standard IPv6 sockets, loopback/veth interfaces, and netlink route encapsulation configs. Fuzzing is warranted to detect regressions, improper checksum handling, or packet corruption.",
"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 7ed98965b2ad5b10d241ec5fc25b58517ece0a7e
Author: syz-cluster <triage@syzkaller.com>
Date: Sun Nov 1 14:16:31 2026 +0000
syz-cluster: applied patch under review
diff --git a/include/net/seg6.h b/include/net/seg6.h
index 82b3fbbcbb9351..01d8034e48fcab 100644
--- a/include/net/seg6.h
+++ b/include/net/seg6.h
@@ -19,7 +19,7 @@ static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,
{
__be32 diff[] = { ~from, to };
- skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);
+ skb->csum = csum_partial(diff, sizeof(diff), skb->csum);
}
static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,
@@ -30,7 +30,7 @@ static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,
to[0], to[1], to[2], to[3],
};
- skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);
+ skb->csum = csum_partial(diff, sizeof(diff), skb->csum);
}
struct seg6_pernet_data {
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 96c8402a27a549..9d3ba310065a1b 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -460,6 +460,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)
}
if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) {
+ /* payload_len, nexthdr and hop_limit */
+ __be32 *hlim_word = (__be32 *)ipv6_hdr(skb) + 1;
+ __be32 old;
+
if (ipv6_hdr(skb)->hop_limit <= 1) {
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
icmpv6_send(skb, ICMPV6_TIME_EXCEED,
@@ -467,8 +471,12 @@ static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)
kfree_skb_reason(skb, SKB_DROP_REASON_IP_TTL_EXCEEDED);
return -1;
}
+ old = *hlim_word;
ipv6_hdr(skb)->hop_limit--;
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ update_csum_diff4(skb, old, *hlim_word);
+
skb_pull(skb, skb_transport_offset(skb));
goto looped_back;
}
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 0d39a38a5dd299..3821d8e1409e71 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -456,7 +456,7 @@ static int seg6_do_srh(struct sk_buff *skb, struct dst_entry *cache_dst)
return err;
skb_mac_header_rebuild(skb);
- skb_push(skb, skb->mac_len);
+ skb_push_rcsum(skb, skb->mac_len);
if (tinfo->mode == SEG6_IPTUN_MODE_L2ENCAP)
err = __seg6_do_srh_encap(skb, tinfo->srh,
diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index 0c3d1be7f1299e..3045a351f4e92f 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -291,7 +291,9 @@ static struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,
struct ipv6_sr_hdr *srh,
enum skb_drop_reason *reason)
{
+ struct in6_addr *daddr;
struct in6_addr *addr;
+ __be32 old;
int srhoff;
int wlen;
@@ -309,10 +311,19 @@ static struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,
/* skb_ensure_writable() may change skb pointers; evaluate srh again */
srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
+ daddr = &ipv6_hdr(skb)->daddr;
+ /* nexthdr, hdrlen, type and segments_left */
+ old = *(__be32 *)srh;
srh->segments_left--;
addr = srh->segments + srh->segments_left;
- ipv6_hdr(skb)->daddr = *addr;
+
+ if (skb->ip_summed == CHECKSUM_COMPLETE) {
+ update_csum_diff4(skb, old, *(__be32 *)srh);
+ update_csum_diff16(skb, (__be32 *)daddr, (__be32 *)addr);
+ }
+
+ *daddr = *addr;
return srh;
}
@@ -427,11 +438,13 @@ seg6_next_csid_advance_arg(struct sk_buff *skb,
__u8 fnc_octects = seg6_flv_lcnode_func_octects(finfo);
__u8 blk_octects = seg6_flv_lcblock_octects(finfo);
struct in6_addr *addr;
+ struct in6_addr old;
if (unlikely(skb_ensure_writable(skb, sizeof(struct ipv6hdr))))
return SKB_DROP_REASON_NOMEM;
addr = &ipv6_hdr(skb)->daddr;
+ old = *addr;
/* advance DA.Argument */
memmove(&addr->s6_addr[blk_octects],
@@ -440,6 +453,9 @@ seg6_next_csid_advance_arg(struct sk_buff *skb,
memset(&addr->s6_addr[16 - fnc_octects], 0x00, fnc_octects);
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ update_csum_diff16(skb, (__be32 *)&old, (__be32 *)addr);
+
return SKB_NOT_DROPPED_YET;
}
@@ -1566,6 +1582,12 @@ static int input_action_end_bpf(struct sk_buff *skb,
goto drop;
}
+ /* The program may have changed the packet and seg6_bpf_has_valid_srh()
+ * may rewrite the SRH Hdr Ext Len below.
+ * skb->csum may then no longer be the checksum of the full packet.
+ */
+ skb_checksum_complete_unset(skb);
+
if (srh_state->srh && !seg6_bpf_has_valid_srh(skb))
goto drop;
local_unlock_nested_bh(&seg6_bpf_srh_states.bh_lock);
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index df215e1a62621b..16e9fbf889fd1b 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -92,6 +92,7 @@ TEST_PROGS := \
rxtimestamp.sh \
sctp_vrf.sh \
skf_net_off.sh \
+ srv6_csum_complete_test.sh \
srv6_encap_lookup_l3vpn_test.sh \
srv6_end_dt46_l3vpn_test.sh \
srv6_end_dt4_l3vpn_test.sh \
diff --git a/tools/testing/selftests/net/srv6_csum_complete.bpf.c b/tools/testing/selftests/net/srv6_csum_complete.bpf.c
new file mode 100644
index 00000000000000..281b0361f97693
--- /dev/null
+++ b/tools/testing/selftests/net/srv6_csum_complete.bpf.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Andrea Mayer <andrea.mayer@uniroma2.it>
+ */
+#include <stddef.h>
+#include <linux/bpf.h>
+#include <linux/if_ether.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/seg6.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+/* On the tc ingress, skb->data points to the Ethernet header */
+#define TC_IPV6_OFF ETH_HLEN
+/* Byte with the lowest 8 bits of the Flow Label */
+#define TC_FLOW_LBL_OFF (TC_IPV6_OFF + \
+ offsetof(struct ipv6hdr, flow_lbl) + 2)
+/* Bit of the Flow Label changed in the control datagram */
+#define CTRL_FLOW_LBL_BIT 0x01
+
+/* In End.BPF, skb->data points to the IPv6 header, followed by the SRH */
+#define SRH_TAG_OFF (sizeof(struct ipv6hdr) + \
+ offsetof(struct ipv6_sr_hdr, tag))
+/* Value written in the SRH Tag, test case (vi) */
+#define SRH_TAG 0x1234
+
+/* Test case (v) of srv6_csum_complete_test.sh. The program runs on the tc
+ * ingress of rt, after the ct action, only for the control datagram. It
+ * changes one bit of the Flow Label, without updating the receive checksum
+ * (skb->csum). The Flow Label is not part of the UDP checksum, which stays
+ * correct. UDP must drop the datagram because the receive checksum no longer
+ * matches the packet.
+ */
+SEC("tc")
+int ctrl_flow_label(struct __sk_buff *skb)
+{
+ __u8 lbl;
+
+ /* Read the byte with the lowest 8 bits of the Flow Label */
+ if (bpf_skb_load_bytes(skb, TC_FLOW_LBL_OFF, &lbl, sizeof(lbl)))
+ return TC_ACT_SHOT;
+
+ lbl ^= CTRL_FLOW_LBL_BIT;
+
+ /* Write the byte back, flags 0 do not update the receive checksum */
+ if (bpf_skb_store_bytes(skb, TC_FLOW_LBL_OFF, &lbl, sizeof(lbl), 0))
+ return TC_ACT_SHOT;
+
+ return TC_ACT_OK;
+}
+
+/* Test case (vi), the End.BPF program writes the SRH Tag */
+SEC("lwt_seg6local")
+int end_bpf_tag(struct __sk_buff *skb)
+{
+ __u16 tag = bpf_htons(SRH_TAG);
+
+ if (bpf_lwt_seg6_store_bytes(skb, SRH_TAG_OFF, &tag, sizeof(tag)))
+ return BPF_DROP;
+
+ return BPF_OK;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/net/srv6_csum_complete_test.sh b/tools/testing/selftests/net/srv6_csum_complete_test.sh
new file mode 100755
index 00000000000000..0b9c929313620f
--- /dev/null
+++ b/tools/testing/selftests/net/srv6_csum_complete_test.sh
@@ -0,0 +1,642 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# author: Andrea Mayer <andrea.mayer@uniroma2.it>
+
+# This test checks the receive checksum of an SRv6 packet that is processed and
+# then delivered on the same node. The node changes the Segments Left and the
+# destination address of the packet, and can also change the Hop Limit.
+#
+# The receive checksum (CHECKSUM_COMPLETE) is the checksum of the whole packet,
+# kept with the received packet. When the node changes the packet, it must also
+# update this sum, or discard it.
+#
+# Network topology
+# ================
+#
+# The test uses a host (hs) and a router (rt) connected through a veth pair. In
+# each test case, hs sends one UDP datagram to an address of rt.
+#
+# +--------------------+ +--------------------------+
+# | hs | | rt |
+# | | | |
+# | veth-hs +--------------------+ veth-rt |
+# | fd00::1/64 | | fd00::2/64 |
+# | tx checksum off | | tc ingress: ct, then bpf |
+# +--------------------+ | |
+# | lo: fc00::1 ... fc00::4 |
+# | cafe::1 ... cafe::6 |
+# +--------------------------+
+#
+# Receive checksum
+# ================
+#
+# veth does not provide the receive checksum. For this reason, a tc ct action
+# runs on the ingress of rt. The ct action checks the UDP checksum, and in this
+# way computes the receive checksum in software. If the receive checksum does
+# not match the packet, UDP drops the datagram as a checksum error.
+#
+# The ct action computes the receive checksum when hs computes the UDP checksum
+# in software, before the datagram crosses the veth. For this reason, hs has
+# transmit checksumming off.
+#
+# Each datagram is longer than 76 bytes, UDP header included. For datagrams of
+# 76 bytes or less, UDP computes the checksum again from the packet, and accepts
+# the datagram even with a wrong receive checksum.
+#
+# UDP counters
+# ============
+#
+# Each datagram goes to a port with no listener. If the UDP checksum check
+# passes, rt counts the datagram in Udp6NoPorts. If it fails, rt counts it in
+# Udp6InCsumErrors.
+#
+# Control datagram
+# ================
+#
+# A control datagram checks that the test detects a wrong receive checksum after
+# a change to the packet. After the ct action, a tc bpf filter on rt changes one
+# bit of its Flow Label, without updating the receive checksum. The Flow Label
+# is not part of the UDP checksum, which stays correct. UDP must drop the
+# datagram because the receive checksum no longer matches the packet. If UDP
+# accepts it, the test cannot detect a wrong receive checksum. The other test
+# cases may then pass even when their receive checksum is wrong, and for this
+# reason the test fails.
+#
+# Routes and tc filters
+# =====================
+#
+# hs: encap (main table)
+# +---------+-----------------------------------------------------+
+# | dst | action |
+# +---------+-----------------------------------------------------+
+# | cafe::1 | via fd00::2 |
+# | cafe::2 | encap seg6 mode inline segs fc00::1,fc00::2 |
+# | cafe::3 | encap seg6 mode inline segs fcbb:0:0200:: |
+# | cafe::4 | encap seg6 mode inline segs fcbb:0:0100:0200:: |
+# | cafe::5 | encap seg6 mode inline segs fc00::3,fc00::4 |
+# | cafe::6 | encap seg6 mode inline segs fc00::b0,fcbb:0:0200:: |
+# +---------+-----------------------------------------------------+
+#
+# rt: SRv6 behaviors (main table)
+# +------------------+------------------------------------------------+
+# | SID | action |
+# +------------------+------------------------------------------------+
+# | fcbb:0:0100::/48 | End flavors next-csid lblen 32 nflen 16 |
+# | fcbb:0:0200::/48 | End.B6.Encaps srh segs fc00::d6 |
+# | fc00::d6 | End.DT6 table 255 (local) |
+# | fc00::b0 | End.BPF, the program writes the SRH Tag |
+# +------------------+------------------------------------------------+
+#
+# rt: tc ingress of veth-rt
+# +-------+------+---------------------------------------------------+
+# | chain | prio | filter |
+# +-------+------+---------------------------------------------------+
+# | 0 | 1 | matchall, action ct, goto chain 1 |
+# | 1 | 1 | flower dst_ip fc00::3, goto chain 2 |
+# | 2 | 1 | bpf, changes one bit of the Flow Label |
+# +-------+------+---------------------------------------------------+
+#
+# Test cases
+# ==========
+#
+# hs applies the SRv6 Policies in inline mode, i.e. the original destination
+# becomes the last SID of the SID List.
+#
+# i) cafe::1, no SRH, used as a reference.
+#
+# ii) cafe::2, SID List=fc00::1,fc00::2,cafe::2
+# fc00::1 and fc00::2 are addresses of rt. rt processes the SRH twice. Each
+# time, it also decrements the Hop Limit.
+#
+# iii) cafe::3, SID List=fcbb:0:0200::,cafe::3
+# End.B6.Encaps advances the SRH and adds an outer IPv6 header with an SRH.
+# The outer header goes to the End.DT6 SID fc00::d6, which removes it.
+#
+# iv) cafe::4, SID List=fcbb:0:0100:0200::,cafe::4
+# End with the NEXT-C-SID flavor changes the DA to the next C-SID,
+# fcbb:0:0200::. Then the datagram follows the same path as in (iii).
+#
+# v) cafe::5, SID List=fc00::3,fc00::4,cafe::5, control.
+# The tc flower filter matches the first segment, fc00::3, and the tc bpf
+# filter changes the Flow Label. Then rt processes the SRH as in (ii).
+#
+# vi) cafe::6, SID List=fc00::b0,fcbb:0:0200::,cafe::6
+# End.BPF writes the SRH Tag. Then the datagram follows the same path as in
+# (iii).
+#
+# In the test case (v), the datagram is expected to be dropped as a checksum
+# error. In all the other test cases, the datagram is expected to be delivered
+# on rt.
+
+# shellcheck source=lib.sh
+source lib.sh
+
+readonly IPv6_RT_NETWORK=fd00
+readonly IPv6_DST_NETWORK=cafe
+readonly SID_LOCATOR=fc00
+readonly CSID_BLOCK=fcbb:0
+readonly CSID_LBLEN=32
+readonly CSID_NFLEN=16
+readonly CSID_BLOCK_FUNC_LEN=$((CSID_LBLEN + CSID_NFLEN))
+readonly B6_FUNC=0200
+readonly CSID_FUNC=0100
+readonly DT6_FUNC=d6
+readonly BPF_FUNC=b0
+readonly DUMMY_DEVNAME=dum0
+readonly UDP_PORT=9
+readonly UDP_PAYLOAD_LEN=200
+readonly WAIT_TIMEOUT_SEC=5
+
+# destination of the control datagram on the veth, test case (v)
+readonly CTRL_DST="${SID_LOCATOR}::3"
+# tc chain of the flower filter that selects the control datagram
+readonly CTRL_CHAIN=1
+# tc chain of the bpf filter that changes the Flow Label
+readonly BPF_CHAIN=2
+
+readonly BPF_FILE=srv6_csum_complete.bpf.o
+readonly BPF_TC_SEC=tc
+readonly BPF_END_SEC=lwt_seg6local
+
+# return values of check_udp_delivery()
+readonly UDP_DELIVERED=0
+readonly UDP_LOST=1
+readonly UDP_CSUM_ERROR=2
+
+SETUP_ERR=1
+
+ret=${ksft_skip}
+nsuccess=0
+nfail=0
+
+log_test()
+{
+ log_test_expected "$1" "$2" "$3"
+}
+
+print_log_test_results()
+{
+ printf "\nTests passed: %3d\n" "${nsuccess}"
+ printf "Tests failed: %3d\n" "${nfail}"
+
+ # when a test fails, the value of 'ret' is set to 1 (error code).
+ # Conversely, when all tests are passed successfully, the 'ret' value
+ # is set to 0 (success code).
+ if [ "${ret}" -ne 1 ]; then
+ ret=0
+ fi
+}
+
+log_section()
+{
+ echo
+ echo "################################################################################"
+ echo "TEST SECTION: $*"
+ echo "################################################################################"
+}
+
+cleanup()
+{
+ cleanup_all_ns
+
+ # check whether the setup phase was completed successfully or not. In
+ # case of an error during the setup phase of the testing environment,
+ # the selftest is considered as "skipped".
+ if [ "${SETUP_ERR}" -ne 0 ]; then
+ echo "SKIP: Setting up the testing environment failed"
+ exit "${ksft_skip}"
+ fi
+
+ exit "${ret}"
+}
+
+# add on hs the SRv6 Policy for cafe::<id>, in inline mode
+# args:
+# $1 - destination id
+# $2 - segments, comma separated
+set_hs_policy()
+{
+ local dstid="$1"
+ local segs="$2"
+
+ ip -netns "${NS_HS}" -6 route add "${IPv6_DST_NETWORK}::${dstid}/128" \
+ encap seg6 mode inline segs "${segs}" \
+ via "${IPv6_RT_NETWORK}::2" dev veth-hs
+}
+
+setup_hs()
+{
+ ip -netns "${NS_HS}" link set veth-hs up
+ ip -netns "${NS_HS}" addr add "${IPv6_RT_NETWORK}::1/64" \
+ dev veth-hs nodad
+
+ # with transmit checksumming on, conntrack on rt does not compute the
+ # receive checksum
+ ip netns exec "${NS_HS}" ethtool -K veth-hs tx off >/dev/null
+
+ # routes to the SIDs, used after the SRH is inserted
+ ip -netns "${NS_HS}" -6 route add "${SID_LOCATOR}::/16" \
+ via "${IPv6_RT_NETWORK}::2" dev veth-hs
+ ip -netns "${NS_HS}" -6 route add "${CSID_BLOCK}::/${CSID_LBLEN}" \
+ via "${IPv6_RT_NETWORK}::2" dev veth-hs
+
+ # test case (i), the reference, no SRH
+ ip -netns "${NS_HS}" -6 route add "${IPv6_DST_NETWORK}::1/128" \
+ via "${IPv6_RT_NETWORK}::2" dev veth-hs
+
+ # the SRv6 Policies of the test cases (ii) to (vi)
+ set_hs_policy 2 "${SID_LOCATOR}::1,${SID_LOCATOR}::2"
+ set_hs_policy 3 "${CSID_BLOCK}:${B6_FUNC}::"
+ set_hs_policy 4 "${CSID_BLOCK}:${CSID_FUNC}:${B6_FUNC}::"
+ set_hs_policy 5 "${SID_LOCATOR}::3,${SID_LOCATOR}::4"
+ set_hs_policy 6 "${SID_LOCATOR}::${BPF_FUNC},${CSID_BLOCK}:${B6_FUNC}::"
+}
+
+setup_rt()
+{
+ local dstid
+ local dev
+
+ ip -netns "${NS_RT}" link set veth-rt up
+ ip -netns "${NS_RT}" addr add "${IPv6_RT_NETWORK}::2/64" \
+ dev veth-rt nodad
+
+ # local segments of the test case (ii)
+ ip -netns "${NS_RT}" addr add "${SID_LOCATOR}::1/128" dev lo nodad
+ ip -netns "${NS_RT}" addr add "${SID_LOCATOR}::2/128" dev lo nodad
+ # local segments of the test case (v)
+ ip -netns "${NS_RT}" addr add "${SID_LOCATOR}::3/128" dev lo nodad
+ ip -netns "${NS_RT}" addr add "${SID_LOCATOR}::4/128" dev lo nodad
+ for dstid in 1 2 3 4 5 6; do
+ ip -netns "${NS_RT}" addr add \
+ "${IPv6_DST_NETWORK}::${dstid}/128" dev lo nodad
+ done
+
+ for dev in all veth-rt lo; do
+ ip netns exec "${NS_RT}" sysctl -wq \
+ net.ipv6.conf."${dev}".seg6_enabled=1
+ done
+
+ # SRv6 behaviors used by the test cases (iii), (iv) and (vi)
+ ip -netns "${NS_RT}" -6 route \
+ add "${CSID_BLOCK}:${CSID_FUNC}::/${CSID_BLOCK_FUNC_LEN}" \
+ encap seg6local action End flavors next-csid \
+ lblen "${CSID_LBLEN}" nflen "${CSID_NFLEN}" dev veth-rt
+ ip -netns "${NS_RT}" -6 route \
+ add "${CSID_BLOCK}:${B6_FUNC}::/${CSID_BLOCK_FUNC_LEN}" \
+ encap seg6local action End.B6.Encaps \
+ srh segs "${SID_LOCATOR}::${DT6_FUNC}" dev veth-rt
+ ip -netns "${NS_RT}" -6 route add "${SID_LOCATOR}::${DT6_FUNC}/128" \
+ encap seg6local action End.DT6 table 255 dev veth-rt
+ ip -netns "${NS_RT}" -6 route add "${SID_LOCATOR}::${BPF_FUNC}/128" \
+ encap seg6local action End.BPF endpoint obj "${BPF_FILE}" \
+ sec "${BPF_END_SEC}" dev veth-rt
+
+ tc -netns "${NS_RT}" qdisc add dev veth-rt clsact
+ # the bpf filter changes the Flow Label of the control datagram
+ tc -netns "${NS_RT}" filter add dev veth-rt ingress \
+ chain "${BPF_CHAIN}" prio 1 protocol ipv6 \
+ bpf object-file "${BPF_FILE}" section "${BPF_TC_SEC}" \
+ direct-action
+ # the control datagram goes to the bpf filter
+ tc -netns "${NS_RT}" filter add dev veth-rt ingress \
+ chain "${CTRL_CHAIN}" prio 1 protocol ipv6 \
+ flower dst_ip "${CTRL_DST}" \
+ action goto chain "${BPF_CHAIN}"
+ # every packet goes to the ct action, which computes the receive
+ # checksum, then to the chain of the flower filter
+ tc -netns "${NS_RT}" filter add dev veth-rt ingress prio 1 \
+ protocol ipv6 matchall \
+ action ct pipe action goto chain "${CTRL_CHAIN}"
+ ip netns exec "${NS_RT}" sysctl -wq \
+ net.netfilter.nf_conntrack_checksum=1
+}
+
+setup()
+{
+ setup_ns NS_HS NS_RT
+
+ ip -netns "${NS_HS}" link add veth-hs type veth \
+ peer name veth-rt netns "${NS_RT}"
+
+ setup_hs
+ setup_rt
+
+ # testing environment was set up successfully
+ SETUP_ERR=0
+}
+
+# print the value of a counter of rt in /proc/net/snmp6
+# args:
+# $1 - counter name in /proc/net/snmp6
+get_rt_udp6_counter()
+{
+ local name="$1"
+
+ ip netns exec "${NS_RT}" cat /proc/net/snmp6 | \
+ awk -v k="${name}" '$1 == k { print $2 }'
+}
+
+# number of datagrams that UDP on rt counted in Udp6NoPorts or Udp6InCsumErrors
+get_rt_udp6_received()
+{
+ echo $(( $(get_rt_udp6_counter Udp6NoPorts) +
+ $(get_rt_udp6_counter Udp6InCsumErrors) ))
+}
+
+check_hs_rt_connectivity()
+{
+ ip netns exec "${NS_HS}" ping -c 1 -W 1 "${IPv6_RT_NETWORK}::2" \
+ >/dev/null 2>&1
+}
+
+check_and_log_hs_rt_connectivity()
+{
+ check_hs_rt_connectivity
+ log_test $? 0 "Connectivity: hs -> rt"
+}
+
+connectivity_tests()
+{
+ log_section "IPv6 connectivity test between host and router"
+
+ check_and_log_hs_rt_connectivity
+}
+
+# Send one UDP datagram from hs to a port with no listener on rt.
+# args:
+# $1 - destination id
+# return:
+# - UDP_DELIVERED if rt counts the datagram as delivered
+# - UDP_CSUM_ERROR if rt drops it for a bad checksum
+# - UDP_LOST if the datagram cannot be sent, or if it does not arrive
+check_udp_delivery()
+{
+ local dstid="$1"
+ local noports
+ local payload
+ local errors
+ local recv
+ local dst
+
+ dst="${IPv6_DST_NETWORK}::${dstid}"
+ noports="$(get_rt_udp6_counter Udp6NoPorts)"
+ errors="$(get_rt_udp6_counter Udp6InCsumErrors)"
+ recv=$((noports + errors))
+ payload="$(printf '%*s' "${UDP_PAYLOAD_LEN}" '')"
+
+ # send the datagram with the /dev/udp redirection of bash
+ if ! ip netns exec "${NS_HS}" bash -c "printf '%s' '${payload}' > \
+ /dev/udp/${dst}/${UDP_PORT}"; then
+ return "${UDP_LOST}"
+ fi
+
+ # wait until rt counts the datagram in Udp6NoPorts or Udp6InCsumErrors
+ if ! slowwait "${WAIT_TIMEOUT_SEC}" until_counter_is \
+ ">= $((recv + 1))" get_rt_udp6_received >/dev/null; then
+ return "${UDP_LOST}"
+ fi
+
+ if [ "$(get_rt_udp6_counter Udp6InCsumErrors)" -ne "${errors}" ]; then
+ return "${UDP_CSUM_ERROR}"
+ fi
+
+ if [ "$(get_rt_udp6_counter Udp6NoPorts)" -ne "$((noports + 1))" ]; then
+ return "${UDP_LOST}"
+ fi
+
+ return "${UDP_DELIVERED}"
+}
+
+# check the delivery of a datagram to cafe::<id> and log the result
+# args:
+# $1 - destination id
+# $2 - expected return value of check_udp_delivery()
+# $3 - description of the path
+check_and_log_udp_delivery()
+{
+ local dstid="$1"
+ local expected="$2"
+ local desc="$3"
+
+ check_udp_delivery "${dstid}"
+ log_test $? "${expected}" \
+ "UDP: hs -> ${IPv6_DST_NETWORK}::${dstid} (${desc})"
+}
+
+udp_delivery_tests()
+{
+ log_section "UDP delivery test with CHECKSUM_COMPLETE"
+
+ check_and_log_udp_delivery 1 "${UDP_DELIVERED}" "no SRH"
+ check_and_log_udp_delivery 2 "${UDP_DELIVERED}" "SRH, local segments"
+ check_and_log_udp_delivery 3 "${UDP_DELIVERED}" "End.B6.Encaps, End.DT6"
+ check_and_log_udp_delivery 4 "${UDP_DELIVERED}" \
+ "End next-csid, End.B6.Encaps, End.DT6"
+ check_and_log_udp_delivery 5 "${UDP_CSUM_ERROR}" "control, csum error"
+ check_and_log_udp_delivery 6 "${UDP_DELIVERED}" \
+ "End.BPF, End.B6.Encaps, End.DT6"
+}
+
+test_command_or_ksft_skip()
+{
+ local cmd="$1"
+
+ if [ ! -x "$(command -v "${cmd}")" ]; then
+ echo "SKIP: Could not run test without \"${cmd}\" tool"
+ exit "${ksft_skip}"
+ fi
+}
+
+test_dummy_dev_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ modprobe dummy &>/dev/null || true
+ if ! ip -netns "${test_netns}" link add "${DUMMY_DEVNAME}" \
+ type dummy; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: dummy dev not supported"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+test_iproute2_supp_or_ksft_skip()
+{
+ if ! ip route help 2>&1 | grep -qo next-csid; then
+ echo "SKIP: Missing SRv6 next-csid flavor support in iproute2"
+ exit "${ksft_skip}"
+ fi
+}
+
+test_kernel_supp_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ ip -netns "${test_netns}" link add "${DUMMY_DEVNAME}" type dummy
+ ip -netns "${test_netns}" link set "${DUMMY_DEVNAME}" up
+
+ if ! ip -netns "${test_netns}" -6 route \
+ add "${CSID_BLOCK}::/${CSID_LBLEN}" encap seg6local \
+ action End flavors next-csid dev "${DUMMY_DEVNAME}" \
+ 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: SRv6 next-csid flavor not supported"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+test_veth_tx_csum_off_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ if ! ip -netns "${test_netns}" link add veth-t0 type veth \
+ peer name veth-t1 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: veth dev not supported"
+ exit "${ksft_skip}"
+ fi
+
+ # setup_hs() turns off transmit checksumming on veth-hs. If it stays on,
+ # conntrack does not compute the receive checksum and the test cannot
+ # see the error.
+ ip netns exec "${test_netns}" ethtool -K veth-t0 tx off >/dev/null 2>&1
+
+ if ! ip netns exec "${test_netns}" ethtool -k veth-t0 | \
+ grep -q "^tx-checksumming: off"; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: Cannot turn off transmit checksumming on veth"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+test_bpf_file_or_ksft_skip()
+{
+ if [ ! -f "${BPF_FILE}" ]; then
+ echo "SKIP: Missing ${BPF_FILE}, run 'make' first"
+ exit "${ksft_skip}"
+ fi
+}
+
+test_tc_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ ip -netns "${test_netns}" link add "${DUMMY_DEVNAME}" type dummy
+
+ if ! tc -netns "${test_netns}" qdisc add dev "${DUMMY_DEVNAME}" \
+ clsact 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: tc clsact qdisc not supported"
+ exit "${ksft_skip}"
+ fi
+
+ if ! tc -netns "${test_netns}" filter add dev "${DUMMY_DEVNAME}" \
+ ingress chain "${BPF_CHAIN}" protocol ipv6 \
+ bpf object-file "${BPF_FILE}" section "${BPF_TC_SEC}" \
+ direct-action 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: tc bpf filter not supported"
+ exit "${ksft_skip}"
+ fi
+
+ if ! tc -netns "${test_netns}" filter add dev "${DUMMY_DEVNAME}" \
+ ingress chain "${CTRL_CHAIN}" protocol ipv6 \
+ flower dst_ip "${CTRL_DST}" \
+ action goto chain "${BPF_CHAIN}" 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: tc flower filter or goto chain action not supported"
+ exit "${ksft_skip}"
+ fi
+
+ if ! tc -netns "${test_netns}" filter add dev "${DUMMY_DEVNAME}" \
+ ingress protocol ipv6 matchall \
+ action ct pipe action goto chain "${CTRL_CHAIN}" \
+ 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: tc matchall filter or ct action not supported"
+ exit "${ksft_skip}"
+ fi
+
+ # setup_rt() turns on nf_conntrack_checksum. If it is off, conntrack
+ # does not check the UDP checksum and does not compute the receive
+ # checksum. The test cannot see the error.
+ if ! ip netns exec "${test_netns}" sysctl -wq \
+ net.netfilter.nf_conntrack_checksum=1 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: nf_conntrack_checksum sysctl not available"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+test_end_bpf_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ ip -netns "${test_netns}" link add "${DUMMY_DEVNAME}" type dummy
+ ip -netns "${test_netns}" link set "${DUMMY_DEVNAME}" up
+
+ if ! ip -netns "${test_netns}" -6 route \
+ add "${SID_LOCATOR}::${BPF_FUNC}/128" encap seg6local \
+ action End.BPF endpoint obj "${BPF_FILE}" \
+ sec "${BPF_END_SEC}" dev "${DUMMY_DEVNAME}" \
+ 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: SRv6 End.BPF not supported"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+if [ "$(id -u)" -ne 0 ]; then
+ echo "SKIP: Need root privileges"
+ exit "${ksft_skip}"
+fi
+
+# required programs to carry out this selftest
+test_command_or_ksft_skip ip
+test_command_or_ksft_skip tc
+test_command_or_ksft_skip ethtool
+test_command_or_ksft_skip ping
+test_command_or_ksft_skip sysctl
+test_command_or_ksft_skip awk
+test_command_or_ksft_skip grep
+
+test_dummy_dev_or_ksft_skip
+test_iproute2_supp_or_ksft_skip
+test_kernel_supp_or_ksft_skip
+test_veth_tx_csum_off_or_ksft_skip
+test_bpf_file_or_ksft_skip
+test_tc_or_ksft_skip
+test_end_bpf_or_ksft_skip
+
+set -e
+trap cleanup EXIT
+
+setup
+set +e
+
+connectivity_tests
+udp_delivery_tests
+
+print_log_test_results
|
| 3/2 | 2026/11/01 14:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 13802 output: 43 thoughts: 704 Thoughts: **Analyzing the Patch: Segment Routing v6 Checksum Updates** Okay, let's break this down. My initial assessment is that this patch is all about optimizing and correcting checksum calculations within the Segment Routing over IPv6 (SRv6) implementation. I see changes across several key files, primarily focusing on how checksums are updated within the `sk_buff` structure. First, I'm observing a consistent pattern: the patch is replacing `~csum_partial((char *)diff, sizeof(diff), ~skb->csum)` with `csum_partial(diff, sizeof(diff), skb->csum)`. This strongly suggests a correction or refinement in how the incremental checksum updates are handled. The original code was likely inverting the checksum, calculating a partial checksum over a difference, and then inverting the result again. The revised code removes the double inversion, which could indicate a bug fix related to checksum arithmetic, or a simplification aimed at efficiency if the double-inversion was unnecessary. This correction is evident in `include/net/seg6.h`, impacting both `update_csum_diff4` and `update_csum_diff16`. The patch also adds checksum update logic in `net/ipv6/exthdrs.c` specifically for the loopback interface within `ipv6_srh_rcv`. When the hop limit is decremented, if checksum offloading is enabled (`skb->ip_summed == CHECKSUM_COMPLETE`), the `update_csum_diff4` function is called. This indicates that checksum updates are critical on loopback interfaces, which is essential to make sure the packet's checksum remains valid even as it is manipulated. Moving to `net/ipv6/seg6_iptunnel.c` and `seg6_do_srh`, I'm seeing a change from `skb_push(skb, skb->mac_len)` to `skb_push_rcsum(skb, skb->mac_len)`. This is a significant indicator that the patch is specifically focusing on checksum handling within the SRv6 tunneling context. The `skb_push_rcsum` variant is likely responsible for updating checksums after pushing the MAC header. The `net/ipv6/seg6_local.c` changes are particularly interesting. In `advance_nextseg`, checksum updates are being added when segments_left is decremented and the destination address is updated. The function `update_csum_diff4` is called when decrementing `segments_left`, and `update_csum_diff16` is used when the destination address changes. This suggests the patch addresses crucial checksum maintenance as SRv6 packets are processed, ensuring end-to-end checksum integrity. In `seg6_next_csid_advance_arg`, checksum updates using `update_csum_diff16` are also introduced. Finally, in `input_action_end_bpf` the code is unsetting `skb->ip_summed`. This is likely a cleanup step when BPF programs are involved, to avoid possible confusion from an incorrect checksum flag state. To get the full picture, I need to dig into the surrounding code and understand how these functions are used, and what configuration options are required to enable these changes. I'll reach for grepper or read the files to get context on the modified functions and how these updates interact with other parts of the SRv6 stack. This looks like a solid and targeted set of fixes, but verification is key. |
| 4/2 | 2026/11/01 14:16 | tool | grepper |
0mArgs:{
"Expression": "update_csum_diff",
"PathPrefixes": [
"include/net/seg6.h",
"net/ipv6/"
]
}Results: {
"Output": "include/net/seg6.h-16-\ninclude/net/seg6.h:17:static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,\ninclude/net/seg6.h-18-\t\t\t\t __be32 to)\n--\ninclude/net/seg6.h-24-\ninclude/net/seg6.h:25:static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,\ninclude/net/seg6.h-26-\t\t\t\t __be32 *to)\n--\nnet/ipv6/exthdrs.c=342=static void seg6_update_csum(struct sk_buff *skb)\n--\nnet/ipv6/exthdrs.c-362-\nnet/ipv6/exthdrs.c:363:\tupdate_csum_diff4(skb, from, to);\nnet/ipv6/exthdrs.c-364-\n--\nnet/ipv6/exthdrs.c-366-\nnet/ipv6/exthdrs.c:367:\tupdate_csum_diff16(skb, (__be32 *)(\u0026ipv6_hdr(skb)-\u003edaddr),\nnet/ipv6/exthdrs.c-368-\t\t\t (__be32 *)addr);\n--\nnet/ipv6/exthdrs.c=371=static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n--\nnet/ipv6/exthdrs.c-477-\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\nnet/ipv6/exthdrs.c:478:\t\t\tupdate_csum_diff4(skb, old, *hlim_word);\nnet/ipv6/exthdrs.c-479-\n--\nnet/ipv6/seg6_local.c=290=static struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-321-\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE) {\nnet/ipv6/seg6_local.c:322:\t\tupdate_csum_diff4(skb, old, *(__be32 *)srh);\nnet/ipv6/seg6_local.c:323:\t\tupdate_csum_diff16(skb, (__be32 *)daddr, (__be32 *)addr);\nnet/ipv6/seg6_local.c-324-\t}\n--\nnet/ipv6/seg6_local.c=435=seg6_next_csid_advance_arg(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-456-\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\nnet/ipv6/seg6_local.c:457:\t\tupdate_csum_diff16(skb, (__be32 *)\u0026old, (__be32 *)addr);\nnet/ipv6/seg6_local.c-458-\n"
} |
| 5/2 | 2026/11/01 14:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 16123 output: 29 thoughts: 44 Thoughts: Okay, let's dive into this IPv6 Segment Routing situation. **Kconfig, Compilation, and Dependencies: A Quick Investigation** Alright, first things first: I need to refresh my memory on the Kconfig prerequisites for IPv6 Segment Routing. Let's see what's actually *required* to bring that functionality into the kernel build. Then, since I know the core source code for this likely involves `net/ipv6/seg6*.c`, I need to figure out *where* that code gets compiled. The logical next step is to examine the `net/ipv6/Makefile`. It's almost certain that's where the necessary object files are built. That should show me the relevant dependencies and build configurations. |
| 6/2 | 2026/11/01 14:16 | tool | grepper |
0mArgs:{
"Expression": "seg6",
"PathPrefixes": [
"net/ipv6/Makefile"
]
}Results: {
"Output": "net/ipv6/Makefile=8=ipv6-y :=\taf_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \\\n--\nnet/ipv6/Makefile-12-\t\texthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o \\\nnet/ipv6/Makefile:13:\t\tudp_offload.o seg6.o fib6_notifier.o rpl.o ioam6.o\nnet/ipv6/Makefile-14-\n--\nnet/ipv6/Makefile=24=ipv6-$(CONFIG_NETLABEL) += calipso.o\nnet/ipv6/Makefile:25:ipv6-$(CONFIG_IPV6_SEG6_LWTUNNEL) += seg6_iptunnel.o seg6_local.o\nnet/ipv6/Makefile:26:ipv6-$(CONFIG_IPV6_SEG6_HMAC) += seg6_hmac.o\nnet/ipv6/Makefile-27-ipv6-$(CONFIG_IPV6_RPL_LWTUNNEL) += rpl_iptunnel.o\n"
} |
| 7/2 | 2026/11/01 14:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 16631 output: 35 thoughts: 51 Thoughts: Okay, let's dive into this. Here's how I'd approach this task in my mind: **Examining Kconfig for IPv6 Segment Routing Enhancements** Alright, I need to get a clear picture of what's going on with the IPv6 Segment Routing (SRv6) configuration options. Specifically, I need to verify what's available in the Kconfig files. I know the standard location for IPv6-related configurations is within `net/ipv6/Kconfig`. I'll start there. My immediate focus is on `CONFIG_IPV6_SEG6_LWTUNNEL` and `CONFIG_IPV6_SEG6_HMAC`, as those are the most relevant. I need to understand if they're enabled, how they interact, and if there are any dependencies or related configurations. I also want to make sure I'm not missing anything else that is tagged as a Seg6 config. I'll need to check for other SRv6-related configurations to get the full picture. My goal is to develop a complete and informed understanding of the available options and their relationships within the build system. |
| 8/2 | 2026/11/01 14:16 | tool | grepper |
0mArgs:{
"Expression": "config IPV6_SEG6",
"PathPrefixes": [
"net/ipv6/Kconfig"
]
}Results: {
"Output": "net/ipv6/Kconfig=279=config IPV6_PIMSM_V2\n--\nnet/ipv6/Kconfig-285-\nnet/ipv6/Kconfig:286:config IPV6_SEG6_LWTUNNEL\nnet/ipv6/Kconfig-287-\tbool \"IPv6: Segment Routing Header encapsulation support\"\n--\nnet/ipv6/Kconfig-299-\nnet/ipv6/Kconfig:300:config IPV6_SEG6_HMAC\nnet/ipv6/Kconfig-301-\tbool \"IPv6: Segment Routing HMAC support\"\n--\nnet/ipv6/Kconfig-311-\nnet/ipv6/Kconfig:312:config IPV6_SEG6_BPF\nnet/ipv6/Kconfig-313-\tdef_bool y\n"
} |
| 9/2 | 2026/11/01 14:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 17176 output: 35 thoughts: 20 Thoughts: Here's a summary of my thought process, tailored for an expert like yourself: **Diving into the IPv6 Configuration** Okay, I need to get down into the details. I'm focusing on the IPv6 configuration, specifically within the kernel's Kconfig files. I'm thinking line 286 in `net/ipv6/Kconfig` might be a good starting point for whatever it is I'm investigating. This is where the core IPv6 features and options are defined, and that specific line probably holds a key piece of information related to the problem. I'll need to scrutinize that section and see what it reveals. |
| 10/2 | 2026/11/01 14:16 | tool | read-file |
0mArgs:{
"File": "net/ipv6/Kconfig",
"FirstLine": 285,
"LineCount": 40
}Results: {
"Contents": " 285:\t\n 286:\tconfig IPV6_SEG6_LWTUNNEL\n 287:\t\tbool \"IPv6: Segment Routing Header encapsulation support\"\n 288:\t\tdepends on IPV6\n 289:\t\tselect LWTUNNEL\n 290:\t\tselect DST_CACHE\n 291:\t\tselect IPV6_MULTIPLE_TABLES\n 292:\t\thelp\n 293:\t\t Support for encapsulation of packets within an outer IPv6\n 294:\t\t header and a Segment Routing Header using the lightweight\n 295:\t\t tunnels mechanism. Also enable support for advanced local\n 296:\t\t processing of SRv6 packets based on their active segment.\n 297:\t\n 298:\t\t If unsure, say N.\n 299:\t\n 300:\tconfig IPV6_SEG6_HMAC\n 301:\t\tbool \"IPv6: Segment Routing HMAC support\"\n 302:\t\tdepends on IPV6\n 303:\t\tselect CRYPTO_LIB_SHA1\n 304:\t\tselect CRYPTO_LIB_SHA256\n 305:\t\tselect CRYPTO_LIB_UTILS\n 306:\t\thelp\n 307:\t\t Support for HMAC signature generation and verification\n 308:\t\t of SR-enabled packets.\n 309:\t\n 310:\t\t If unsure, say N.\n 311:\t\n 312:\tconfig IPV6_SEG6_BPF\n 313:\t\tdef_bool y\n 314:\t\tdepends on IPV6_SEG6_LWTUNNEL\n 315:\t\tdepends on IPV6 = y\n 316:\t\n 317:\tconfig IPV6_RPL_LWTUNNEL\n 318:\t\tbool \"IPv6: RPL Source Routing Header support\"\n 319:\t\tdepends on IPV6\n 320:\t\tselect LWTUNNEL\n 321:\t\tselect DST_CACHE\n 322:\t\thelp\n 323:\t\t Support for RFC6554 RPL Source Routing Header using the lightweight\n 324:\t\t tunnels mechanism.\n"
} |
| 11/2 | 2026/11/01 14:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 17927 output: 39 thoughts: 601 Thoughts: **Analyzing the SEG6 Checksum Update** Okay, so we're looking at modifications related to `IPV6`, specifically `IPV6_SEG6_LWTUNNEL` and `IPV6_SEG6_BPF`. My initial thought is to figure out *exactly* what's been altered. Without direct access to git log, the diff is our best bet. Let's dig in. First, I see the changes to `include/net/seg6.h`. The functions `update_csum_diff4` and `update_csum_diff16` immediately catch my eye. The core of the change is in how the checksum is updated within these functions. Previously, it looked like this: `skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);`. Now it's: `skb->csum = csum_partial(diff, sizeof(diff), skb->csum);`. Wait a minute... that previous version was *completely* wrong. `csum_partial` calculates a 1's complement sum and adds it to the third argument (`wsum`). The `diff` array *already* contains the necessary 1's complement adjustments (`~from` and `to`). Therefore, the double negation and flipping the checksum in that previous version was just adding confusion and errors! It looks like someone was attempting to invert the whole checksum process again, resulting in an incorrect operation. The original code was broken! Okay, where are these `update_csum_diff` functions even *used*? Time to check where they're referenced. It seems they are used in `net/ipv6/exthdrs.c`, specifically within `seg6_update_csum`. Now to examine `seg6_update_csum` in more detail. This refactoring makes much more sense now! |
| 12/2 | 2026/11/01 14:17 | tool | read-file |
0mArgs:{
"File": "net/ipv6/exthdrs.c",
"FirstLine": 340,
"LineCount": 40
}Results: {
"Contents": " 340:\t}\n 341:\t\n 342:\tstatic void seg6_update_csum(struct sk_buff *skb)\n 343:\t{\n 344:\t\tstruct ipv6_sr_hdr *hdr;\n 345:\t\tstruct in6_addr *addr;\n 346:\t\t__be32 from, to;\n 347:\t\n 348:\t\t/* srh is at transport offset and seg_left is already decremented\n 349:\t\t * but daddr is not yet updated with next segment\n 350:\t\t */\n 351:\t\n 352:\t\thdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);\n 353:\t\taddr = hdr-\u003esegments + hdr-\u003esegments_left;\n 354:\t\n 355:\t\thdr-\u003esegments_left++;\n 356:\t\tfrom = *(__be32 *)hdr;\n 357:\t\n 358:\t\thdr-\u003esegments_left--;\n 359:\t\tto = *(__be32 *)hdr;\n 360:\t\n 361:\t\t/* update skb csum with diff resulting from seg_left decrement */\n 362:\t\n 363:\t\tupdate_csum_diff4(skb, from, to);\n 364:\t\n 365:\t\t/* compute csum diff between current and next segment and update */\n 366:\t\n 367:\t\tupdate_csum_diff16(skb, (__be32 *)(\u0026ipv6_hdr(skb)-\u003edaddr),\n 368:\t\t\t\t (__be32 *)addr);\n 369:\t}\n 370:\t\n 371:\tstatic int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n 372:\t{\n 373:\t\tstruct inet6_skb_parm *opt = IP6CB(skb);\n 374:\t\tstruct net *net = dev_net(skb-\u003edev);\n 375:\t\tstruct ipv6_sr_hdr *hdr;\n 376:\t\tstruct in6_addr *addr;\n 377:\t\tint accept_seg6;\n 378:\t\n 379:\t\thdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);\n"
} |
| 13/2 | 2026/11/01 14:17 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 19593 output: 39 thoughts: 40 Thoughts: Okay, here's my interpretation of those lines, crafted as a first-person expert summary: **Diving into IPv6 SRH Reception** Alright, let's get down to the nitty-gritty of how we handle Source Routing Header (SRH) reception in IPv6, specifically within the `ipv6_srh_rcv` function. I need to refresh my memory on the critical processing steps, so let me pull up lines 450-490 in `net/ipv6/exthdrs.c`. I'm expecting to find the core logic for parsing and validating the SRH, checking its integrity, and most importantly, deciding what to do with the packet after the SRH has been processed. My expectation is that this segment will include checks for the SRH's validity, like verifying the header length and ensuring the segments left aligns. It should be handling pointer decrements and potential changes to the destination address based on the current segment. The important considerations for me are always going to be the efficiency of these operations because this is the data path. I'll be looking to see if there are any performance optimizations such as pre-calculated values, as well as any safeguards to prevent buffer overflows or other security vulnerabilities. Of course, any interactions with the routing table will be there as well. The code should also have logic to handle cases where an SRH might be nested (an SRH within another extension header). I'll want to see how it deals with potential errors during processing, like malformed headers or invalid segment numbers, and specifically, what kind of error messages are generated because that could be a performance issue. I'll need to confirm that this is correct, and I will be looking to see that the code adheres to RFC standards to ensure interoperability with different IPv6 implementations. |
| 14/2 | 2026/11/01 14:17 | tool | read-file |
0mArgs:{
"File": "net/ipv6/exthdrs.c",
"FirstLine": 450,
"LineCount": 45
}Results: {
"Contents": " 450:\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\n 451:\t\t\tseg6_update_csum(skb);\n 452:\t\n 453:\t\tipv6_hdr(skb)-\u003edaddr = *addr;\n 454:\t\n 455:\t\tip6_route_input(skb);\n 456:\t\n 457:\t\tif (skb_dst(skb)-\u003eerror) {\n 458:\t\t\tdst_input(skb);\n 459:\t\t\treturn -1;\n 460:\t\t}\n 461:\t\n 462:\t\tif (skb_dst_dev(skb)-\u003eflags \u0026 IFF_LOOPBACK) {\n 463:\t\t\t/* payload_len, nexthdr and hop_limit */\n 464:\t\t\t__be32 *hlim_word = (__be32 *)ipv6_hdr(skb) + 1;\n 465:\t\t\t__be32 old;\n 466:\t\n 467:\t\t\tif (ipv6_hdr(skb)-\u003ehop_limit \u003c= 1) {\n 468:\t\t\t\t__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);\n 469:\t\t\t\ticmpv6_send(skb, ICMPV6_TIME_EXCEED,\n 470:\t\t\t\t\t ICMPV6_EXC_HOPLIMIT, 0);\n 471:\t\t\t\tkfree_skb_reason(skb, SKB_DROP_REASON_IP_TTL_EXCEEDED);\n 472:\t\t\t\treturn -1;\n 473:\t\t\t}\n 474:\t\t\told = *hlim_word;\n 475:\t\t\tipv6_hdr(skb)-\u003ehop_limit--;\n 476:\t\n 477:\t\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\n 478:\t\t\t\tupdate_csum_diff4(skb, old, *hlim_word);\n 479:\t\n 480:\t\t\tskb_pull(skb, skb_transport_offset(skb));\n 481:\t\t\tgoto looped_back;\n 482:\t\t}\n 483:\t\n 484:\t\tdst_input(skb);\n 485:\t\n 486:\t\treturn -1;\n 487:\t}\n 488:\t\n 489:\tstatic int ipv6_rpl_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n 490:\t{\n 491:\t\tstruct ipv6_rpl_sr_hdr *hdr, *ohdr, *chdr;\n 492:\t\tstruct inet6_skb_parm *opt = IP6CB(skb);\n 493:\t\tstruct net *net = dev_net(skb-\u003edev);\n 494:\t\tstruct ipv6hdr *oldhdr;\n"
} |
| 15/2 | 2026/11/01 14:17 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 20818 output: 40 thoughts: 188 Thoughts: **IPv6 Segment Routing Headaches... Solved?** Alright, let's break this down. In `ipv6_srh_rcv`, specifically when dealing with loopback interfaces (`skb_dst_dev(skb)->flags & IFF_LOOPBACK`), there was a subtle but important bug. The hop limit was being decremented, which is standard, but the checksum *wasn't* updated to reflect that change. That's a classic source of packet corruption! Now, thankfully, it looks like they've fixed it. If `skb->ip_summed` is set to `CHECKSUM_COMPLETE`, which is crucial for offload support, we now correctly call `update_csum_diff4(skb, old, *hlim_word)`. Good, that makes me feel better knowing checksum integrity isn't going to be a problem any more. Now, that brings up another interesting point; the code in `seg6_do_srh` in `net/ipv6/seg6_iptunnel.c` was updated. Previously, a simple `skb_push(skb, skb->mac_len);` was used. But now it's been changed to `skb_push_rcsum(skb, skb->mac_len);`. This is important, as `skb_push_rcsum` keeps track of the checksum, in contrast to the older function. It keeps checksums correct by design. I'll need to dig into `seg6_do_srh` itself to see exactly how this change improves performance and/or correct handling of the packet. But, for now, the checksum fix is a huge improvement, and I'm glad someone caught it! |
| 16/2 | 2026/11/01 14:17 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_iptunnel.c",
"FirstLine": 445,
"LineCount": 40
}Results: {
"Contents": " 445:\t\tcase SEG6_IPTUN_MODE_L2ENCAP:\n 446:\t\tcase SEG6_IPTUN_MODE_L2ENCAP_RED:\n 447:\t\t\tif (!skb_mac_header_was_set(skb))\n 448:\t\t\t\treturn -EINVAL;\n 449:\t\n 450:\t\t\theadroom = skb-\u003emac_len + sizeof(struct ipv6hdr) +\n 451:\t\t\t\t ipv6_optlen(tinfo-\u003esrh) +\n 452:\t\t\t\t dst_dev_overhead(cache_dst, skb);\n 453:\t\n 454:\t\t\terr = skb_cow_head(skb, headroom);\n 455:\t\t\tif (unlikely(err))\n 456:\t\t\t\treturn err;\n 457:\t\n 458:\t\t\tskb_mac_header_rebuild(skb);\n 459:\t\t\tskb_push_rcsum(skb, skb-\u003emac_len);\n 460:\t\n 461:\t\t\tif (tinfo-\u003emode == SEG6_IPTUN_MODE_L2ENCAP)\n 462:\t\t\t\terr = __seg6_do_srh_encap(skb, tinfo-\u003esrh,\n 463:\t\t\t\t\t\t\t IPPROTO_ETHERNET, cache_dst,\n 464:\t\t\t\t\t\t\t \u0026slwt-\u003etunsrc);\n 465:\t\t\telse\n 466:\t\t\t\terr = seg6_do_srh_encap_red(skb, tinfo-\u003esrh,\n 467:\t\t\t\t\t\t\t IPPROTO_ETHERNET, cache_dst,\n 468:\t\t\t\t\t\t\t \u0026slwt-\u003etunsrc);\n 469:\t\n 470:\t\t\tif (err)\n 471:\t\t\t\treturn err;\n 472:\t\n 473:\t\t\tskb-\u003eprotocol = htons(ETH_P_IPV6);\n 474:\t\t\tbreak;\n 475:\t\t}\n 476:\t\n 477:\t\tskb_set_transport_header(skb, sizeof(struct ipv6hdr));\n 478:\t\tnf_reset_ct(skb);\n 479:\t\n 480:\t\treturn 0;\n 481:\t}\n 482:\t\n 483:\t/* insert an SRH within an IPv6 packet, just after the IPv6 header */\n 484:\tint seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)\n"
} |
| 17/2 | 2026/11/01 14:17 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 22076 output: 39 thoughts: 51 Thoughts: Here's my analysis of the provided code locations, from an expert's perspective: **Diving into `net/ipv6/seg6_local.c`** Okay, so we're focusing on some specific sections within `net/ipv6/seg6_local.c`. I see the intent here: we're probably digging into how Segment Routing over IPv6 (SRv6) is implemented locally. Let's break down those line ranges. * **Lines 290-330:** This is likely dealing with handling incoming SRv6 packets at the local node. I'm expecting to find the core logic for the "local SIDs" processing - how the system figures out which local segment is being targeted, any potential actions taken (e.g., decapsulation if the SID directs us to a tunnel endpoint). I want to see how the code interfaces with the FIB (Forwarding Information Base) or any relevant route lookups. Are they using standard routing tables, or something more specialized for SRv6? Are there any optimizations, such as caching, for frequent segments? I'll be looking for potential race conditions or locking issues that could arise from concurrent processing. Also, I'll be interested in how error handling is implemented; how are bad segments handled and reported? * **Lines 435-460:** Now, this chunk probably relates to some sort of control path logic or policy enforcement. Could be SID table management, perhaps adding, deleting, or modifying local SIDs. I'd anticipate seeing functions for interacting with netlink, or some other interface used for configuring the SRv6 local segment. I'll pay close attention to the security aspects. Are there checks for permissions or malicious configuration attempts? Is there proper validation of inputs? I'm curious about the interaction with the routing daemon (e.g., Bird, FRR) -- does this section update the routing tables directly, or send events to trigger route updates? Are there any interesting control plane features (e.g., SRv6 policies)? * **Lines 1566-1590:** This feels like it might be the "exit" or "final" stage of packet processing related to SRv6. After all the local SID handling is done, this code may determine the next hop, apply any necessary header manipulations, and send it out on the wire. I expect to see integration with the IPv6 header structure (e.g., updating the Segment Routing Header). How efficient is this final packet transmission? Are there any specific optimizations for performance or for the data-path? Are there any potential issues that could cause significant delay or loss during this process? |
| 18/2 | 2026/11/01 14:17 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_local.c",
"FirstLine": 290,
"LineCount": 45
}Results: {
"Contents": " 290:\tstatic struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,\n 291:\t\t\t\t\t\t struct ipv6_sr_hdr *srh,\n 292:\t\t\t\t\t\t enum skb_drop_reason *reason)\n 293:\t{\n 294:\t\tstruct in6_addr *daddr;\n 295:\t\tstruct in6_addr *addr;\n 296:\t\t__be32 old;\n 297:\t\tint srhoff;\n 298:\t\tint wlen;\n 299:\t\n 300:\t\tsrhoff = (unsigned char *)srh - skb-\u003edata;\n 301:\t\t/* we write only the Segment Left field and the IPv6 DA. The segment\n 302:\t\t * list is only read, and seg6_get_srh() already pulled it into the\n 303:\t\t * linear area.\n 304:\t\t */\n 305:\t\twlen = srhoff + sizeof(*srh);\n 306:\t\n 307:\t\tif (unlikely(skb_ensure_writable(skb, wlen))) {\n 308:\t\t\t*reason = SKB_DROP_REASON_NOMEM;\n 309:\t\t\treturn NULL;\n 310:\t\t}\n 311:\t\n 312:\t\t/* skb_ensure_writable() may change skb pointers; evaluate srh again */\n 313:\t\tsrh = (struct ipv6_sr_hdr *)(skb-\u003edata + srhoff);\n 314:\t\tdaddr = \u0026ipv6_hdr(skb)-\u003edaddr;\n 315:\t\t/* nexthdr, hdrlen, type and segments_left */\n 316:\t\told = *(__be32 *)srh;\n 317:\t\n 318:\t\tsrh-\u003esegments_left--;\n 319:\t\taddr = srh-\u003esegments + srh-\u003esegments_left;\n 320:\t\n 321:\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE) {\n 322:\t\t\tupdate_csum_diff4(skb, old, *(__be32 *)srh);\n 323:\t\t\tupdate_csum_diff16(skb, (__be32 *)daddr, (__be32 *)addr);\n 324:\t\t}\n 325:\t\n 326:\t\t*daddr = *addr;\n 327:\t\n 328:\t\treturn srh;\n 329:\t}\n 330:\t\n 331:\tstatic int\n 332:\tseg6_lookup_any_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,\n 333:\t\t\t\tu32 tbl_id, bool local_delivery, int oif)\n 334:\t{\n"
} |
| 19/2 | 2026/11/01 14:17 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 23473 output: 39 thoughts: 30 Thoughts: Okay, here's my interpretation of those thoughts, crafted with the understanding that I'm speaking to a fellow expert: **Diving Deeper: Exploring `seg6_next_csid_advance_arg` and `input_action_end_bpf`** Right, so we're focusing on some key areas here, and I'm immediately thinking about how `seg6_next_csid_advance_arg` and `input_action_end_bpf` fit into the larger picture. I'm already anticipating the nuances involved in their interaction, and how they likely play a critical role in the flow and handling. Specifically, I want to consider how these elements are connected and how their individual functions contribute to the overall performance and outcome. Let's delve in to the details. |
| 20/2 | 2026/11/01 14:17 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_local.c",
"FirstLine": 430,
"LineCount": 35
}Results: {
"Contents": " 430:\t * This function returns:\n 431:\t * - SKB_NOT_DROPPED_YET on success;\n 432:\t * - SKB_DROP_REASON_NOMEM when the skb cannot be made writable.\n 433:\t */\n 434:\tstatic enum skb_drop_reason\n 435:\tseg6_next_csid_advance_arg(struct sk_buff *skb,\n 436:\t\t\t\t const struct seg6_flavors_info *finfo)\n 437:\t{\n 438:\t\t__u8 fnc_octects = seg6_flv_lcnode_func_octects(finfo);\n 439:\t\t__u8 blk_octects = seg6_flv_lcblock_octects(finfo);\n 440:\t\tstruct in6_addr *addr;\n 441:\t\tstruct in6_addr old;\n 442:\t\n 443:\t\tif (unlikely(skb_ensure_writable(skb, sizeof(struct ipv6hdr))))\n 444:\t\t\treturn SKB_DROP_REASON_NOMEM;\n 445:\t\n 446:\t\taddr = \u0026ipv6_hdr(skb)-\u003edaddr;\n 447:\t\told = *addr;\n 448:\t\n 449:\t\t/* advance DA.Argument */\n 450:\t\tmemmove(\u0026addr-\u003es6_addr[blk_octects],\n 451:\t\t\t\u0026addr-\u003es6_addr[blk_octects + fnc_octects],\n 452:\t\t\t16 - blk_octects - fnc_octects);\n 453:\t\n 454:\t\tmemset(\u0026addr-\u003es6_addr[16 - fnc_octects], 0x00, fnc_octects);\n 455:\t\n 456:\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\n 457:\t\t\tupdate_csum_diff16(skb, (__be32 *)\u0026old, (__be32 *)addr);\n 458:\t\n 459:\t\treturn SKB_NOT_DROPPED_YET;\n 460:\t}\n 461:\t\n 462:\tstatic int input_action_end_finish(struct sk_buff *skb,\n 463:\t\t\t\t\t struct seg6_local_lwt *slwt)\n 464:\t{\n"
} |
| 21/2 | 2026/11/01 14:17 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 24350 output: 40 thoughts: 15 Thoughts: Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person: **Analyzing `input_action_end_bpf`** Right, let's dive into this `input_action_end_bpf` code. I'm assuming, based on the naming convention, this is related to some form of BPF-based input handling, specifically the conclusion of an action. My first questions immediately revolve around its context: What's the triggering mechanism? Is it a hardware interrupt, a timer, or some kind of software signal? Understanding the event that *causes* this function to execute is crucial for proper analysis. Next, I need to look at the data structures it's interacting with. Is it modifying shared memory regions? Are there any locks involved? Data races are a plague, and BPF is particularly susceptible due to its potential for concurrent execution and limited built-in safety mechanisms. I'll need to scrutinize any accesses to shared variables, paying close attention to atomicity and memory barriers if the target system is multi-core. The BPF program itself... that's where the real complexity lies. I'll have to disassemble it to understand the exact bytecode instructions. I’m thinking I will need to look for calls to helper functions as well. I need to trace the control flow to determine what actions are happening upon the "end" event. I want to look for anything that might represent a state transition, resource release, or message queue update. Is it updating any counters or statistics? Does it have implications for performance? Is there any potential for denial of service? Error handling must be critical. I'll also be asking what kind of memory model is in play. I need to ascertain if the eBPF code adheres to any architectural constraints for efficiency and safety. Furthermore, I need to know how the eBPF program is verified and loaded. Are there any potential vulnerabilities related to the loading process itself? Could malicious code be injected? What's the sandboxing strategy, and how effective is it in preventing unauthorized actions? Finally, the larger context. This function doesn't exist in a vacuum. What are the dependencies? What other parts of the system rely on the actions triggered by `input_action_end_bpf`? Understanding the "before" and "after" picture is as important as the function itself to fully grasping its function within the entire system. |
| 22/2 | 2026/11/01 14:17 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_local.c",
"FirstLine": 1560,
"LineCount": 40
}Results: {
"Contents": "1560:\t\t * statement. It is also accessed by the bpf_lwt_seg6_* helpers via\n1561:\t\t * bpf_prog_run_save_cb().\n1562:\t\t */\n1563:\t\tlocal_lock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\n1564:\t\tsrh_state = this_cpu_ptr(\u0026seg6_bpf_srh_states);\n1565:\t\tsrh_state-\u003esrh = srh;\n1566:\t\tsrh_state-\u003ehdrlen = srh-\u003ehdrlen \u003c\u003c 3;\n1567:\t\tsrh_state-\u003evalid = true;\n1568:\t\n1569:\t\trcu_read_lock();\n1570:\t\tbpf_compute_data_pointers(skb);\n1571:\t\tret = bpf_prog_run_save_cb(slwt-\u003ebpf.prog, skb);\n1572:\t\trcu_read_unlock();\n1573:\t\n1574:\t\tswitch (ret) {\n1575:\t\tcase BPF_OK:\n1576:\t\tcase BPF_REDIRECT:\n1577:\t\t\tbreak;\n1578:\t\tcase BPF_DROP:\n1579:\t\t\tgoto drop;\n1580:\t\tdefault:\n1581:\t\t\tpr_warn_once(\"bpf-seg6local: Illegal return value %u\\n\", ret);\n1582:\t\t\tgoto drop;\n1583:\t\t}\n1584:\t\n1585:\t\t/* The program may have changed the packet and seg6_bpf_has_valid_srh()\n1586:\t\t * may rewrite the SRH Hdr Ext Len below.\n1587:\t\t * skb-\u003ecsum may then no longer be the checksum of the full packet.\n1588:\t\t */\n1589:\t\tskb_checksum_complete_unset(skb);\n1590:\t\n1591:\t\tif (srh_state-\u003esrh \u0026\u0026 !seg6_bpf_has_valid_srh(skb))\n1592:\t\t\tgoto drop;\n1593:\t\tlocal_unlock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\n1594:\t\n1595:\t\tif (ret != BPF_REDIRECT)\n1596:\t\t\tseg6_lookup_nexthop(skb, NULL, 0);\n1597:\t\n1598:\t\treturn dst_input(skb);\n1599:\t\n"
} |
| 23/2 | 2026/11/01 14:17 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 25582 output: 40 thoughts: 1074 Thoughts: **Focusing on IPv6 SRv6 for Fuzzing** Okay, so I'm looking at some code related to core networking, specifically IPv6 Segment Routing (SRv6) – this is about handling IPv6 routing headers, lightweight tunnels, and such. The good news is, this stuff is definitely reachable in virtualized environments like QEMU and GCE, which is a major win for fuzzing. We're talking pure software protocol handling SRv6, triggered through standard sockets and netlink interfaces. Syzkaller is known for generating and heavily testing these scenarios, which solidifies its relevance. Now, let's go through the triage criteria. The patch definitely touches reachable, executable code. It's in core networking, so according to the criteria, it's WorthFuzzing=true. The next question is preventing the fuzzer from being diluted. I need to extract "FocusSymbols" – this means identifying specific kernel functions to guide the fuzzer away from ubiquitous lifecycle paths and towards the *actual* logic being modified. No generic allocators or synchronization primitives here, we're after the feature-specific stuff. I've got `update_csum_diff4` and `update_csum_diff16` in `include/net/seg6.h`. They are static inline functions. Their caller is `seg6_update_csum` which is also static. It is called by `ipv6_srh_rcv`. And, crucially, `ipv6_srh_rcv` is the handler registered for `IPPROTO_ROUTING`, which makes it a critical entrypoint. So I'll definitely list `ipv6_srh_rcv`. Now for the other static inline functions and static helpers: `seg6_do_srh`, `advance_nextseg`, `seg6_next_csid_advance_arg`, and `input_action_end_bpf`. They call the modified inline functions or are entrypoints or implement feature-specific logic. So, let's explore `net/ipv6/seg6_iptunnel.c` and `net/ipv6/seg6_local.c` to identify any non-static functions, or entrypoints that would be suitable FocusSymbols for the fuzzer. These are the key candidates to keep the fuzzing effort focused. |
| 24/2 | 2026/11/01 14:18 | tool | grepper |
0mArgs:{
"Expression": "seg6_do_srh",
"PathPrefixes": [
"net/ipv6/seg6_iptunnel.c"
]
}Results: {
"Output": "net/ipv6/seg6_iptunnel.c=124=static __be32 seg6_make_flowlabel(struct net *net, struct sk_buff *skb,\n--\nnet/ipv6/seg6_iptunnel.c-140-\nnet/ipv6/seg6_iptunnel.c:141:static int __seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,\nnet/ipv6/seg6_iptunnel.c-142-\t\t\t int proto, struct dst_entry *cache_dst,\n--\nnet/ipv6/seg6_iptunnel.c-217-/* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */\nnet/ipv6/seg6_iptunnel.c:218:int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)\nnet/ipv6/seg6_iptunnel.c-219-{\nnet/ipv6/seg6_iptunnel.c:220:\treturn __seg6_do_srh_encap(skb, osrh, proto, NULL, NULL);\nnet/ipv6/seg6_iptunnel.c-221-}\nnet/ipv6/seg6_iptunnel.c:222:EXPORT_SYMBOL_GPL(seg6_do_srh_encap);\nnet/ipv6/seg6_iptunnel.c-223-\nnet/ipv6/seg6_iptunnel.c-224-/* encapsulate an IPv6 packet within an outer IPv6 header with reduced SRH */\nnet/ipv6/seg6_iptunnel.c:225:static int seg6_do_srh_encap_red(struct sk_buff *skb,\nnet/ipv6/seg6_iptunnel.c-226-\t\t\t\t struct ipv6_sr_hdr *osrh, int proto,\n--\nnet/ipv6/seg6_iptunnel.c-269-\nnet/ipv6/seg6_iptunnel.c:270:\t/* based on seg6_do_srh_encap() */\nnet/ipv6/seg6_iptunnel.c-271-\tif (skb-\u003eprotocol == htons(ETH_P_IPV6)) {\n--\nnet/ipv6/seg6_iptunnel.c-344-\nnet/ipv6/seg6_iptunnel.c:345:static int __seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,\nnet/ipv6/seg6_iptunnel.c-346-\t\t\t\tstruct dst_entry *cache_dst)\n--\nnet/ipv6/seg6_iptunnel.c-397-\nnet/ipv6/seg6_iptunnel.c:398:static int seg6_do_srh(struct sk_buff *skb, struct dst_entry *cache_dst)\nnet/ipv6/seg6_iptunnel.c-399-{\n--\nnet/ipv6/seg6_iptunnel.c-413-\nnet/ipv6/seg6_iptunnel.c:414:\t\terr = __seg6_do_srh_inline(skb, tinfo-\u003esrh, cache_dst);\nnet/ipv6/seg6_iptunnel.c-415-\t\tif (err)\n--\nnet/ipv6/seg6_iptunnel.c-431-\t\tif (tinfo-\u003emode == SEG6_IPTUN_MODE_ENCAP)\nnet/ipv6/seg6_iptunnel.c:432:\t\t\terr = __seg6_do_srh_encap(skb, tinfo-\u003esrh, proto,\nnet/ipv6/seg6_iptunnel.c-433-\t\t\t\t\t\t cache_dst, \u0026slwt-\u003etunsrc);\nnet/ipv6/seg6_iptunnel.c-434-\t\telse\nnet/ipv6/seg6_iptunnel.c:435:\t\t\terr = seg6_do_srh_encap_red(skb, tinfo-\u003esrh, proto,\nnet/ipv6/seg6_iptunnel.c-436-\t\t\t\t\t\t cache_dst, \u0026slwt-\u003etunsrc);\n--\nnet/ipv6/seg6_iptunnel.c-461-\t\tif (tinfo-\u003emode == SEG6_IPTUN_MODE_L2ENCAP)\nnet/ipv6/seg6_iptunnel.c:462:\t\t\terr = __seg6_do_srh_encap(skb, tinfo-\u003esrh,\nnet/ipv6/seg6_iptunnel.c-463-\t\t\t\t\t\t IPPROTO_ETHERNET, cache_dst,\n--\nnet/ipv6/seg6_iptunnel.c-465-\t\telse\nnet/ipv6/seg6_iptunnel.c:466:\t\t\terr = seg6_do_srh_encap_red(skb, tinfo-\u003esrh,\nnet/ipv6/seg6_iptunnel.c-467-\t\t\t\t\t\t IPPROTO_ETHERNET, cache_dst,\n--\nnet/ipv6/seg6_iptunnel.c-483-/* insert an SRH within an IPv6 packet, just after the IPv6 header */\nnet/ipv6/seg6_iptunnel.c:484:int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)\nnet/ipv6/seg6_iptunnel.c-485-{\nnet/ipv6/seg6_iptunnel.c:486:\treturn __seg6_do_srh_inline(skb, osrh, NULL);\nnet/ipv6/seg6_iptunnel.c-487-}\nnet/ipv6/seg6_iptunnel.c:488:EXPORT_SYMBOL_GPL(seg6_do_srh_inline);\nnet/ipv6/seg6_iptunnel.c-489-\n--\nnet/ipv6/seg6_iptunnel.c=563=static int seg6_input_core(struct net *net, struct sock *sk,\n--\nnet/ipv6/seg6_iptunnel.c-584-\nnet/ipv6/seg6_iptunnel.c:585:\terr = seg6_do_srh(skb, dst);\nnet/ipv6/seg6_iptunnel.c-586-\tif (unlikely(err)) {\n--\nnet/ipv6/seg6_iptunnel.c=673=static int seg6_output_core(struct net *net, struct sock *sk,\n--\nnet/ipv6/seg6_iptunnel.c-686-\nnet/ipv6/seg6_iptunnel.c:687:\terr = seg6_do_srh(skb, dst);\nnet/ipv6/seg6_iptunnel.c-688-\tif (unlikely(err))\n"
} |
| 25/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 28921 output: 40 thoughts: 70 Thoughts: Here's my summary, as if I were thinking it: **Diving into the SEG6 IPTunnel Code** Okay, time to get my hands dirty with this SEG6 IPTunnel implementation. My focus is the `net/ipv6/seg6_iptunnel.c` file. Specifically, I need to get a handle on how the core operations are handled, the ingress and egress of packets. Let's see... I'm thinking I'll start by examining the exported operations, `seg6_input` and `seg6_output`. That's always a solid way to start, right? They'll be the entry points I'm after. And I bet the action happens somewhere in the region of lines 580 to 690. I'm going to scan that section for now. |
| 26/2 | 2026/11/01 14:18 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_iptunnel.c",
"FirstLine": 580,
"LineCount": 60
}Results: {
"Contents": " 580:\t\n 581:\t\tlocal_bh_disable();\n 582:\t\tdst = dst_cache_get(\u0026slwt-\u003ecache_input);\n 583:\t\tlocal_bh_enable();\n 584:\t\n 585:\t\terr = seg6_do_srh(skb, dst);\n 586:\t\tif (unlikely(err)) {\n 587:\t\t\tdst_release(dst);\n 588:\t\t\tgoto drop;\n 589:\t\t}\n 590:\t\n 591:\t\tif (unlikely(!dst)) {\n 592:\t\t\tdst = seg6_input_route(net, skb, slwt);\n 593:\t\t\tif (!dst) {\n 594:\t\t\t\terr = -ENETUNREACH;\n 595:\t\t\t\tgoto drop;\n 596:\t\t\t}\n 597:\t\n 598:\t\t\t/* cache only if we don't create a dst reference loop */\n 599:\t\t\tif (!dst-\u003eerror \u0026\u0026 lwtst != dst-\u003elwtstate) {\n 600:\t\t\t\tlocal_bh_disable();\n 601:\t\t\t\tdst_cache_set_ip6(\u0026slwt-\u003ecache_input, dst,\n 602:\t\t\t\t\t\t \u0026ipv6_hdr(skb)-\u003esaddr);\n 603:\t\t\t\tlocal_bh_enable();\n 604:\t\t\t}\n 605:\t\n 606:\t\t\terr = skb_cow_head(skb, LL_RESERVED_SPACE(dst_dev(dst)));\n 607:\t\t\tif (unlikely(err))\n 608:\t\t\t\tgoto drop;\n 609:\t\t} else {\n 610:\t\t\tskb_dst_drop(skb);\n 611:\t\t\tskb_dst_set(skb, dst);\n 612:\t\t}\n 613:\t\n 614:\t\tif (static_branch_unlikely(\u0026nf_hooks_lwtunnel_enabled))\n 615:\t\t\treturn NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,\n 616:\t\t\t\t dev_net(skb-\u003edev), NULL, skb, NULL,\n 617:\t\t\t\t skb_dst_dev(skb), seg6_input_finish);\n 618:\t\n 619:\t\treturn seg6_input_finish(dev_net(skb-\u003edev), NULL, skb);\n 620:\tdrop:\n 621:\t\tkfree_skb(skb);\n 622:\t\treturn err;\n 623:\t}\n 624:\t\n 625:\tstatic int seg6_input_nf(struct sk_buff *skb)\n 626:\t{\n 627:\t\tstruct net_device *dev = skb_dst_dev(skb);\n 628:\t\tstruct net *net = dev_net(skb-\u003edev);\n 629:\t\n 630:\t\tswitch (skb-\u003eprotocol) {\n 631:\t\tcase htons(ETH_P_IP):\n 632:\t\t\treturn NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, net, NULL,\n 633:\t\t\t\t skb, NULL, dev, seg6_input_core);\n 634:\t\tcase htons(ETH_P_IPV6):\n 635:\t\t\treturn NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, net, NULL,\n 636:\t\t\t\t skb, NULL, dev, seg6_input_core);\n 637:\t\t}\n 638:\t\n 639:\t\treturn -EINVAL;\n"
} |
| 27/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 30151 output: 40 thoughts: 25 Thoughts: Okay, let's dive into this code. I need to get a handle on how these segments are defined, specifically `seg6_input` and `seg6_output`. I remember seeing them around line 640, so that's where I'll start my investigation. Understanding their definitions is critical to grasping how the data flow is being handled at that point in the process. I'll need to look closely at the structure and any associated variables or calculations. This seems like a critical area to comprehend before I delve any deeper into the code. |
| 28/2 | 2026/11/01 14:18 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_iptunnel.c",
"FirstLine": 640,
"LineCount": 60
}Results: {
"Contents": " 640:\t}\n 641:\t\n 642:\tstatic int seg6_input(struct sk_buff *skb)\n 643:\t{\n 644:\t\tif (static_branch_unlikely(\u0026nf_hooks_lwtunnel_enabled))\n 645:\t\t\treturn seg6_input_nf(skb);\n 646:\t\n 647:\t\treturn seg6_input_core(dev_net(skb-\u003edev), NULL, skb);\n 648:\t}\n 649:\t\n 650:\t/* look up the route for the first SID on the output path. Always returns a\n 651:\t * refcounted dst.\n 652:\t */\n 653:\tstatic struct dst_entry *seg6_output_dst_lookup(struct net *net,\n 654:\t\t\t\t\t\t\tstruct sk_buff *skb,\n 655:\t\t\t\t\t\t\tstruct flowi6 *fl6,\n 656:\t\t\t\t\t\t\tstruct seg6_lwt *slwt)\n 657:\t{\n 658:\t\tstruct dst_entry *dst;\n 659:\t\n 660:\t\tif (slwt-\u003etable) {\n 661:\t\t\tdst = seg6_table_lookup(net, skb, fl6, slwt-\u003etable);\n 662:\t\t\tif (!dst) {\n 663:\t\t\t\tdst = \u0026net-\u003eipv6.ip6_blk_hole_entry-\u003edst;\n 664:\t\t\t\tdst_hold(dst);\n 665:\t\t\t}\n 666:\t\t} else {\n 667:\t\t\tdst = ip6_route_output(net, NULL, fl6);\n 668:\t\t}\n 669:\t\n 670:\t\treturn dst;\n 671:\t}\n 672:\t\n 673:\tstatic int seg6_output_core(struct net *net, struct sock *sk,\n 674:\t\t\t\t struct sk_buff *skb)\n 675:\t{\n 676:\t\tstruct dst_entry *orig_dst = skb_dst(skb);\n 677:\t\tstruct dst_entry *dst = NULL;\n 678:\t\tstruct seg6_lwt *slwt;\n 679:\t\tint err;\n 680:\t\n 681:\t\tslwt = seg6_lwt_lwtunnel(orig_dst-\u003elwtstate);\n 682:\t\n 683:\t\tlocal_bh_disable();\n 684:\t\tdst = dst_cache_get(\u0026slwt-\u003ecache_output);\n 685:\t\tlocal_bh_enable();\n 686:\t\n 687:\t\terr = seg6_do_srh(skb, dst);\n 688:\t\tif (unlikely(err))\n 689:\t\t\tgoto drop;\n 690:\t\n 691:\t\tif (unlikely(!dst)) {\n 692:\t\t\tstruct ipv6hdr *hdr = ipv6_hdr(skb);\n 693:\t\t\tstruct flowi6 fl6;\n 694:\t\n 695:\t\t\tseg6_init_flowi6(skb, hdr, \u0026fl6);\n 696:\t\n 697:\t\t\tdst = seg6_output_dst_lookup(net, skb, \u0026fl6, slwt);\n 698:\t\t\tif (dst-\u003eerror) {\n 699:\t\t\t\terr = dst-\u003eerror;\n"
} |
| 29/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 31222 output: 57 thoughts: 74 Thoughts: Here's my summary, as the expert: **Investigating SEG6 Local Code Paths** Alright, time to dig into the `net/ipv6/seg6_local.c` file. I need to understand the control flow here, particularly around how the segment routing process works at the local endpoint. Specifically, I'm trying to trace the execution paths of a few key functions: `advance_nextseg`, `seg6_next_csid_advance_arg`, and `input_action_end_bpf`. To get a handle on this, I'm going to run a quick `grep` within that file to see exactly where those functions are called. That should give me a good starting point for mapping out the critical points in this module. From there, I'll be able to work backward and forward, getting the context for each of these functions to trace the program's operations. |
| 30/2 | 2026/11/01 14:18 | tool | grepper |
0mArgs:{
"Expression": "advance_nextseg|seg6_next_csid_advance_arg|input_action_end_bpf",
"PathPrefixes": [
"net/ipv6/seg6_local.c"
]
}Results: {
"Output": "net/ipv6/seg6_local.c=232=static bool decap_and_validate(struct sk_buff *skb, int proto)\n--\nnet/ipv6/seg6_local.c-289- */\nnet/ipv6/seg6_local.c:290:static struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,\nnet/ipv6/seg6_local.c-291-\t\t\t\t\t struct ipv6_sr_hdr *srh,\n--\nnet/ipv6/seg6_local.c=434=static enum skb_drop_reason\nnet/ipv6/seg6_local.c:435:seg6_next_csid_advance_arg(struct sk_buff *skb,\nnet/ipv6/seg6_local.c-436-\t\t\t const struct seg6_flavors_info *finfo)\n--\nnet/ipv6/seg6_local.c=470=static int input_action_end_core(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-480-\nnet/ipv6/seg6_local.c:481:\tsrh = advance_nextseg(skb, srh, \u0026reason);\nnet/ipv6/seg6_local.c-482-\tif (!srh) {\n--\nnet/ipv6/seg6_local.c=494=static int end_next_csid_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)\n--\nnet/ipv6/seg6_local.c-503-\t/* update DA */\nnet/ipv6/seg6_local.c:504:\treason = seg6_next_csid_advance_arg(skb, finfo);\nnet/ipv6/seg6_local.c-505-\tif (reason) {\n--\nnet/ipv6/seg6_local.c=521=static int input_action_end_x_core(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-531-\nnet/ipv6/seg6_local.c:532:\tsrh = advance_nextseg(skb, srh, \u0026reason);\nnet/ipv6/seg6_local.c-533-\tif (!srh) {\n--\nnet/ipv6/seg6_local.c=545=static int end_x_next_csid_core(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-555-\t/* update DA */\nnet/ipv6/seg6_local.c:556:\treason = seg6_next_csid_advance_arg(skb, finfo);\nnet/ipv6/seg6_local.c-557-\tif (reason) {\n--\nnet/ipv6/seg6_local.c=845=static int end_flv8986_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)\n--\nnet/ipv6/seg6_local.c-875-\t\t/* process the packet as the \"standard\" End behavior */\nnet/ipv6/seg6_local.c:876:\t\tsrh = advance_nextseg(skb, srh, \u0026reason);\nnet/ipv6/seg6_local.c-877-\t\tif (!srh) {\n--\nnet/ipv6/seg6_local.c-882-\tcase SEG6_LOCAL_FLV_ACT_PSP:\nnet/ipv6/seg6_local.c:883:\t\tsrh = advance_nextseg(skb, srh, \u0026reason);\nnet/ipv6/seg6_local.c-884-\t\tif (!srh) {\n--\nnet/ipv6/seg6_local.c=942=static int input_action_end_t(struct sk_buff *skb, struct seg6_local_lwt *slwt)\n--\nnet/ipv6/seg6_local.c-951-\nnet/ipv6/seg6_local.c:952:\tsrh = advance_nextseg(skb, srh, \u0026reason);\nnet/ipv6/seg6_local.c-953-\tif (!srh) {\n--\nnet/ipv6/seg6_local.c=1475=static int input_action_end_b6_encap(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-1485-\nnet/ipv6/seg6_local.c:1486:\tsrh = advance_nextseg(skb, srh, \u0026reason);\nnet/ipv6/seg6_local.c-1487-\tif (!srh) {\n--\nnet/ipv6/seg6_local.c=1514=bool seg6_bpf_has_valid_srh(struct sk_buff *skb)\n--\nnet/ipv6/seg6_local.c-1537-\nnet/ipv6/seg6_local.c:1538:static int input_action_end_bpf(struct sk_buff *skb,\nnet/ipv6/seg6_local.c-1539-\t\t\t\tstruct seg6_local_lwt *slwt)\n--\nnet/ipv6/seg6_local.c-1550-\t}\nnet/ipv6/seg6_local.c:1551:\tsrh = advance_nextseg(skb, srh, \u0026reason);\nnet/ipv6/seg6_local.c-1552-\tif (!srh) {\n--\nnet/ipv6/seg6_local.c=1606=static struct seg6_action_desc seg6_action_table[] = {\n--\nnet/ipv6/seg6_local.c-1700-\t\t.optattrs\t= SEG6_F_LOCAL_COUNTERS,\nnet/ipv6/seg6_local.c:1701:\t\t.input\t\t= input_action_end_bpf,\nnet/ipv6/seg6_local.c-1702-\t},\n"
} |
| 31/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 33092 output: 38 thoughts: 76 Thoughts: Okay, let's dive into this. Here's how I'd approach understanding the `seg6_local` processing flow: **Analyzing `seg6_local.c`** Alright, I need to get a clear picture of how this `seg6_local` module is integrated into the IPv6 networking stack. First, I'll zero in on `net/ipv6/seg6_local.c` and start by understanding how functions like `input_action_end_core` are called within it. I want to trace back from those calls to see where the packet processing originates and eventually reaches this module. I need to understand the control flow. To do that effectively, I'll need to identify the entry points. So, next, I'll search for references to something like `.input` within that file, or maybe specifically `seg6_local_input`. That's likely where the packet makes its initial entry or hooks into the processing chain within the module. Knowing that entry point will be crucial for understanding the overall data flow and how `seg6_local` interacts with the rest of the stack. I need to identify the key functions that handle the packet from ingress to processing. |
| 32/2 | 2026/11/01 14:18 | tool | grepper |
0mArgs:{
"Expression": "seg6_local_input",
"PathPrefixes": [
"net/ipv6/seg6_local.c"
]
}Results: {
"Output": "net/ipv6/seg6_local.c=1726=static void seg6_local_update_counters(struct seg6_local_lwt *slwt,\n--\nnet/ipv6/seg6_local.c-1743-\nnet/ipv6/seg6_local.c:1744:static int seg6_local_input_core(struct net *net, struct sock *sk,\nnet/ipv6/seg6_local.c-1745-\t\t\t\t struct sk_buff *skb)\n--\nnet/ipv6/seg6_local.c-1765-\nnet/ipv6/seg6_local.c:1766:static int seg6_local_input(struct sk_buff *skb)\nnet/ipv6/seg6_local.c-1767-{\n--\nnet/ipv6/seg6_local.c-1775-\t\t\t dev_net(skb-\u003edev), NULL, skb, skb-\u003edev, NULL,\nnet/ipv6/seg6_local.c:1776:\t\t\t seg6_local_input_core);\nnet/ipv6/seg6_local.c-1777-\nnet/ipv6/seg6_local.c:1778:\treturn seg6_local_input_core(dev_net(skb-\u003edev), NULL, skb);\nnet/ipv6/seg6_local.c-1779-}\n--\nnet/ipv6/seg6_local.c=2806=static const struct lwtunnel_encap_ops seg6_local_ops = {\n--\nnet/ipv6/seg6_local.c-2808-\t.destroy_state\t= seg6_local_destroy_state,\nnet/ipv6/seg6_local.c:2809:\t.input\t\t= seg6_local_input,\nnet/ipv6/seg6_local.c-2810-\t.fill_encap\t= seg6_local_fill_encap,\n"
} |
| 33/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 33964 output: 40 thoughts: 226 Thoughts: **Analyzing the Control Flow in `seg6_local.c`** Okay, so looking at this code in `net/ipv6/seg6_local.c`, specifically the `seg6_local_input_core` function, I'm tracing the action handlers. It's calling the action table's `.input` handler, which is then triggering a cascade of functions. I see `input_action_end_core`, `input_action_end_bpf`, `end_next_csid_core`, and others being invoked. Crucially, `advance_nextseg` is called by a variety of these "end" functions: `input_action_end_core`, `input_action_end_x_core`, `end_flv8986_core`, `input_action_end_t`, `input_action_end_b6_encap`, and `input_action_end_bpf`. This suggests `advance_nextseg` handles moving to the next segment after processing the current one. Similarly, `seg6_next_csid_advance_arg` is called by `end_next_csid_core` and `end_x_next_csid_core`, indicating this function handles advancement within the CSID. Now, I need to drill down into `seg6_local_input_core` to fully grasp the control flow and understand the broader picture. |
| 34/2 | 2026/11/01 14:18 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_local.c",
"FirstLine": 1740,
"LineCount": 30
}Results: {
"Contents": "1740:\t\n1741:\t\tu64_stats_update_end(\u0026pcounters-\u003esyncp);\n1742:\t}\n1743:\t\n1744:\tstatic int seg6_local_input_core(struct net *net, struct sock *sk,\n1745:\t\t\t\t\t struct sk_buff *skb)\n1746:\t{\n1747:\t\tstruct dst_entry *orig_dst = skb_dst(skb);\n1748:\t\tstruct seg6_action_desc *desc;\n1749:\t\tstruct seg6_local_lwt *slwt;\n1750:\t\tunsigned int len = skb-\u003elen;\n1751:\t\tint rc;\n1752:\t\n1753:\t\tslwt = seg6_local_lwtunnel(orig_dst-\u003elwtstate);\n1754:\t\tdesc = slwt-\u003edesc;\n1755:\t\n1756:\t\trc = desc-\u003einput(skb, slwt);\n1757:\t\n1758:\t\tif (!seg6_lwtunnel_counters_enabled(slwt))\n1759:\t\t\treturn rc;\n1760:\t\n1761:\t\tseg6_local_update_counters(slwt, len, rc);\n1762:\t\n1763:\t\treturn rc;\n1764:\t}\n1765:\t\n1766:\tstatic int seg6_local_input(struct sk_buff *skb)\n1767:\t{\n1768:\t\tif (skb-\u003eprotocol != htons(ETH_P_IPV6)) {\n1769:\t\t\tkfree_skb(skb);\n"
} |
| 35/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 34985 output: 34 thoughts: 61 Thoughts: Okay, let's dive into this. **Examining the IPv6 Source Routing Header Reception** Right, let's get down to brass tacks. I need to understand how IPv6 Source Routing Headers are handled, specifically the reception process. So, my initial focus is on `ipv6_srh_rcv` within `net/ipv6/exthdrs.c`. The obvious next step is to figure out how this function is integrated into the system. Therefore, I need to pinpoint exactly where `ipv6_srh_rcv` is registered. Back to `net/ipv6/exthdrs.c` it is. Let's see how this thing is hooked up. |
| 36/2 | 2026/11/01 14:18 | tool | grepper |
0mArgs:{
"Expression": "ipv6_srh_rcv",
"PathPrefixes": [
"net/ipv6/"
]
}Results: {
"Output": "net/ipv6/exthdrs.c=342=static void seg6_update_csum(struct sk_buff *skb)\n--\nnet/ipv6/exthdrs.c-370-\nnet/ipv6/exthdrs.c:371:static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\nnet/ipv6/exthdrs.c-372-{\n--\nnet/ipv6/exthdrs.c=653=static int ipv6_rthdr_rcv(struct sk_buff *skb)\n--\nnet/ipv6/exthdrs.c-691-\t\t\tgoto disabled;\nnet/ipv6/exthdrs.c:692:\t\treturn ipv6_srh_rcv(skb, idev);\nnet/ipv6/exthdrs.c-693-\tcase IPV6_SRCRT_TYPE_3:\n"
} |
| 37/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 35484 output: 39 thoughts: 34 Thoughts: Here's a breakdown of my thought process: **Diving into IPv6 Routing Header Handling** Okay, so `ipv6_rthdr_rcv`... that immediately triggers something in my mind: routing header! I need to understand this part of the IPv6 processing. My immediate instinct is to delve directly into the code of `ipv6_rthdr_rcv` itself. It's the designated handler, so it's the core of what I need to focus on right now. Let's see what's actually going on in there! |
| 38/2 | 2026/11/01 14:18 | tool | read-file |
0mArgs:{
"File": "net/ipv6/exthdrs.c",
"FirstLine": 650,
"LineCount": 55
}Results: {
"Contents": " 650:\t ********************************/\n 651:\t\n 652:\t/* called with rcu_read_lock() */\n 653:\tstatic int ipv6_rthdr_rcv(struct sk_buff *skb)\n 654:\t{\n 655:\t\tstruct inet6_dev *idev = __in6_dev_get(skb-\u003edev);\n 656:\t\tstruct inet6_skb_parm *opt = IP6CB(skb);\n 657:\t\tstruct in6_addr *addr = NULL;\n 658:\t\tint n, i;\n 659:\t\tstruct ipv6_rt_hdr *hdr;\n 660:\t\tstruct rt0_hdr *rthdr;\n 661:\t\tstruct net *net = dev_net(skb-\u003edev);\n 662:\t\tint accept_source_route;\n 663:\t\n 664:\t\taccept_source_route = READ_ONCE(net-\u003eipv6.devconf_all-\u003eaccept_source_route);\n 665:\t\n 666:\t\tif (idev)\n 667:\t\t\taccept_source_route = min(accept_source_route,\n 668:\t\t\t\t\t\t READ_ONCE(idev-\u003ecnf.accept_source_route));\n 669:\t\n 670:\t\tif (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||\n 671:\t\t !pskb_may_pull(skb, (skb_transport_offset(skb) +\n 672:\t\t\t\t\t ((skb_transport_header(skb)[1] + 1) \u003c\u003c 3)))) {\n 673:\t\t\t__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);\n 674:\t\t\tkfree_skb(skb);\n 675:\t\t\treturn -1;\n 676:\t\t}\n 677:\t\n 678:\t\thdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);\n 679:\t\n 680:\t\tif (ipv6_addr_is_multicast(\u0026ipv6_hdr(skb)-\u003edaddr) ||\n 681:\t\t skb-\u003epkt_type != PACKET_HOST) {\n 682:\t\t\t__IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);\n 683:\t\t\tkfree_skb(skb);\n 684:\t\t\treturn -1;\n 685:\t\t}\n 686:\t\n 687:\t\tswitch (hdr-\u003etype) {\n 688:\t\tcase IPV6_SRCRT_TYPE_4:\n 689:\t\t\t/* segment routing */\n 690:\t\t\tif (!idev)\n 691:\t\t\t\tgoto disabled;\n 692:\t\t\treturn ipv6_srh_rcv(skb, idev);\n 693:\t\tcase IPV6_SRCRT_TYPE_3:\n 694:\t\t\t/* rpl segment routing */\n 695:\t\t\tif (!idev)\n 696:\t\t\t\tgoto disabled;\n 697:\t\t\treturn ipv6_rpl_srh_rcv(skb, idev);\n 698:\t\tdefault:\n 699:\t\t\tbreak;\n 700:\t\t}\n 701:\t\n 702:\tlooped_back:\n 703:\t\tif (hdr-\u003esegments_left == 0) {\n 704:\t\t\tswitch (hdr-\u003etype) {\n"
} |
| 39/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 36592 output: 39 thoughts: 383 Thoughts: **Analyzing IPv6 Routing Header Reception** Okay, so I'm digging into how IPv6 routing headers are handled. I see that `ipv6_rthdr_rcv` is registered with the `inet6_protocol` structure, specifically with `.handler`. My initial thought is to check if `ipv6_srh_rcv` is inlined within `ipv6_rthdr_rcv`, but hold on, let's just compare them directly, even if one might be static. I'm trying to determine if either `ipv6_srh_rcv` or `ipv6_rthdr_rcv` deserves special attention – could either be a "FocusSymbol," something critical for a deeper dive? Now, I'm looking closely at `ipv6_srh_rcv`. I see this interesting block: skb_pull(skb, skb_transport_offset(skb)); goto looped_back; } Wait a second… `goto looped_back;`? That's not right. Doesn't `looped_back:` reside within `ipv6_rthdr_rcv`? This is a bit odd. Why is there a `goto` to a label in another function from within `ipv6_srh_rcv`? I'm going to quickly check lines 400-500 in `net/ipv6/exthdrs.c` to see if that helps clarify what's going on here. This jumps out as a potential area of concern. |
| 40/2 | 2026/11/01 14:18 | tool | read-file |
0mArgs:{
"File": "net/ipv6/exthdrs.c",
"FirstLine": 460,
"LineCount": 40
}Results: {
"Contents": " 460:\t\t}\n 461:\t\n 462:\t\tif (skb_dst_dev(skb)-\u003eflags \u0026 IFF_LOOPBACK) {\n 463:\t\t\t/* payload_len, nexthdr and hop_limit */\n 464:\t\t\t__be32 *hlim_word = (__be32 *)ipv6_hdr(skb) + 1;\n 465:\t\t\t__be32 old;\n 466:\t\n 467:\t\t\tif (ipv6_hdr(skb)-\u003ehop_limit \u003c= 1) {\n 468:\t\t\t\t__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);\n 469:\t\t\t\ticmpv6_send(skb, ICMPV6_TIME_EXCEED,\n 470:\t\t\t\t\t ICMPV6_EXC_HOPLIMIT, 0);\n 471:\t\t\t\tkfree_skb_reason(skb, SKB_DROP_REASON_IP_TTL_EXCEEDED);\n 472:\t\t\t\treturn -1;\n 473:\t\t\t}\n 474:\t\t\told = *hlim_word;\n 475:\t\t\tipv6_hdr(skb)-\u003ehop_limit--;\n 476:\t\n 477:\t\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\n 478:\t\t\t\tupdate_csum_diff4(skb, old, *hlim_word);\n 479:\t\n 480:\t\t\tskb_pull(skb, skb_transport_offset(skb));\n 481:\t\t\tgoto looped_back;\n 482:\t\t}\n 483:\t\n 484:\t\tdst_input(skb);\n 485:\t\n 486:\t\treturn -1;\n 487:\t}\n 488:\t\n 489:\tstatic int ipv6_rpl_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n 490:\t{\n 491:\t\tstruct ipv6_rpl_sr_hdr *hdr, *ohdr, *chdr;\n 492:\t\tstruct inet6_skb_parm *opt = IP6CB(skb);\n 493:\t\tstruct net *net = dev_net(skb-\u003edev);\n 494:\t\tstruct ipv6hdr *oldhdr;\n 495:\t\tunsigned int chdr_len;\n 496:\t\tunsigned char *buf;\n 497:\t\tint accept_rpl_seg;\n 498:\t\tint i, err;\n 499:\t\tu64 n = 0;\n"
} |
| 41/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 38040 output: 39 thoughts: 49 Thoughts: Okay, let me think this through... **Missing Link in the IPv6 SRH Reception Puzzle** Hold on a second! I'm pretty sure I remember dealing with a `looped_back` label in the IPv6 Segment Routing Header processing recently. But, I'm drawing a blank on its specific location within `ipv6_srh_rcv`. This just doesn't feel right. Let me check... I need to refresh my memory and pinpoint where that logic lives. Okay, let's open up `net/ipv6/exthdrs.c` and zero in on lines 400 through 450. That should contain the relevant code related to receiving and handling segment routing headers, and hopefully, I'll find my elusive `looped_back` label there. That should clear this right up and I can move on. |
| 42/2 | 2026/11/01 14:18 | tool | read-file |
0mArgs:{
"File": "net/ipv6/exthdrs.c",
"FirstLine": 400,
"LineCount": 50
}Results: {
"Contents": " 400:\t\n 401:\t\t\t\tskb_postpull_rcsum(skb, skb_network_header(skb),\n 402:\t\t\t\t\t\t skb_network_header_len(skb));\n 403:\t\t\t\tskb_pull(skb, offset);\n 404:\t\t\t\tskb_postpull_rcsum(skb, skb_transport_header(skb),\n 405:\t\t\t\t\t\t offset);\n 406:\t\n 407:\t\t\t\tskb_reset_network_header(skb);\n 408:\t\t\t\tskb_reset_transport_header(skb);\n 409:\t\t\t\tskb-\u003eencapsulation = 0;\n 410:\t\t\t\tif (hdr-\u003enexthdr == NEXTHDR_IPV4)\n 411:\t\t\t\t\tskb-\u003eprotocol = htons(ETH_P_IP);\n 412:\t\t\t\t__skb_tunnel_rx(skb, skb-\u003edev, net);\n 413:\t\n 414:\t\t\t\tnetif_rx(skb);\n 415:\t\t\t\treturn -1;\n 416:\t\t\t}\n 417:\t\n 418:\t\t\topt-\u003esrcrt = skb_network_header_len(skb);\n 419:\t\t\topt-\u003elastopt = opt-\u003esrcrt;\n 420:\t\t\tskb-\u003etransport_header += (hdr-\u003ehdrlen + 1) \u003c\u003c 3;\n 421:\t\t\topt-\u003enhoff = (\u0026hdr-\u003enexthdr) - skb_network_header(skb);\n 422:\t\n 423:\t\t\treturn 1;\n 424:\t\t}\n 425:\t\n 426:\t\tif (hdr-\u003esegments_left \u003e= (hdr-\u003ehdrlen \u003e\u003e 1)) {\n 427:\t\t\t__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);\n 428:\t\t\ticmpv6_param_prob(skb, ICMPV6_HDR_FIELD,\n 429:\t\t\t\t\t ((\u0026hdr-\u003esegments_left) -\n 430:\t\t\t\t\t skb_network_header(skb)));\n 431:\t\t\treturn -1;\n 432:\t\t}\n 433:\t\n 434:\t\tif (skb_cloned(skb)) {\n 435:\t\t\tif (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {\n 436:\t\t\t\t__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),\n 437:\t\t\t\t\t\tIPSTATS_MIB_OUTDISCARDS);\n 438:\t\t\t\tkfree_skb(skb);\n 439:\t\t\t\treturn -1;\n 440:\t\t\t}\n 441:\t\n 442:\t\t\thdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);\n 443:\t\t}\n 444:\t\n 445:\t\thdr-\u003esegments_left--;\n 446:\t\taddr = hdr-\u003esegments + hdr-\u003esegments_left;\n 447:\t\n 448:\t\tskb_push(skb, -skb_network_offset(skb));\n 449:\t\n"
} |
| 43/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 39140 output: 39 thoughts: 24 Thoughts: Okay, here's my interpretation of what's going on in those lines of `net/ipv6/exthdrs.c`, written as a first-person expert summary: **Analyzing IPv6 Extension Header Handling** Alright, let's dive into lines 380-400 of `net/ipv6/exthdrs.c`. From what I'm seeing, this section is all about the crucial process of parsing and handling IPv6 extension headers. We're right in the thick of how the kernel processes these headers that come after the IPv6 header itself, and it's essential for flexibility and supporting various functionalities like fragmentation, routing, and authentication. Essentially, I'm observing the core logic where the kernel's IPv6 stack is methodically examining each extension header present in a packet. I'm focusing on the `exthdrs_next_hdr()` function. It's essentially traversing the header chain. It seems like the code is delicately determining the type of the *next* header. It's carefully inspecting the "Next Header" field within each extension header to ascertain which type comes next. It's using this field to navigate through the chain: if it's a Hop-by-Hop, Destination Options, Routing, Fragmentation, Authentication, Encapsulating Security Payload, or Destination Options header, this determines the sequence. I'm interpreting that there's a strong emphasis on *safety* and *correctness* here. There's probably rigorous checking to ensure the header chain remains coherent, avoiding loops or invalid sequences which are critical for preventing attacks or processing errors. Ultimately, I realize that this is the pivotal part. It's the critical step in making sure the rest of the stack can understand the packet and deliver it or process it correctly. I can see the potential for vulnerabilities here, if the parsing or processing of these headers is mishandled. Malformed headers could be exploited to cause a denial-of-service or even allow for arbitrary code execution. It's this level of meticulous examination that makes me realize that it is the backbone of the entire IPv6 header chain processing. |
| 44/2 | 2026/11/01 14:18 | tool | read-file |
0mArgs:{
"File": "net/ipv6/exthdrs.c",
"FirstLine": 375,
"LineCount": 26
}Results: {
"Contents": " 375:\t\tstruct ipv6_sr_hdr *hdr;\n 376:\t\tstruct in6_addr *addr;\n 377:\t\tint accept_seg6;\n 378:\t\n 379:\t\thdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);\n 380:\t\n 381:\t\taccept_seg6 = min(READ_ONCE(net-\u003eipv6.devconf_all-\u003eseg6_enabled),\n 382:\t\t\t\t READ_ONCE(idev-\u003ecnf.seg6_enabled));\n 383:\t\n 384:\t\tif (!accept_seg6) {\n 385:\t\t\tkfree_skb(skb);\n 386:\t\t\treturn -1;\n 387:\t\t}\n 388:\t\n 389:\t#ifdef CONFIG_IPV6_SEG6_HMAC\n 390:\t\tif (!seg6_hmac_validate_skb(skb, hdr)) {\n 391:\t\t\tkfree_skb(skb);\n 392:\t\t\treturn -1;\n 393:\t\t}\n 394:\t#endif\n 395:\t\n 396:\tlooped_back:\n 397:\t\tif (hdr-\u003esegments_left == 0) {\n 398:\t\t\tif (hdr-\u003enexthdr == NEXTHDR_IPV6 || hdr-\u003enexthdr == NEXTHDR_IPV4) {\n 399:\t\t\t\tint offset = (hdr-\u003ehdrlen + 1) \u003c\u003c 3;\n 400:\t\n"
} |
| 45/2 | 2026/11/01 14:18 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 40062 output: 40 thoughts: 601 Thoughts: **Analyzing Potential Symbol Candidates in SEG6 Processing**
Okay, so I've confirmed that `looped_back` is indeed situated within `ipv6_srh_rcv`. Now I'm mentally tracing through the relevant code. In `net/ipv6/exthdrs.c`, I see `ipv6_srh_rcv` and `seg6_update_csum`. Over in `net/ipv6/seg6_iptunnel.c`, there's `seg6_do_srh`, and in `net/ipv6/seg6_local.c`, I've noted `advance_nextseg`, `seg6_next_csid_advance_arg`, and `input_action_end_bpf`.
My next step is to evaluate whether these are viable symbol candidates for further analysis. First, I need to check whether `ipv6_srh_rcv` is static and if it's inlined. It *is* static, but it's a sizable function – over 115 lines – so inlining is unlikely. Regardless, I should figure out what actually calls it: `ipv6_rthdr_rcv`.
Then, I'll examine `seg6_do_srh`. It's called by `seg6_input_core` and `seg6_output_core`. Good to know.
Next, `advance_nextseg`: it's invoked by `input_action_end_core`, `input_action_end_x_core`, `end_flv8986_core`, `input_action_end_t`, `input_action_end_b6_encap`, and `input_action_end_bpf`.
`seg6_next_csid_advance_arg` is called by `end_next_csid_core` and `end_x_next_csid_core`.
Now, the important one, `input_action_end_bpf`. This is a function pointer within `seg6_action_table`, so it's *definitely* not inlined. I should check `seg6_action_table` to confirm that.
Okay, let me check the `seg6_action_table` in `net/ipv6/seg6_local.c` around line 1606. Yes, it's there: `[SEG6_LOCAL_ACTION_END_BPF] = { .input = input_action_end_bpf, },`. Okay, all the info is in order.
|
| 46/2 | 2026/11/01 14:19 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_local.c",
"FirstLine": 1606,
"LineCount": 40
}Results: {
"Contents": "1606:\tstatic struct seg6_action_desc seg6_action_table[] = {\n1607:\t\t{\n1608:\t\t\t.action\t\t= SEG6_LOCAL_ACTION_END,\n1609:\t\t\t.attrs\t\t= 0,\n1610:\t\t\t.optattrs\t= SEG6_F_LOCAL_COUNTERS |\n1611:\t\t\t\t\t SEG6_F_LOCAL_FLAVORS,\n1612:\t\t\t.input\t\t= input_action_end,\n1613:\t\t},\n1614:\t\t{\n1615:\t\t\t.action\t\t= SEG6_LOCAL_ACTION_END_X,\n1616:\t\t\t.attrs\t\t= SEG6_F_ATTR(SEG6_LOCAL_NH6),\n1617:\t\t\t.optattrs\t= SEG6_F_LOCAL_COUNTERS |\n1618:\t\t\t\t\t SEG6_F_LOCAL_FLAVORS |\n1619:\t\t\t\t\t SEG6_F_ATTR(SEG6_LOCAL_OIF),\n1620:\t\t\t.input\t\t= input_action_end_x,\n1621:\t\t},\n1622:\t\t{\n1623:\t\t\t.action\t\t= SEG6_LOCAL_ACTION_END_T,\n1624:\t\t\t.attrs\t\t= SEG6_F_ATTR(SEG6_LOCAL_TABLE),\n1625:\t\t\t.optattrs\t= SEG6_F_LOCAL_COUNTERS,\n1626:\t\t\t.input\t\t= input_action_end_t,\n1627:\t\t},\n1628:\t\t{\n1629:\t\t\t.action\t\t= SEG6_LOCAL_ACTION_END_DX2,\n1630:\t\t\t.attrs\t\t= SEG6_F_ATTR(SEG6_LOCAL_OIF),\n1631:\t\t\t.optattrs\t= SEG6_F_LOCAL_COUNTERS,\n1632:\t\t\t.input\t\t= input_action_end_dx2,\n1633:\t\t},\n1634:\t\t{\n1635:\t\t\t.action\t\t= SEG6_LOCAL_ACTION_END_DX6,\n1636:\t\t\t.attrs\t\t= SEG6_F_ATTR(SEG6_LOCAL_NH6),\n1637:\t\t\t.optattrs\t= SEG6_F_LOCAL_COUNTERS,\n1638:\t\t\t.input\t\t= input_action_end_dx6,\n1639:\t\t},\n1640:\t\t{\n1641:\t\t\t.action\t\t= SEG6_LOCAL_ACTION_END_DX4,\n1642:\t\t\t.attrs\t\t= SEG6_F_ATTR(SEG6_LOCAL_NH4),\n1643:\t\t\t.optattrs\t= SEG6_F_LOCAL_COUNTERS,\n1644:\t\t\t.input\t\t= input_action_end_dx4,\n1645:\t\t},\n"
} |
| 47/2 | 2026/11/01 14:19 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 41978 output: 35 thoughts: 4307 Thoughts: **Focus Symbol and EnableConfig Analysis for SRv6 Patch** Alright, let's break this down. First, `input_action_end_bpf` is definitely a real symbol. The other functions referenced in the `seg6_action_table` are also address-taken, so they're all potential targets. The question is, which ones are *good* targets, and how do we avoid the fuzzing equivalent of shouting into a crowd? The guidance is clear: avoid the noise. Don't include functions that are part of the kernel's core plumbing. Instead, *target specific feature logic and entrypoints.* And figure out how to handle those static inline functions that lack distinct symbols. So, where are the changes? The following functions were directly modified in C files: 1. `ipv6_srh_rcv` in `net/ipv6/exthdrs.c` 2. `seg6_do_srh` in `net/ipv6/seg6_iptunnel.c` 3. `advance_nextseg` in `net/ipv6/seg6_local.c` 4. `seg6_next_csid_advance_arg` in `net/ipv6/seg6_local.c` 5. `input_action_end_bpf` in `net/ipv6/seg6_local.c` And, the following were modified in the patch, and call the changed inline functions: - `seg6_update_csum` (called by `ipv6_srh_rcv`) - `ipv6_srh_rcv` (directly added) - `advance_nextseg` (directly added) - `seg6_next_csid_advance_arg` (directly added) We've also got entry points: `seg6_local_input`, `seg6_input`, and `seg6_output`. These are likely important, but are they ubiquitous? No, they're part of Segment Routing over IPv6 (SRv6), so they are triggered only when SRv6 is in use. Now, which of these functions deserve the title "FocusSymbol?" Given the guidance, here's the initial list: * `ipv6_srh_rcv` and `ipv6_rthdr_rcv` - We'll include both since `ipv6_rthdr_rcv` handles IPv6 Routing Header packets (and `ipv6_srh_rcv` is the new SRH packet handler). * `seg6_do_srh` * `advance_nextseg` * `seg6_next_csid_advance_arg` * `input_action_end_bpf` * `seg6_local_input`, `seg6_input`, and `seg6_output` (the LWT entry points) Are there any enable configs we have to add to the fuzzing build? Well, everything hinges on `CONFIG_IPV6`. The relevant code is compiled in `net/ipv6/exthdrs.c`, which is included in `ipv6-y` and thus requires `CONFIG_IPV6`. |
| 48/2 | 2026/11/01 14:19 | tool | grepper |
0mArgs:{
"Expression": "CONFIG_.*",
"PathPrefixes": [
"net/ipv6/exthdrs.c"
]
}Results: {
"Output": "net/ipv6/exthdrs.c-42-#include \u003cnet/calipso.h\u003e\nnet/ipv6/exthdrs.c:43:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-44-#include \u003cnet/xfrm.h\u003e\n--\nnet/ipv6/exthdrs.c-47-#include \u003cnet/seg6.h\u003e\nnet/ipv6/exthdrs.c:48:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/exthdrs.c-49-#include \u003cnet/seg6_hmac.h\u003e\n--\nnet/ipv6/exthdrs.c=107=static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff);\nnet/ipv6/exthdrs.c:108:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-109-static bool ipv6_dest_hao(struct sk_buff *skb, int optoff);\n--\nnet/ipv6/exthdrs.c=114=static bool ip6_parse_tlv(bool hopbyhop,\n--\nnet/ipv6/exthdrs.c-197-\t\t\t\tswitch (nh[off]) {\nnet/ipv6/exthdrs.c:198:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-199-\t\t\t\tcase IPV6_TLV_HAO:\n--\nnet/ipv6/exthdrs.c-230-\nnet/ipv6/exthdrs.c:231:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-232-static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)\n--\nnet/ipv6/exthdrs.c=296=static int ipv6_destopt_rcv(struct sk_buff *skb)\n--\nnet/ipv6/exthdrs.c-299-\tstruct inet6_skb_parm *opt = IP6CB(skb);\nnet/ipv6/exthdrs.c:300:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-301-\t__u16 dstbuf;\n--\nnet/ipv6/exthdrs.c-321-\topt-\u003elastopt = opt-\u003edst1 = skb_network_header_len(skb);\nnet/ipv6/exthdrs.c:322:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-323-\tdstbuf = opt-\u003edst1;\n--\nnet/ipv6/exthdrs.c-329-\t\topt = IP6CB(skb);\nnet/ipv6/exthdrs.c:330:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-331-\t\topt-\u003enhoff = dstbuf;\n--\nnet/ipv6/exthdrs.c=371=static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n--\nnet/ipv6/exthdrs.c-388-\nnet/ipv6/exthdrs.c:389:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/exthdrs.c-390-\tif (!seg6_hmac_validate_skb(skb, hdr)) {\n--\nnet/ipv6/exthdrs.c=653=static int ipv6_rthdr_rcv(struct sk_buff *skb)\n--\nnet/ipv6/exthdrs.c-704-\t\tswitch (hdr-\u003etype) {\nnet/ipv6/exthdrs.c:705:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-706-\t\tcase IPV6_SRCRT_TYPE_2:\n--\nnet/ipv6/exthdrs.c-730-\tswitch (hdr-\u003etype) {\nnet/ipv6/exthdrs.c:731:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-732-\tcase IPV6_SRCRT_TYPE_2:\n--\nnet/ipv6/exthdrs.c-785-\tswitch (hdr-\u003etype) {\nnet/ipv6/exthdrs.c:786:#if IS_ENABLED(CONFIG_IPV6_MIP6)\nnet/ipv6/exthdrs.c-787-\tcase IPV6_SRCRT_TYPE_2:\n--\nnet/ipv6/exthdrs.c=1132=static u8 ipv6_push_rthdr4(struct sk_buff *skb, u8 proto,\n--\nnet/ipv6/exthdrs.c-1160-\nnet/ipv6/exthdrs.c:1161:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/exthdrs.c-1162-\tif (sr_has_hmac(sr_phdr)) {\n"
} |
| 49/2 | 2026/11/01 14:19 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 48395 output: 50 thoughts: 148 Thoughts: **Examining IPv6 Segmentation and eBPF in the Kernel** Okay, so I'm digging into some IPv6 code in the kernel. My initial observation is that `net/ipv6/exthdrs.c` is always compiled with `CONFIG_IPV6`, which makes sense. I need to understand the dependencies a bit better, however. My immediate thought is to consider `net/ipv6/seg6_iptunnel.c` and `net/ipv6/seg6_local.c`. A quick peek at `net/ipv6/Makefile` confirms that they are included when `CONFIG_IPV6_SEG6_LWTUNNEL` is set. Now, I'm especially interested in the relationship between these files and eBPF. I'm focusing on the `input_action_end_bpf` function in particular. To be thorough, I want to see if `input_action_end_bpf` is conditionally compiled based on any config options within `seg6_local.c`, which seems like the most likely place to find it. I'll check for any `#ifdef` guards surrounding that function in the source file. |
| 50/2 | 2026/11/01 14:19 | tool | grepper |
0mArgs:{
"Expression": "CONFIG_.*",
"PathPrefixes": [
"net/ipv6/seg6_local.c",
"net/ipv6/seg6_iptunnel.c"
]
}Results: {
"Output": "net/ipv6/seg6_iptunnel.c-25-#include \u003cnet/dst_cache.h\u003e\nnet/ipv6/seg6_iptunnel.c:26:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/seg6_iptunnel.c-27-#include \u003cnet/seg6_hmac.h\u003e\n--\nnet/ipv6/seg6_iptunnel.c=141=static int __seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,\n--\nnet/ipv6/seg6_iptunnel.c-201-\nnet/ipv6/seg6_iptunnel.c:202:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/seg6_iptunnel.c-203-\tif (sr_has_hmac(isrh)) {\n--\nnet/ipv6/seg6_iptunnel.c=225=static int seg6_do_srh_encap_red(struct sk_buff *skb,\n--\nnet/ipv6/seg6_iptunnel.c-328-\nnet/ipv6/seg6_iptunnel.c:329:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/seg6_iptunnel.c-330-\tif (unlikely(!skip_srh \u0026\u0026 sr_has_hmac(isrh))) {\n--\nnet/ipv6/seg6_iptunnel.c=345=static int __seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,\n--\nnet/ipv6/seg6_iptunnel.c-380-\nnet/ipv6/seg6_iptunnel.c:381:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/seg6_iptunnel.c-382-\tif (sr_has_hmac(isrh)) {\n--\nnet/ipv6/seg6_local.c-27-#include \u003cnet/ip_tunnels.h\u003e\nnet/ipv6/seg6_local.c:28:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/seg6_local.c-29-#include \u003cnet/seg6_hmac.h\u003e\n--\nnet/ipv6/seg6_local.c=187=struct seg6_local_lwt {\n--\nnet/ipv6/seg6_local.c-195-\tstruct bpf_lwt_prog bpf;\nnet/ipv6/seg6_local.c:196:#ifdef CONFIG_NET_L3_MASTER_DEV\nnet/ipv6/seg6_local.c-197-\tstruct seg6_end_dt_info dt_info;\n--\nnet/ipv6/seg6_local.c=216=static struct ipv6_sr_hdr *get_and_validate_srh(struct sk_buff *skb)\n--\nnet/ipv6/seg6_local.c-223-\nnet/ipv6/seg6_local.c:224:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/seg6_local.c-225-\tif (!seg6_hmac_validate_skb(skb, srh))\n--\nnet/ipv6/seg6_local.c=232=static bool decap_and_validate(struct sk_buff *skb, int proto)\n--\nnet/ipv6/seg6_local.c-240-\nnet/ipv6/seg6_local.c:241:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/seg6_local.c-242-\tif (srh \u0026\u0026 !seg6_hmac_validate_skb(skb, srh))\n--\nnet/ipv6/seg6_local.c=845=static int end_flv8986_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)\n--\nnet/ipv6/seg6_local.c-858-\tpinfo = seg6_get_srh_pktinfo(srh);\nnet/ipv6/seg6_local.c:859:#ifdef CONFIG_IPV6_SEG6_HMAC\nnet/ipv6/seg6_local.c-860-\tif (srh \u0026\u0026 !seg6_hmac_validate_skb(skb, srh))\n--\nnet/ipv6/seg6_local.c=1101=static int input_action_end_dx4(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-1124-\nnet/ipv6/seg6_local.c:1125:#ifdef CONFIG_NET_L3_MASTER_DEV\nnet/ipv6/seg6_local.c-1126-static struct net *fib6_config_get_net(const struct fib6_config *fib6_cfg)\n--\nnet/ipv6/seg6_local.c=1377=static int input_action_end_dt6(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-1385-\nnet/ipv6/seg6_local.c:1386:#ifdef CONFIG_NET_L3_MASTER_DEV\nnet/ipv6/seg6_local.c-1387-\tif (seg6_end_dt6_get_mode(slwt) == DT_LEGACY_MODE)\n--\nnet/ipv6/seg6_local.c-1418-\nnet/ipv6/seg6_local.c:1419:#ifdef CONFIG_NET_L3_MASTER_DEV\nnet/ipv6/seg6_local.c-1420-static int seg6_end_dt46_build(struct seg6_local_lwt *slwt, const void *cfg,\n--\nnet/ipv6/seg6_local.c=1606=static struct seg6_action_desc seg6_action_table[] = {\n--\nnet/ipv6/seg6_local.c-1649-\t\t.optattrs\t= SEG6_F_LOCAL_COUNTERS,\nnet/ipv6/seg6_local.c:1650:#ifdef CONFIG_NET_L3_MASTER_DEV\nnet/ipv6/seg6_local.c-1651-\t\t.input\t\t= input_action_end_dt4,\n--\nnet/ipv6/seg6_local.c-1658-\t\t.action\t\t= SEG6_LOCAL_ACTION_END_DT6,\nnet/ipv6/seg6_local.c:1659:#ifdef CONFIG_NET_L3_MASTER_DEV\nnet/ipv6/seg6_local.c-1660-\t\t.attrs\t\t= 0,\n--\nnet/ipv6/seg6_local.c-1676-\t\t.optattrs\t= SEG6_F_LOCAL_COUNTERS,\nnet/ipv6/seg6_local.c:1677:#ifdef CONFIG_NET_L3_MASTER_DEV\nnet/ipv6/seg6_local.c-1678-\t\t.input\t\t= input_action_end_dt46,\n--\nnet/ipv6/seg6_local.c=1878=seg6_end_dt_info *seg6_possible_end_dt_info(struct seg6_local_lwt *slwt)\nnet/ipv6/seg6_local.c-1879-{\nnet/ipv6/seg6_local.c:1880:#ifdef CONFIG_NET_L3_MASTER_DEV\nnet/ipv6/seg6_local.c-1881-\treturn \u0026slwt-\u003edt_info;\n"
} |
| 51/2 | 2026/11/01 14:19 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 50762 output: 22 thoughts: 63 Thoughts: Okay, let's dive into this `CONFIG_IPV6_SEG6_BPF` configuration option. My immediate instinct is to figure out its scope – where is this thing actually *used* in the codebase? It's not enough to just know it exists; I need to understand its impact and dependencies. **Initial Investigation into CONFIG_IPV6_SEG6_BPF** First port of call, naturally, is the Kconfig file in `net/ipv6`. That's the logical place to start defining and documenting the option. I'll need to scrutinize `net/ipv6/Kconfig` to see how it's defined, what it depends on, and perhaps most importantly, what it *enables*. After that, I would explore `net/ipv6/seg6_local.c` as this seems to be the place where the code related to segment routing with IPv6 and BPF would be implemented. I will have to look elsewhere too, but these files are my first guess. |
| 52/2 | 2026/11/01 14:19 | tool | grepper |
0mArgs:{
"Expression": "IPV6_SEG6_BPF"
}Results: {
"Output": "net/core/filter.c=6866=static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {\n--\nnet/core/filter.c-6877-\nnet/core/filter.c:6878:#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\nnet/core/filter.c-6879-static int bpf_push_seg6_encap(struct sk_buff *skb, u32 type, void *hdr, u32 len)\n--\nnet/core/filter.c-6910-}\nnet/core/filter.c:6911:#endif /* CONFIG_IPV6_SEG6_BPF */\nnet/core/filter.c-6912-\n--\nnet/core/filter.c=6921=BPF_CALL_4(bpf_lwt_in_push_encap, struct sk_buff *, skb, u32, type, void *, hdr,\n--\nnet/core/filter.c-6924-\tswitch (type) {\nnet/core/filter.c:6925:#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\nnet/core/filter.c-6926-\tcase BPF_LWT_ENCAP_SEG6:\n--\nnet/core/filter.c=6962=static const struct bpf_func_proto bpf_lwt_xmit_push_encap_proto = {\n--\nnet/core/filter.c-6971-\nnet/core/filter.c:6972:#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\nnet/core/filter.c-6973-BPF_CALL_4(bpf_lwt_seg6_store_bytes, struct sk_buff *, skb, u32, offset,\n--\nnet/core/filter.c=7156=static const struct bpf_func_proto bpf_lwt_seg6_adjust_srh_proto = {\n--\nnet/core/filter.c-7163-};\nnet/core/filter.c:7164:#endif /* CONFIG_IPV6_SEG6_BPF */\nnet/core/filter.c-7165-\n--\nnet/core/filter.c=9044=lwt_seg6local_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)\n--\nnet/core/filter.c-9048-\t\treturn NULL;\nnet/core/filter.c:9049:#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)\nnet/core/filter.c-9050-\tcase BPF_FUNC_lwt_seg6_store_bytes:\n--\nnet/ipv6/Kconfig=300=config IPV6_SEG6_HMAC\n--\nnet/ipv6/Kconfig-311-\nnet/ipv6/Kconfig:312:config IPV6_SEG6_BPF\nnet/ipv6/Kconfig-313-\tdef_bool y\n--\ntools/bpf/bpftool/feature.c=328=static void probe_kernel_image_config(const char *define_prefix)\n--\ntools/bpf/bpftool/feature.c-388-\t\t/* BPF_PROG_TYPE_LWT_SEG6_LOCAL and related helpers */\ntools/bpf/bpftool/feature.c:389:\t\t{ \"CONFIG_IPV6_SEG6_BPF\", },\ntools/bpf/bpftool/feature.c-390-\t\t/* BPF_PROG_TYPE_LIRC_MODE2 and related helpers */\n--\ntools/testing/selftests/bpf/config=48=CONFIG_IPV6_IOAM6_LWTUNNEL=y\ntools/testing/selftests/bpf/config:49:CONFIG_IPV6_SEG6_BPF=y\ntools/testing/selftests/bpf/config-50-CONFIG_IPV6_SEG6_LWTUNNEL=y\n"
} |
| 53/2 | 2026/11/01 14:19 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 52084 output: 356 thoughts: 1882 Thoughts: **Checksum Handling in IPv6 Segment Routing: A Deep Dive** Okay, let's break this down. My initial thought is that `CONFIG_IPV6_SEG6_BPF` is dependent on `IPV6_SEG6_LWTUNNEL` and `IPV6`. I'm seeing that `input_action_end_bpf` in `seg6_local.c` uses BPF with seg6 local. I need to clarify the essential configurations for SRv6. It looks like we absolutely need `IPV6` and `IPV6_SEG6_LWTUNNEL` – and `IPV6_SEG6_BPF` is likely automatically enabled via the dependency. `IPV6_SEG6_HMAC` is optional, but relevant to the overall feature set. Also, `LWTUNNEL` gets implicitly selected by `IPV6_SEG6_LWTUNNEL`. Now, let's think about sysctl requirements for seg6 processing. The `ipv6_srh_rcv` function has this check: `accept_seg6 = min(...)` using `seg6_enabled`. The system needs that `seg6_enabled` to be active, but syzkaller knows how to deal with sysctls and sends packets. The selftest `srv6_csum_complete_test.sh` will show how this sysctl is set. It looks like it is set via `net.ipv6.conf.all.seg6_enabled=1` and route configurations. I need to revisit the "FocusSymbols" – the functions that are being modified. I see changes in `net/ipv6/exthdrs.c` with `ipv6_srh_rcv`, `seg6_update_csum`, and `ipv6_rthdr_rcv`. Then there's `net/ipv6/seg6_iptunnel.c` with `seg6_do_srh`, `seg6_input`, and `seg6_output`. And then `net/ipv6/seg6_local.c` with `advance_nextseg`, `seg6_next_csid_advance_arg`, `input_action_end_bpf`, and `seg6_local_input`. Are there any other callers or modified functions? It's time to dig into the diffs again. I'm noting the changes in `include/net/seg6.h` – the `update_csum_diff4` and `update_csum_diff16` functions, which were buggy. They got fixed. `ipv6_srh_rcv` now updates the checksum via the fixed `update_csum_diff4` when the hop limit is decremented on the loopback. `seg6_do_srh` is now using `skb_push_rcsum` instead of `skb_push` for the MAC header. In `seg6_local.c`, both `advance_nextseg` and `seg6_next_csid_advance_arg` are adding checksum updates when `CHECKSUM_COMPLETE`. Finally, `input_action_end_bpf` is adding `skb_checksum_complete_unset(skb);`. All these changes are centered on the network stack, specifically concerning IPv6 segment routing (SRv6) and how it handles checksum calculation and verification, especially when `CHECKSUM_COMPLETE` is set. When a packet's altered mid-flight (decrementing hop limit, modifying the next hop or next-csid in the SRH, or making changes in the BPF hook), the `skb->csum` needs to be corrected, or unset, to prevent checksum failures in higher layers. I recognize that these types of checksum changes can be a source of regressions, checksum mismatches, packet drops, or bugs with malformed or truncated packets. Let's quickly review the required configs: `IPV6`, `IPV6_SEG6_LWTUNNEL`, `IPV6_SEG6_BPF`, `BPF_SYSCALL` (if using End.BPF), and potentially `NETFILTER` and `NF_CONNTRACK` (if using conntrack for testing). However, `IPV6` and `IPV6_SEG6_LWTUNNEL` are the core requirements. A quick double-check: `IPV6_SEG6_LWTUNNEL` does depend on other features via the `Kconfig`. It relies on `IPV6`, and selects `LWTUNNEL`, `DST_CACHE`, and `IPV6_MULTIPLE_TABLES`. So, it seems like `IPV6` and `IPV6_SEG6_LWTUNNEL` are the key |
| 54/2 | 2026/11/01 14:20 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"IPV6",
"IPV6_SEG6_LWTUNNEL",
"IPV6_SEG6_BPF"
],
"FocusSymbols": [
"ipv6_srh_rcv",
"seg6_update_csum",
"ipv6_rthdr_rcv",
"seg6_do_srh",
"seg6_input",
"seg6_output",
"advance_nextseg",
"seg6_next_csid_advance_arg",
"input_action_end_bpf",
"seg6_local_input"
],
"Reasoning": "The patch series modifies checksum update logic for IPv6 Segment Routing (SRv6) when packets carry CHECKSUM_COMPLETE. Specifically, it corrects the complement arithmetic in update_csum_diff4() and update_csum_diff16(), adds missing checksum updates when updating the hop limit in ipv6_srh_rcv(), updates skb-\u003ecsum when advancing segments in advance_nextseg() and seg6_next_csid_advance_arg(), uses skb_push_rcsum() in seg6_do_srh(), and clears CHECKSUM_COMPLETE in input_action_end_bpf(). This code is part of core IPv6 routing and lightweight tunnel encapsulation, fully reachable in standard virtualized QEMU/GCE environments via standard IPv6 sockets, loopback/veth interfaces, and netlink route encapsulation configs. Fuzzing is warranted to detect regressions, improper checksum handling, or packet corruption.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"IPV6",
"IPV6_SEG6_LWTUNNEL",
"IPV6_SEG6_BPF"
],
"FocusSymbols": [
"ipv6_srh_rcv",
"seg6_update_csum",
"ipv6_rthdr_rcv",
"seg6_do_srh",
"seg6_input",
"seg6_output",
"advance_nextseg",
"seg6_next_csid_advance_arg",
"input_action_end_bpf",
"seg6_local_input"
],
"Reasoning": "The patch series modifies checksum update logic for IPv6 Segment Routing (SRv6) when packets carry CHECKSUM_COMPLETE. Specifically, it corrects the complement arithmetic in update_csum_diff4() and update_csum_diff16(), adds missing checksum updates when updating the hop limit in ipv6_srh_rcv(), updates skb-\u003ecsum when advancing segments in advance_nextseg() and seg6_next_csid_advance_arg(), uses skb_push_rcsum() in seg6_do_srh(), and clears CHECKSUM_COMPLETE in input_action_end_bpf(). This code is part of core IPv6 routing and lightweight tunnel encapsulation, fully reachable in standard virtualized QEMU/GCE environments via standard IPv6 sockets, loopback/veth interfaces, and netlink route encapsulation configs. Fuzzing is warranted to detect regressions, improper checksum handling, or packet corruption.",
"WorthFuzzing": true
} |
| 55/1 | 2026/11/01 14:20 | action | If |
1mArgs:{
"WorthFuzzing": true
}Results: null |
| 56/2 | 2026/11/01 14:20 | agent | kmsan-evaluator |
1mModel:core Args: null Results: {
"KMSANReasoning": "The patch series addresses CHECKSUM_COMPLETE maintenance and checksum update formulas in IPv6 Segment Routing (SRv6). Specifically:\n1. It corrects the math in `update_csum_diff4` and `update_csum_diff16` by removing incorrect 1's complement inversions in `csum_partial`.\n2. It adds differential checksum updates (`update_csum_diff4` / `update_csum_diff16`) when modifying hop limit or destination addresses in `ipv6_srh_rcv`, `advance_nextseg`, and `seg6_next_csid_advance_arg`.\n3. It switches `skb_push` to `skb_push_rcsum` in `seg6_iptunnel.c` and calls `skb_checksum_complete_unset(skb)` in `seg6_local.c` after End.BPF actions.\n4. It adds selftests for CHECKSUM_COMPLETE validation under SRv6.\n\nNone of these changes introduce or expose uninitialized memory risks:\n- All new stack variables (`old`, `diff`) are immediately and fully initialized before read.\n- Packet accesses operate on verified, existing packet header buffers.\n- No data structures or padding bytes are copied to userspace or leaked.\n- Control flow branching does not depend on uninitialized variables.\n\nAny potential packet buffer boundary issues or memory corruptions are within the scope of standard KASAN/network stack checks. Thus, a dedicated KMSAN fuzzing session is not warranted.",
"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 7ed98965b2ad5b10d241ec5fc25b58517ece0a7e
Author: syz-cluster <triage@syzkaller.com>
Date: Sun Nov 1 14:16:31 2026 +0000
syz-cluster: applied patch under review
diff --git a/include/net/seg6.h b/include/net/seg6.h
index 82b3fbbcbb9351..01d8034e48fcab 100644
--- a/include/net/seg6.h
+++ b/include/net/seg6.h
@@ -19,7 +19,7 @@ static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,
{
__be32 diff[] = { ~from, to };
- skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);
+ skb->csum = csum_partial(diff, sizeof(diff), skb->csum);
}
static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,
@@ -30,7 +30,7 @@ static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,
to[0], to[1], to[2], to[3],
};
- skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);
+ skb->csum = csum_partial(diff, sizeof(diff), skb->csum);
}
struct seg6_pernet_data {
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 96c8402a27a549..9d3ba310065a1b 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -460,6 +460,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)
}
if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) {
+ /* payload_len, nexthdr and hop_limit */
+ __be32 *hlim_word = (__be32 *)ipv6_hdr(skb) + 1;
+ __be32 old;
+
if (ipv6_hdr(skb)->hop_limit <= 1) {
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
icmpv6_send(skb, ICMPV6_TIME_EXCEED,
@@ -467,8 +471,12 @@ static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)
kfree_skb_reason(skb, SKB_DROP_REASON_IP_TTL_EXCEEDED);
return -1;
}
+ old = *hlim_word;
ipv6_hdr(skb)->hop_limit--;
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ update_csum_diff4(skb, old, *hlim_word);
+
skb_pull(skb, skb_transport_offset(skb));
goto looped_back;
}
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 0d39a38a5dd299..3821d8e1409e71 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -456,7 +456,7 @@ static int seg6_do_srh(struct sk_buff *skb, struct dst_entry *cache_dst)
return err;
skb_mac_header_rebuild(skb);
- skb_push(skb, skb->mac_len);
+ skb_push_rcsum(skb, skb->mac_len);
if (tinfo->mode == SEG6_IPTUN_MODE_L2ENCAP)
err = __seg6_do_srh_encap(skb, tinfo->srh,
diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index 0c3d1be7f1299e..3045a351f4e92f 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -291,7 +291,9 @@ static struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,
struct ipv6_sr_hdr *srh,
enum skb_drop_reason *reason)
{
+ struct in6_addr *daddr;
struct in6_addr *addr;
+ __be32 old;
int srhoff;
int wlen;
@@ -309,10 +311,19 @@ static struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,
/* skb_ensure_writable() may change skb pointers; evaluate srh again */
srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
+ daddr = &ipv6_hdr(skb)->daddr;
+ /* nexthdr, hdrlen, type and segments_left */
+ old = *(__be32 *)srh;
srh->segments_left--;
addr = srh->segments + srh->segments_left;
- ipv6_hdr(skb)->daddr = *addr;
+
+ if (skb->ip_summed == CHECKSUM_COMPLETE) {
+ update_csum_diff4(skb, old, *(__be32 *)srh);
+ update_csum_diff16(skb, (__be32 *)daddr, (__be32 *)addr);
+ }
+
+ *daddr = *addr;
return srh;
}
@@ -427,11 +438,13 @@ seg6_next_csid_advance_arg(struct sk_buff *skb,
__u8 fnc_octects = seg6_flv_lcnode_func_octects(finfo);
__u8 blk_octects = seg6_flv_lcblock_octects(finfo);
struct in6_addr *addr;
+ struct in6_addr old;
if (unlikely(skb_ensure_writable(skb, sizeof(struct ipv6hdr))))
return SKB_DROP_REASON_NOMEM;
addr = &ipv6_hdr(skb)->daddr;
+ old = *addr;
/* advance DA.Argument */
memmove(&addr->s6_addr[blk_octects],
@@ -440,6 +453,9 @@ seg6_next_csid_advance_arg(struct sk_buff *skb,
memset(&addr->s6_addr[16 - fnc_octects], 0x00, fnc_octects);
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ update_csum_diff16(skb, (__be32 *)&old, (__be32 *)addr);
+
return SKB_NOT_DROPPED_YET;
}
@@ -1566,6 +1582,12 @@ static int input_action_end_bpf(struct sk_buff *skb,
goto drop;
}
+ /* The program may have changed the packet and seg6_bpf_has_valid_srh()
+ * may rewrite the SRH Hdr Ext Len below.
+ * skb->csum may then no longer be the checksum of the full packet.
+ */
+ skb_checksum_complete_unset(skb);
+
if (srh_state->srh && !seg6_bpf_has_valid_srh(skb))
goto drop;
local_unlock_nested_bh(&seg6_bpf_srh_states.bh_lock);
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index df215e1a62621b..16e9fbf889fd1b 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -92,6 +92,7 @@ TEST_PROGS := \
rxtimestamp.sh \
sctp_vrf.sh \
skf_net_off.sh \
+ srv6_csum_complete_test.sh \
srv6_encap_lookup_l3vpn_test.sh \
srv6_end_dt46_l3vpn_test.sh \
srv6_end_dt4_l3vpn_test.sh \
diff --git a/tools/testing/selftests/net/srv6_csum_complete.bpf.c b/tools/testing/selftests/net/srv6_csum_complete.bpf.c
new file mode 100644
index 00000000000000..281b0361f97693
--- /dev/null
+++ b/tools/testing/selftests/net/srv6_csum_complete.bpf.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Andrea Mayer <andrea.mayer@uniroma2.it>
+ */
+#include <stddef.h>
+#include <linux/bpf.h>
+#include <linux/if_ether.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/seg6.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+/* On the tc ingress, skb->data points to the Ethernet header */
+#define TC_IPV6_OFF ETH_HLEN
+/* Byte with the lowest 8 bits of the Flow Label */
+#define TC_FLOW_LBL_OFF (TC_IPV6_OFF + \
+ offsetof(struct ipv6hdr, flow_lbl) + 2)
+/* Bit of the Flow Label changed in the control datagram */
+#define CTRL_FLOW_LBL_BIT 0x01
+
+/* In End.BPF, skb->data points to the IPv6 header, followed by the SRH */
+#define SRH_TAG_OFF (sizeof(struct ipv6hdr) + \
+ offsetof(struct ipv6_sr_hdr, tag))
+/* Value written in the SRH Tag, test case (vi) */
+#define SRH_TAG 0x1234
+
+/* Test case (v) of srv6_csum_complete_test.sh. The program runs on the tc
+ * ingress of rt, after the ct action, only for the control datagram. It
+ * changes one bit of the Flow Label, without updating the receive checksum
+ * (skb->csum). The Flow Label is not part of the UDP checksum, which stays
+ * correct. UDP must drop the datagram because the receive checksum no longer
+ * matches the packet.
+ */
+SEC("tc")
+int ctrl_flow_label(struct __sk_buff *skb)
+{
+ __u8 lbl;
+
+ /* Read the byte with the lowest 8 bits of the Flow Label */
+ if (bpf_skb_load_bytes(skb, TC_FLOW_LBL_OFF, &lbl, sizeof(lbl)))
+ return TC_ACT_SHOT;
+
+ lbl ^= CTRL_FLOW_LBL_BIT;
+
+ /* Write the byte back, flags 0 do not update the receive checksum */
+ if (bpf_skb_store_bytes(skb, TC_FLOW_LBL_OFF, &lbl, sizeof(lbl), 0))
+ return TC_ACT_SHOT;
+
+ return TC_ACT_OK;
+}
+
+/* Test case (vi), the End.BPF program writes the SRH Tag */
+SEC("lwt_seg6local")
+int end_bpf_tag(struct __sk_buff *skb)
+{
+ __u16 tag = bpf_htons(SRH_TAG);
+
+ if (bpf_lwt_seg6_store_bytes(skb, SRH_TAG_OFF, &tag, sizeof(tag)))
+ return BPF_DROP;
+
+ return BPF_OK;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/net/srv6_csum_complete_test.sh b/tools/testing/selftests/net/srv6_csum_complete_test.sh
new file mode 100755
index 00000000000000..0b9c929313620f
--- /dev/null
+++ b/tools/testing/selftests/net/srv6_csum_complete_test.sh
@@ -0,0 +1,642 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# author: Andrea Mayer <andrea.mayer@uniroma2.it>
+
+# This test checks the receive checksum of an SRv6 packet that is processed and
+# then delivered on the same node. The node changes the Segments Left and the
+# destination address of the packet, and can also change the Hop Limit.
+#
+# The receive checksum (CHECKSUM_COMPLETE) is the checksum of the whole packet,
+# kept with the received packet. When the node changes the packet, it must also
+# update this sum, or discard it.
+#
+# Network topology
+# ================
+#
+# The test uses a host (hs) and a router (rt) connected through a veth pair. In
+# each test case, hs sends one UDP datagram to an address of rt.
+#
+# +--------------------+ +--------------------------+
+# | hs | | rt |
+# | | | |
+# | veth-hs +--------------------+ veth-rt |
+# | fd00::1/64 | | fd00::2/64 |
+# | tx checksum off | | tc ingress: ct, then bpf |
+# +--------------------+ | |
+# | lo: fc00::1 ... fc00::4 |
+# | cafe::1 ... cafe::6 |
+# +--------------------------+
+#
+# Receive checksum
+# ================
+#
+# veth does not provide the receive checksum. For this reason, a tc ct action
+# runs on the ingress of rt. The ct action checks the UDP checksum, and in this
+# way computes the receive checksum in software. If the receive checksum does
+# not match the packet, UDP drops the datagram as a checksum error.
+#
+# The ct action computes the receive checksum when hs computes the UDP checksum
+# in software, before the datagram crosses the veth. For this reason, hs has
+# transmit checksumming off.
+#
+# Each datagram is longer than 76 bytes, UDP header included. For datagrams of
+# 76 bytes or less, UDP computes the checksum again from the packet, and accepts
+# the datagram even with a wrong receive checksum.
+#
+# UDP counters
+# ============
+#
+# Each datagram goes to a port with no listener. If the UDP checksum check
+# passes, rt counts the datagram in Udp6NoPorts. If it fails, rt counts it in
+# Udp6InCsumErrors.
+#
+# Control datagram
+# ================
+#
+# A control datagram checks that the test detects a wrong receive checksum after
+# a change to the packet. After the ct action, a tc bpf filter on rt changes one
+# bit of its Flow Label, without updating the receive checksum. The Flow Label
+# is not part of the UDP checksum, which stays correct. UDP must drop the
+# datagram because the receive checksum no longer matches the packet. If UDP
+# accepts it, the test cannot detect a wrong receive checksum. The other test
+# cases may then pass even when their receive checksum is wrong, and for this
+# reason the test fails.
+#
+# Routes and tc filters
+# =====================
+#
+# hs: encap (main table)
+# +---------+-----------------------------------------------------+
+# | dst | action |
+# +---------+-----------------------------------------------------+
+# | cafe::1 | via fd00::2 |
+# | cafe::2 | encap seg6 mode inline segs fc00::1,fc00::2 |
+# | cafe::3 | encap seg6 mode inline segs fcbb:0:0200:: |
+# | cafe::4 | encap seg6 mode inline segs fcbb:0:0100:0200:: |
+# | cafe::5 | encap seg6 mode inline segs fc00::3,fc00::4 |
+# | cafe::6 | encap seg6 mode inline segs fc00::b0,fcbb:0:0200:: |
+# +---------+-----------------------------------------------------+
+#
+# rt: SRv6 behaviors (main table)
+# +------------------+------------------------------------------------+
+# | SID | action |
+# +------------------+------------------------------------------------+
+# | fcbb:0:0100::/48 | End flavors next-csid lblen 32 nflen 16 |
+# | fcbb:0:0200::/48 | End.B6.Encaps srh segs fc00::d6 |
+# | fc00::d6 | End.DT6 table 255 (local) |
+# | fc00::b0 | End.BPF, the program writes the SRH Tag |
+# +------------------+------------------------------------------------+
+#
+# rt: tc ingress of veth-rt
+# +-------+------+---------------------------------------------------+
+# | chain | prio | filter |
+# +-------+------+---------------------------------------------------+
+# | 0 | 1 | matchall, action ct, goto chain 1 |
+# | 1 | 1 | flower dst_ip fc00::3, goto chain 2 |
+# | 2 | 1 | bpf, changes one bit of the Flow Label |
+# +-------+------+---------------------------------------------------+
+#
+# Test cases
+# ==========
+#
+# hs applies the SRv6 Policies in inline mode, i.e. the original destination
+# becomes the last SID of the SID List.
+#
+# i) cafe::1, no SRH, used as a reference.
+#
+# ii) cafe::2, SID List=fc00::1,fc00::2,cafe::2
+# fc00::1 and fc00::2 are addresses of rt. rt processes the SRH twice. Each
+# time, it also decrements the Hop Limit.
+#
+# iii) cafe::3, SID List=fcbb:0:0200::,cafe::3
+# End.B6.Encaps advances the SRH and adds an outer IPv6 header with an SRH.
+# The outer header goes to the End.DT6 SID fc00::d6, which removes it.
+#
+# iv) cafe::4, SID List=fcbb:0:0100:0200::,cafe::4
+# End with the NEXT-C-SID flavor changes the DA to the next C-SID,
+# fcbb:0:0200::. Then the datagram follows the same path as in (iii).
+#
+# v) cafe::5, SID List=fc00::3,fc00::4,cafe::5, control.
+# The tc flower filter matches the first segment, fc00::3, and the tc bpf
+# filter changes the Flow Label. Then rt processes the SRH as in (ii).
+#
+# vi) cafe::6, SID List=fc00::b0,fcbb:0:0200::,cafe::6
+# End.BPF writes the SRH Tag. Then the datagram follows the same path as in
+# (iii).
+#
+# In the test case (v), the datagram is expected to be dropped as a checksum
+# error. In all the other test cases, the datagram is expected to be delivered
+# on rt.
+
+# shellcheck source=lib.sh
+source lib.sh
+
+readonly IPv6_RT_NETWORK=fd00
+readonly IPv6_DST_NETWORK=cafe
+readonly SID_LOCATOR=fc00
+readonly CSID_BLOCK=fcbb:0
+readonly CSID_LBLEN=32
+readonly CSID_NFLEN=16
+readonly CSID_BLOCK_FUNC_LEN=$((CSID_LBLEN + CSID_NFLEN))
+readonly B6_FUNC=0200
+readonly CSID_FUNC=0100
+readonly DT6_FUNC=d6
+readonly BPF_FUNC=b0
+readonly DUMMY_DEVNAME=dum0
+readonly UDP_PORT=9
+readonly UDP_PAYLOAD_LEN=200
+readonly WAIT_TIMEOUT_SEC=5
+
+# destination of the control datagram on the veth, test case (v)
+readonly CTRL_DST="${SID_LOCATOR}::3"
+# tc chain of the flower filter that selects the control datagram
+readonly CTRL_CHAIN=1
+# tc chain of the bpf filter that changes the Flow Label
+readonly BPF_CHAIN=2
+
+readonly BPF_FILE=srv6_csum_complete.bpf.o
+readonly BPF_TC_SEC=tc
+readonly BPF_END_SEC=lwt_seg6local
+
+# return values of check_udp_delivery()
+readonly UDP_DELIVERED=0
+readonly UDP_LOST=1
+readonly UDP_CSUM_ERROR=2
+
+SETUP_ERR=1
+
+ret=${ksft_skip}
+nsuccess=0
+nfail=0
+
+log_test()
+{
+ log_test_expected "$1" "$2" "$3"
+}
+
+print_log_test_results()
+{
+ printf "\nTests passed: %3d\n" "${nsuccess}"
+ printf "Tests failed: %3d\n" "${nfail}"
+
+ # when a test fails, the value of 'ret' is set to 1 (error code).
+ # Conversely, when all tests are passed successfully, the 'ret' value
+ # is set to 0 (success code).
+ if [ "${ret}" -ne 1 ]; then
+ ret=0
+ fi
+}
+
+log_section()
+{
+ echo
+ echo "################################################################################"
+ echo "TEST SECTION: $*"
+ echo "################################################################################"
+}
+
+cleanup()
+{
+ cleanup_all_ns
+
+ # check whether the setup phase was completed successfully or not. In
+ # case of an error during the setup phase of the testing environment,
+ # the selftest is considered as "skipped".
+ if [ "${SETUP_ERR}" -ne 0 ]; then
+ echo "SKIP: Setting up the testing environment failed"
+ exit "${ksft_skip}"
+ fi
+
+ exit "${ret}"
+}
+
+# add on hs the SRv6 Policy for cafe::<id>, in inline mode
+# args:
+# $1 - destination id
+# $2 - segments, comma separated
+set_hs_policy()
+{
+ local dstid="$1"
+ local segs="$2"
+
+ ip -netns "${NS_HS}" -6 route add "${IPv6_DST_NETWORK}::${dstid}/128" \
+ encap seg6 mode inline segs "${segs}" \
+ via "${IPv6_RT_NETWORK}::2" dev veth-hs
+}
+
+setup_hs()
+{
+ ip -netns "${NS_HS}" link set veth-hs up
+ ip -netns "${NS_HS}" addr add "${IPv6_RT_NETWORK}::1/64" \
+ dev veth-hs nodad
+
+ # with transmit checksumming on, conntrack on rt does not compute the
+ # receive checksum
+ ip netns exec "${NS_HS}" ethtool -K veth-hs tx off >/dev/null
+
+ # routes to the SIDs, used after the SRH is inserted
+ ip -netns "${NS_HS}" -6 route add "${SID_LOCATOR}::/16" \
+ via "${IPv6_RT_NETWORK}::2" dev veth-hs
+ ip -netns "${NS_HS}" -6 route add "${CSID_BLOCK}::/${CSID_LBLEN}" \
+ via "${IPv6_RT_NETWORK}::2" dev veth-hs
+
+ # test case (i), the reference, no SRH
+ ip -netns "${NS_HS}" -6 route add "${IPv6_DST_NETWORK}::1/128" \
+ via "${IPv6_RT_NETWORK}::2" dev veth-hs
+
+ # the SRv6 Policies of the test cases (ii) to (vi)
+ set_hs_policy 2 "${SID_LOCATOR}::1,${SID_LOCATOR}::2"
+ set_hs_policy 3 "${CSID_BLOCK}:${B6_FUNC}::"
+ set_hs_policy 4 "${CSID_BLOCK}:${CSID_FUNC}:${B6_FUNC}::"
+ set_hs_policy 5 "${SID_LOCATOR}::3,${SID_LOCATOR}::4"
+ set_hs_policy 6 "${SID_LOCATOR}::${BPF_FUNC},${CSID_BLOCK}:${B6_FUNC}::"
+}
+
+setup_rt()
+{
+ local dstid
+ local dev
+
+ ip -netns "${NS_RT}" link set veth-rt up
+ ip -netns "${NS_RT}" addr add "${IPv6_RT_NETWORK}::2/64" \
+ dev veth-rt nodad
+
+ # local segments of the test case (ii)
+ ip -netns "${NS_RT}" addr add "${SID_LOCATOR}::1/128" dev lo nodad
+ ip -netns "${NS_RT}" addr add "${SID_LOCATOR}::2/128" dev lo nodad
+ # local segments of the test case (v)
+ ip -netns "${NS_RT}" addr add "${SID_LOCATOR}::3/128" dev lo nodad
+ ip -netns "${NS_RT}" addr add "${SID_LOCATOR}::4/128" dev lo nodad
+ for dstid in 1 2 3 4 5 6; do
+ ip -netns "${NS_RT}" addr add \
+ "${IPv6_DST_NETWORK}::${dstid}/128" dev lo nodad
+ done
+
+ for dev in all veth-rt lo; do
+ ip netns exec "${NS_RT}" sysctl -wq \
+ net.ipv6.conf."${dev}".seg6_enabled=1
+ done
+
+ # SRv6 behaviors used by the test cases (iii), (iv) and (vi)
+ ip -netns "${NS_RT}" -6 route \
+ add "${CSID_BLOCK}:${CSID_FUNC}::/${CSID_BLOCK_FUNC_LEN}" \
+ encap seg6local action End flavors next-csid \
+ lblen "${CSID_LBLEN}" nflen "${CSID_NFLEN}" dev veth-rt
+ ip -netns "${NS_RT}" -6 route \
+ add "${CSID_BLOCK}:${B6_FUNC}::/${CSID_BLOCK_FUNC_LEN}" \
+ encap seg6local action End.B6.Encaps \
+ srh segs "${SID_LOCATOR}::${DT6_FUNC}" dev veth-rt
+ ip -netns "${NS_RT}" -6 route add "${SID_LOCATOR}::${DT6_FUNC}/128" \
+ encap seg6local action End.DT6 table 255 dev veth-rt
+ ip -netns "${NS_RT}" -6 route add "${SID_LOCATOR}::${BPF_FUNC}/128" \
+ encap seg6local action End.BPF endpoint obj "${BPF_FILE}" \
+ sec "${BPF_END_SEC}" dev veth-rt
+
+ tc -netns "${NS_RT}" qdisc add dev veth-rt clsact
+ # the bpf filter changes the Flow Label of the control datagram
+ tc -netns "${NS_RT}" filter add dev veth-rt ingress \
+ chain "${BPF_CHAIN}" prio 1 protocol ipv6 \
+ bpf object-file "${BPF_FILE}" section "${BPF_TC_SEC}" \
+ direct-action
+ # the control datagram goes to the bpf filter
+ tc -netns "${NS_RT}" filter add dev veth-rt ingress \
+ chain "${CTRL_CHAIN}" prio 1 protocol ipv6 \
+ flower dst_ip "${CTRL_DST}" \
+ action goto chain "${BPF_CHAIN}"
+ # every packet goes to the ct action, which computes the receive
+ # checksum, then to the chain of the flower filter
+ tc -netns "${NS_RT}" filter add dev veth-rt ingress prio 1 \
+ protocol ipv6 matchall \
+ action ct pipe action goto chain "${CTRL_CHAIN}"
+ ip netns exec "${NS_RT}" sysctl -wq \
+ net.netfilter.nf_conntrack_checksum=1
+}
+
+setup()
+{
+ setup_ns NS_HS NS_RT
+
+ ip -netns "${NS_HS}" link add veth-hs type veth \
+ peer name veth-rt netns "${NS_RT}"
+
+ setup_hs
+ setup_rt
+
+ # testing environment was set up successfully
+ SETUP_ERR=0
+}
+
+# print the value of a counter of rt in /proc/net/snmp6
+# args:
+# $1 - counter name in /proc/net/snmp6
+get_rt_udp6_counter()
+{
+ local name="$1"
+
+ ip netns exec "${NS_RT}" cat /proc/net/snmp6 | \
+ awk -v k="${name}" '$1 == k { print $2 }'
+}
+
+# number of datagrams that UDP on rt counted in Udp6NoPorts or Udp6InCsumErrors
+get_rt_udp6_received()
+{
+ echo $(( $(get_rt_udp6_counter Udp6NoPorts) +
+ $(get_rt_udp6_counter Udp6InCsumErrors) ))
+}
+
+check_hs_rt_connectivity()
+{
+ ip netns exec "${NS_HS}" ping -c 1 -W 1 "${IPv6_RT_NETWORK}::2" \
+ >/dev/null 2>&1
+}
+
+check_and_log_hs_rt_connectivity()
+{
+ check_hs_rt_connectivity
+ log_test $? 0 "Connectivity: hs -> rt"
+}
+
+connectivity_tests()
+{
+ log_section "IPv6 connectivity test between host and router"
+
+ check_and_log_hs_rt_connectivity
+}
+
+# Send one UDP datagram from hs to a port with no listener on rt.
+# args:
+# $1 - destination id
+# return:
+# - UDP_DELIVERED if rt counts the datagram as delivered
+# - UDP_CSUM_ERROR if rt drops it for a bad checksum
+# - UDP_LOST if the datagram cannot be sent, or if it does not arrive
+check_udp_delivery()
+{
+ local dstid="$1"
+ local noports
+ local payload
+ local errors
+ local recv
+ local dst
+
+ dst="${IPv6_DST_NETWORK}::${dstid}"
+ noports="$(get_rt_udp6_counter Udp6NoPorts)"
+ errors="$(get_rt_udp6_counter Udp6InCsumErrors)"
+ recv=$((noports + errors))
+ payload="$(printf '%*s' "${UDP_PAYLOAD_LEN}" '')"
+
+ # send the datagram with the /dev/udp redirection of bash
+ if ! ip netns exec "${NS_HS}" bash -c "printf '%s' '${payload}' > \
+ /dev/udp/${dst}/${UDP_PORT}"; then
+ return "${UDP_LOST}"
+ fi
+
+ # wait until rt counts the datagram in Udp6NoPorts or Udp6InCsumErrors
+ if ! slowwait "${WAIT_TIMEOUT_SEC}" until_counter_is \
+ ">= $((recv + 1))" get_rt_udp6_received >/dev/null; then
+ return "${UDP_LOST}"
+ fi
+
+ if [ "$(get_rt_udp6_counter Udp6InCsumErrors)" -ne "${errors}" ]; then
+ return "${UDP_CSUM_ERROR}"
+ fi
+
+ if [ "$(get_rt_udp6_counter Udp6NoPorts)" -ne "$((noports + 1))" ]; then
+ return "${UDP_LOST}"
+ fi
+
+ return "${UDP_DELIVERED}"
+}
+
+# check the delivery of a datagram to cafe::<id> and log the result
+# args:
+# $1 - destination id
+# $2 - expected return value of check_udp_delivery()
+# $3 - description of the path
+check_and_log_udp_delivery()
+{
+ local dstid="$1"
+ local expected="$2"
+ local desc="$3"
+
+ check_udp_delivery "${dstid}"
+ log_test $? "${expected}" \
+ "UDP: hs -> ${IPv6_DST_NETWORK}::${dstid} (${desc})"
+}
+
+udp_delivery_tests()
+{
+ log_section "UDP delivery test with CHECKSUM_COMPLETE"
+
+ check_and_log_udp_delivery 1 "${UDP_DELIVERED}" "no SRH"
+ check_and_log_udp_delivery 2 "${UDP_DELIVERED}" "SRH, local segments"
+ check_and_log_udp_delivery 3 "${UDP_DELIVERED}" "End.B6.Encaps, End.DT6"
+ check_and_log_udp_delivery 4 "${UDP_DELIVERED}" \
+ "End next-csid, End.B6.Encaps, End.DT6"
+ check_and_log_udp_delivery 5 "${UDP_CSUM_ERROR}" "control, csum error"
+ check_and_log_udp_delivery 6 "${UDP_DELIVERED}" \
+ "End.BPF, End.B6.Encaps, End.DT6"
+}
+
+test_command_or_ksft_skip()
+{
+ local cmd="$1"
+
+ if [ ! -x "$(command -v "${cmd}")" ]; then
+ echo "SKIP: Could not run test without \"${cmd}\" tool"
+ exit "${ksft_skip}"
+ fi
+}
+
+test_dummy_dev_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ modprobe dummy &>/dev/null || true
+ if ! ip -netns "${test_netns}" link add "${DUMMY_DEVNAME}" \
+ type dummy; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: dummy dev not supported"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+test_iproute2_supp_or_ksft_skip()
+{
+ if ! ip route help 2>&1 | grep -qo next-csid; then
+ echo "SKIP: Missing SRv6 next-csid flavor support in iproute2"
+ exit "${ksft_skip}"
+ fi
+}
+
+test_kernel_supp_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ ip -netns "${test_netns}" link add "${DUMMY_DEVNAME}" type dummy
+ ip -netns "${test_netns}" link set "${DUMMY_DEVNAME}" up
+
+ if ! ip -netns "${test_netns}" -6 route \
+ add "${CSID_BLOCK}::/${CSID_LBLEN}" encap seg6local \
+ action End flavors next-csid dev "${DUMMY_DEVNAME}" \
+ 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: SRv6 next-csid flavor not supported"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+test_veth_tx_csum_off_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ if ! ip -netns "${test_netns}" link add veth-t0 type veth \
+ peer name veth-t1 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: veth dev not supported"
+ exit "${ksft_skip}"
+ fi
+
+ # setup_hs() turns off transmit checksumming on veth-hs. If it stays on,
+ # conntrack does not compute the receive checksum and the test cannot
+ # see the error.
+ ip netns exec "${test_netns}" ethtool -K veth-t0 tx off >/dev/null 2>&1
+
+ if ! ip netns exec "${test_netns}" ethtool -k veth-t0 | \
+ grep -q "^tx-checksumming: off"; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: Cannot turn off transmit checksumming on veth"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+test_bpf_file_or_ksft_skip()
+{
+ if [ ! -f "${BPF_FILE}" ]; then
+ echo "SKIP: Missing ${BPF_FILE}, run 'make' first"
+ exit "${ksft_skip}"
+ fi
+}
+
+test_tc_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ ip -netns "${test_netns}" link add "${DUMMY_DEVNAME}" type dummy
+
+ if ! tc -netns "${test_netns}" qdisc add dev "${DUMMY_DEVNAME}" \
+ clsact 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: tc clsact qdisc not supported"
+ exit "${ksft_skip}"
+ fi
+
+ if ! tc -netns "${test_netns}" filter add dev "${DUMMY_DEVNAME}" \
+ ingress chain "${BPF_CHAIN}" protocol ipv6 \
+ bpf object-file "${BPF_FILE}" section "${BPF_TC_SEC}" \
+ direct-action 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: tc bpf filter not supported"
+ exit "${ksft_skip}"
+ fi
+
+ if ! tc -netns "${test_netns}" filter add dev "${DUMMY_DEVNAME}" \
+ ingress chain "${CTRL_CHAIN}" protocol ipv6 \
+ flower dst_ip "${CTRL_DST}" \
+ action goto chain "${BPF_CHAIN}" 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: tc flower filter or goto chain action not supported"
+ exit "${ksft_skip}"
+ fi
+
+ if ! tc -netns "${test_netns}" filter add dev "${DUMMY_DEVNAME}" \
+ ingress protocol ipv6 matchall \
+ action ct pipe action goto chain "${CTRL_CHAIN}" \
+ 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: tc matchall filter or ct action not supported"
+ exit "${ksft_skip}"
+ fi
+
+ # setup_rt() turns on nf_conntrack_checksum. If it is off, conntrack
+ # does not check the UDP checksum and does not compute the receive
+ # checksum. The test cannot see the error.
+ if ! ip netns exec "${test_netns}" sysctl -wq \
+ net.netfilter.nf_conntrack_checksum=1 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: nf_conntrack_checksum sysctl not available"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+test_end_bpf_or_ksft_skip()
+{
+ local test_netns
+
+ setup_ns test_netns
+
+ ip -netns "${test_netns}" link add "${DUMMY_DEVNAME}" type dummy
+ ip -netns "${test_netns}" link set "${DUMMY_DEVNAME}" up
+
+ if ! ip -netns "${test_netns}" -6 route \
+ add "${SID_LOCATOR}::${BPF_FUNC}/128" encap seg6local \
+ action End.BPF endpoint obj "${BPF_FILE}" \
+ sec "${BPF_END_SEC}" dev "${DUMMY_DEVNAME}" \
+ 2>/dev/null; then
+ cleanup_ns "${test_netns}"
+ echo "SKIP: SRv6 End.BPF not supported"
+ exit "${ksft_skip}"
+ fi
+
+ cleanup_ns "${test_netns}"
+}
+
+if [ "$(id -u)" -ne 0 ]; then
+ echo "SKIP: Need root privileges"
+ exit "${ksft_skip}"
+fi
+
+# required programs to carry out this selftest
+test_command_or_ksft_skip ip
+test_command_or_ksft_skip tc
+test_command_or_ksft_skip ethtool
+test_command_or_ksft_skip ping
+test_command_or_ksft_skip sysctl
+test_command_or_ksft_skip awk
+test_command_or_ksft_skip grep
+
+test_dummy_dev_or_ksft_skip
+test_iproute2_supp_or_ksft_skip
+test_kernel_supp_or_ksft_skip
+test_veth_tx_csum_off_or_ksft_skip
+test_bpf_file_or_ksft_skip
+test_tc_or_ksft_skip
+test_end_bpf_or_ksft_skip
+
+set -e
+trap cleanup EXIT
+
+setup
+set +e
+
+connectivity_tests
+udp_delivery_tests
+
+print_log_test_results
|
| 57/3 | 2026/11/01 14:20 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 13014 output: 35 thoughts: 204 Thoughts: **KMSAN Fuzzing Justification: Initial Assessment** Okay, so I'm looking at this patch series and the primary question is: does this warrant firing up a KMSAN fuzzing session? Time to dive in. First, let's carefully inspect the diff. The primary change seems to be within `include/net/seg6.h`. Specifically, in the functions `update_csum_diff4` and `update_csum_diff16`, they've tweaked how checksums are handled. Now, hold on a second...it seems like there's a significant change to how these checksums are calculated. Originally, the code used a convoluted approach: `~csum_partial((char *)diff, sizeof(diff), ~skb->csum)`. It's been simplified, as a fix, to `csum_partial(diff, sizeof(diff), skb->csum)`. That "tilde-csum-tilde" construct is a red flag. What was the rationale behind that in the first place? I'm going to need to dig deeper into the underlying checksum logic. Time to refresh my memory on `csum_partial`, maybe even the lower-level functions that `csum_partial` uses like `csum_block_add`, and more fundamentally, how checksumming is implemented in the kernel. I can't immediately understand *why* this change would be needed. This is where I go digging through the code, starting with that header file in the kernel. This type of checksum manipulation is often where subtle, memory-related bugs can hide. |
| 58/3 | 2026/11/01 14:20 | tool | grepper |
0mArgs:{
"Expression": "update_csum_diff",
"PathPrefixes": [
"include/net/seg6.h"
]
}Results: {
"Output": "include/net/seg6.h-16-\ninclude/net/seg6.h:17:static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,\ninclude/net/seg6.h-18-\t\t\t\t __be32 to)\n--\ninclude/net/seg6.h-24-\ninclude/net/seg6.h:25:static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,\ninclude/net/seg6.h-26-\t\t\t\t __be32 *to)\n"
} |
| 59/3 | 2026/11/01 14:20 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 13754 output: 35 thoughts: 20 Thoughts: Here's a first-person summary, tailored for an expert audience, as requested: **Diving into the SEG6 Code** Alright, let's pull up `include/net/seg6.h`, focusing specifically around line 17. I'm primarily interested in getting a quick refresher on the core data structures and perhaps any recent additions or changes. Given the header file's purpose, I'm expecting to see definitions for structs that represent Segment Routing IPv6 (SRv6) related headers, possibly including any extensions that are used to encode the segment list, the locator, and perhaps any optional metadata. I'll be looking to see how they've handled the seg6 header, and any associated TLVs for encapsulation, de-encapsulation, or policy control. I'm keen to spot any unusual bitfields or packing arrangements that might indicate some clever optimization or a potential area for future performance tweaking. I also expect to see some related enums and defines used for control and processing, such as flags, error codes, or operation types. Finally, I'll be keeping an eye out for any comments hinting at the design rationale, especially those tied to the IETF drafts or RFCs. This is my starting point, and I expect to form a good overview of the relevant SEG6 components in this section of the code. |
| 60/3 | 2026/11/01 14:20 | tool | read-file |
0mArgs:{
"File": "include/net/seg6.h",
"FirstLine": 15,
"LineCount": 40
}Results: {
"Contents": " 15:\t#include \u003clinux/rhashtable-types.h\u003e\n 16:\t\n 17:\tstatic inline void update_csum_diff4(struct sk_buff *skb, __be32 from,\n 18:\t\t\t\t\t __be32 to)\n 19:\t{\n 20:\t\t__be32 diff[] = { ~from, to };\n 21:\t\n 22:\t\tskb-\u003ecsum = csum_partial(diff, sizeof(diff), skb-\u003ecsum);\n 23:\t}\n 24:\t\n 25:\tstatic inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,\n 26:\t\t\t\t\t __be32 *to)\n 27:\t{\n 28:\t\t__be32 diff[] = {\n 29:\t\t\t~from[0], ~from[1], ~from[2], ~from[3],\n 30:\t\t\tto[0], to[1], to[2], to[3],\n 31:\t\t};\n 32:\t\n 33:\t\tskb-\u003ecsum = csum_partial(diff, sizeof(diff), skb-\u003ecsum);\n 34:\t}\n 35:\t\n 36:\tstruct seg6_pernet_data {\n 37:\t\tstruct mutex lock;\n 38:\t\tstruct in6_addr __rcu *tun_src;\n 39:\t#ifdef CONFIG_IPV6_SEG6_HMAC\n 40:\t\tstruct rhashtable hmac_infos;\n 41:\t#endif\n 42:\t};\n 43:\t\n 44:\tstatic inline struct seg6_pernet_data *seg6_pernet(struct net *net)\n 45:\t{\n 46:\t#if IS_ENABLED(CONFIG_IPV6)\n 47:\t\treturn net-\u003eipv6.seg6_data;\n 48:\t#else\n 49:\t\treturn NULL;\n 50:\t#endif\n 51:\t}\n 52:\t\n 53:\textern int seg6_init(void);\n 54:\textern void seg6_exit(void);\n"
} |
| 61/3 | 2026/11/01 14:20 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 14651 output: 39 thoughts: 1517 Thoughts: **Analyzing IPv6 Header and Checksum Updates** Okay, so I'm diving into these IPv6 code changes. It looks like the primary focus here is handling checksum updates in conjunction with modifications to the IPv6 header, particularly the Hop Limit, and SRH (Source Routing Header). In `net/ipv6/exthdrs.c`, when processing packets destined for the loopback interface, I see that they're decrementing the hop limit. The new code introduces the need to update the checksum if `skb->ip_summed == CHECKSUM_COMPLETE`. To handle this, I need to save the `old` value and pass both the old and new value to `update_csum_diff4()`. This ensures the checksum reflects the change in the Hop Limit field. Jumping over to `net/ipv6/seg6_iptunnel.c` where an L2 Encap mode is implemented. Here, the existing code is modified to call `skb_push_rcsum`. I need to ensure that the checksum is handled correctly, but this change seems to be primarily about Layer 2 encapsulation, so there shouldn't be too many issues here. In `net/ipv6/seg6_local.c`, the focus is on the `advance_nextseg()` function, which is crucial for SRH processing. Here, a segment is being advanced, updating the destination address and the SRH header itself. The code now includes checksum updates for both the SRH header and the destination address. Again, similar to `exthdrs.c`, I need to save the old values of the SRH header and destination address and pass them to `update_csum_diff4()` and `update_csum_diff16()` respectively, which allows proper recalculation of the checksum. The `seg6_next_csid_advance_arg()` function, also in `net/ipv6/seg6_local.c`, is updating the argument part of the destination address. Here, as the destination address is getting modified, the old and new destination address values should be saved and supplied to `update_csum_diff16` to perform an update on the checksum. Finally, in `net/ipv6/seg6_local.c`, I notice a change related to BPF (Berkeley Packet Filter). It seems a BPF program might modify the packet and potentially rewrite the SRH Header Extension Length, thus invalidating the packet checksum. Therefore, I need to call `skb_checksum_complete_unset()` to force the kernel to recalculate the checksum. Essentially, these changes are all about maintaining checksum integrity after modifying IPv6 headers, especially when SRH is involved. I will need to check how the `update_csum_diff4()` and `update_csum_diff16()` functions are implemented to fully understand the performance implications and ensure their correctness with respect to potential corner cases. I need to make sure the updates cover all possible packet modifications and address potential edge cases related to checksum offload and fragmented packets. |
| 62/3 | 2026/11/01 14:20 | tool | read-file |
0mArgs:{
"File": "net/ipv6/exthdrs.c",
"FirstLine": 445,
"LineCount": 45
}Results: {
"Contents": " 445:\t\thdr-\u003esegments_left--;\n 446:\t\taddr = hdr-\u003esegments + hdr-\u003esegments_left;\n 447:\t\n 448:\t\tskb_push(skb, -skb_network_offset(skb));\n 449:\t\n 450:\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\n 451:\t\t\tseg6_update_csum(skb);\n 452:\t\n 453:\t\tipv6_hdr(skb)-\u003edaddr = *addr;\n 454:\t\n 455:\t\tip6_route_input(skb);\n 456:\t\n 457:\t\tif (skb_dst(skb)-\u003eerror) {\n 458:\t\t\tdst_input(skb);\n 459:\t\t\treturn -1;\n 460:\t\t}\n 461:\t\n 462:\t\tif (skb_dst_dev(skb)-\u003eflags \u0026 IFF_LOOPBACK) {\n 463:\t\t\t/* payload_len, nexthdr and hop_limit */\n 464:\t\t\t__be32 *hlim_word = (__be32 *)ipv6_hdr(skb) + 1;\n 465:\t\t\t__be32 old;\n 466:\t\n 467:\t\t\tif (ipv6_hdr(skb)-\u003ehop_limit \u003c= 1) {\n 468:\t\t\t\t__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);\n 469:\t\t\t\ticmpv6_send(skb, ICMPV6_TIME_EXCEED,\n 470:\t\t\t\t\t ICMPV6_EXC_HOPLIMIT, 0);\n 471:\t\t\t\tkfree_skb_reason(skb, SKB_DROP_REASON_IP_TTL_EXCEEDED);\n 472:\t\t\t\treturn -1;\n 473:\t\t\t}\n 474:\t\t\told = *hlim_word;\n 475:\t\t\tipv6_hdr(skb)-\u003ehop_limit--;\n 476:\t\n 477:\t\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\n 478:\t\t\t\tupdate_csum_diff4(skb, old, *hlim_word);\n 479:\t\n 480:\t\t\tskb_pull(skb, skb_transport_offset(skb));\n 481:\t\t\tgoto looped_back;\n 482:\t\t}\n 483:\t\n 484:\t\tdst_input(skb);\n 485:\t\n 486:\t\treturn -1;\n 487:\t}\n 488:\t\n 489:\tstatic int ipv6_rpl_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n"
} |
| 63/3 | 2026/11/01 14:20 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 17595 output: 21 thoughts: 13 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience and presented in the first person: **Deep Dive into `seg6_update_csum`** Alright, let's zero in on `seg6_update_csum`. My initial instinct is to treat this function with a healthy dose of suspicion, as checksum updates can be tricky, especially in the context of something like Segment Routing v6 (SRv6). I'm immediately thinking about the potential for off-by-one errors, wrapping issues with the checksum calculations themselves (given the modular arithmetic involved), and how this function integrates with the underlying hardware acceleration, or lack thereof, on this system. I'm also curious about the specific use case. Is this for an intermediate router, an ingress node, or an egress node? The checksum algorithm would likely vary based on where in the SRv6 path this function is being called. Also, what part of the packet header is this checksum updating, the IPv6 header, the SRH extension header, or both? Are we assuming a particular hardware implementation? If so, what are the inherent limitations? Are there any compiler optimizations that could be introduced that would have a noticeable impact? I need to quickly assess how the checksum calculation itself is implemented. Is it a simple addition, a more robust CRC, or something else entirely? What are the potential vulnerabilities given the chosen algorithm? Are there any potential attack vectors? Can someone forge these checksums easily? Finally, and this is crucial, I need to understand how `seg6_update_csum` interacts with the rest of the SRv6 data plane. Is it thread-safe? Does it handle fragmented packets correctly? Does it account for packet reordering? Does it properly update checksums of nested headers? I need to look closely at its integration with the data path and ensure that the performance impact is minimized. In the back of my mind, I want to evaluate if the current implementation has potential bottlenecks. |
| 64/3 | 2026/11/01 14:21 | tool | grepper |
0mArgs:{
"Expression": "seg6_update_csum"
}Results: {
"Output": "net/ipv6/exthdrs.c=296=static int ipv6_destopt_rcv(struct sk_buff *skb)\n--\nnet/ipv6/exthdrs.c-341-\nnet/ipv6/exthdrs.c:342:static void seg6_update_csum(struct sk_buff *skb)\nnet/ipv6/exthdrs.c-343-{\n--\nnet/ipv6/exthdrs.c=371=static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n--\nnet/ipv6/exthdrs.c-450-\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE)\nnet/ipv6/exthdrs.c:451:\t\tseg6_update_csum(skb);\nnet/ipv6/exthdrs.c-452-\n"
} |
| 65/3 | 2026/11/01 14:21 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 18290 output: 39 thoughts: 27 Thoughts: Okay, here's my interpretation of what's going on in those lines of `net/ipv6/exthdrs.c`, as if it were my internal monologue: **Diving into IPv6 Extension Headers** Alright, let's pull up lines 340-370 in `net/ipv6/exthdrs.c`. I'm guessing we're dealing with either processing or generating these pesky extension headers, probably in the context of routing or fragmentation. Let's see... Ah, here we are. It looks like we're deep inside the logic that handles a particular extension header type. More specifically, from the looks of it, it is the code that is responsible for determining whether or not the header we have just encountered is to be processed. I can tell that we're potentially dealing with fragmented packets based on the variables being accessed. It looks like we are assessing whether the 'payload_len' is not enough to account for this type of header. I can see that some length checks are being performed. This makes perfect sense; IPv6 extension headers are notorious for being potential attack vectors if not handled correctly. We're probably doing a sanity check to avoid buffer overflows or other exploits. We are checking the remaining length in the packet against the minimum required size for this header type. Seems like we're comparing the remaining length against `hlen`, or the header length field that is provided in the header. We're obviously failing if the packet is too short. Okay, a conditional check here. If the length is insufficient, we bail out, probably with an error code like `EPROTO` or something similar indicating a malformed packet. The important thing is that the header is invalid, and the packet must be dropped, or handled upstream. Then there are some potential logging statements. The typical approach for diagnosing problems with IPv6 is to include logging. Overall, it is a straightforward validation step. The key takeaway is to ensure the integrity of the data stream. We want to avoid any possibility of reading beyond the packet's bounds. This is a crucial defense against potential vulnerabilities. Safety first. |
| 66/3 | 2026/11/01 14:21 | tool | read-file |
0mArgs:{
"File": "net/ipv6/exthdrs.c",
"FirstLine": 340,
"LineCount": 35
}Results: {
"Contents": " 340:\t}\n 341:\t\n 342:\tstatic void seg6_update_csum(struct sk_buff *skb)\n 343:\t{\n 344:\t\tstruct ipv6_sr_hdr *hdr;\n 345:\t\tstruct in6_addr *addr;\n 346:\t\t__be32 from, to;\n 347:\t\n 348:\t\t/* srh is at transport offset and seg_left is already decremented\n 349:\t\t * but daddr is not yet updated with next segment\n 350:\t\t */\n 351:\t\n 352:\t\thdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);\n 353:\t\taddr = hdr-\u003esegments + hdr-\u003esegments_left;\n 354:\t\n 355:\t\thdr-\u003esegments_left++;\n 356:\t\tfrom = *(__be32 *)hdr;\n 357:\t\n 358:\t\thdr-\u003esegments_left--;\n 359:\t\tto = *(__be32 *)hdr;\n 360:\t\n 361:\t\t/* update skb csum with diff resulting from seg_left decrement */\n 362:\t\n 363:\t\tupdate_csum_diff4(skb, from, to);\n 364:\t\n 365:\t\t/* compute csum diff between current and next segment and update */\n 366:\t\n 367:\t\tupdate_csum_diff16(skb, (__be32 *)(\u0026ipv6_hdr(skb)-\u003edaddr),\n 368:\t\t\t\t (__be32 *)addr);\n 369:\t}\n 370:\t\n 371:\tstatic int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)\n 372:\t{\n 373:\t\tstruct inet6_skb_parm *opt = IP6CB(skb);\n 374:\t\tstruct net *net = dev_net(skb-\u003edev);\n"
} |
| 67/3 | 2026/11/01 14:21 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 19339 output: 39 thoughts: 745 Thoughts: **Checksum Bug Found in SEG6 Code** Okay, let's break this down. I've been digging into the SEG6 code, specifically `seg6_update_csum`, and I've spotted something significant. I was looking at `update_csum_diff4(skb, from, to)` and `update_csum_diff16(...)`, and the implementation of `update_csum_diff4` in `include/net/seg6.h` immediately caught my eye. The inline function used to look like: `skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);`. But now it correctly implements: `skb->csum = csum_partial(diff, sizeof(diff), skb->csum);`. Wait a minute, the original code had an *inverted* checksum calculation. Specifically, `~csum_partial(diff, len, ~csum)` is the *wrong* way to update the checksum. The RFC and standard approach for updating a checksum, when you subtract an old value (`from`) and add a new value (`to`), is `~from + to`. So, if you pass `~from` and `to` to `csum_partial` with an initial `skb->csum`, you are, in effect, performing `skb->csum + ~from + to` in 1's complement arithmetic, which is correct. The old code was effectively doing `~csum_partial(..., ~skb->csum)`, which is incorrect! This was a straight-up checksum calculation bug! Next, I shifted my attention to `net/ipv6/seg6_iptunnel.c`. Here, the change from `skb_push(skb, skb->mac_len)` to `skb_push_rcsum(skb, skb->mac_len)` is significant. If `CHECKSUM_COMPLETE` is set, simply pushing the MAC header without updating the checksum would result in the `skb->csum` not covering the header, or the header not being covered by `skb->csum`, depending on the assumptions about the checksum's completion. `skb_push_rcsum` is the correct function to use because it properly updates `skb->csum` by adding the checksum of the pushed data *if* `ip_summed == CHECKSUM_COMPLETE`. Finally, I checked `net/ipv6/seg6_local.c`, specifically the `advance_nextseg` function. Here, I'm tracking the changes to the destination address. I noticed a key point around line 290. The variable `old` is initialized to `*(__be32 *)srh` and the code accesses `*(__be32 *)srh`. Importantly, `skb_ensure_writable(skb, srhoff + sizeof(struct ipv6_sr_hdr))` had already been called earlier in this function. This means the code is correctly updating the checksum using `update_csum_diff4` and `update_csum_diff16` when appropriate. The previous vulnerability has been corrected. |
| 68/3 | 2026/11/01 14:21 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_local.c",
"FirstLine": 285,
"LineCount": 45
}Results: {
"Contents": " 285:\t * This function returns:\n 286:\t * - the SRH on success;\n 287:\t * - NULL when the skb cannot be made writable. In this case, the function\n 288:\t * sets the drop reason to SKB_DROP_REASON_NOMEM.\n 289:\t */\n 290:\tstatic struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,\n 291:\t\t\t\t\t\t struct ipv6_sr_hdr *srh,\n 292:\t\t\t\t\t\t enum skb_drop_reason *reason)\n 293:\t{\n 294:\t\tstruct in6_addr *daddr;\n 295:\t\tstruct in6_addr *addr;\n 296:\t\t__be32 old;\n 297:\t\tint srhoff;\n 298:\t\tint wlen;\n 299:\t\n 300:\t\tsrhoff = (unsigned char *)srh - skb-\u003edata;\n 301:\t\t/* we write only the Segment Left field and the IPv6 DA. The segment\n 302:\t\t * list is only read, and seg6_get_srh() already pulled it into the\n 303:\t\t * linear area.\n 304:\t\t */\n 305:\t\twlen = srhoff + sizeof(*srh);\n 306:\t\n 307:\t\tif (unlikely(skb_ensure_writable(skb, wlen))) {\n 308:\t\t\t*reason = SKB_DROP_REASON_NOMEM;\n 309:\t\t\treturn NULL;\n 310:\t\t}\n 311:\t\n 312:\t\t/* skb_ensure_writable() may change skb pointers; evaluate srh again */\n 313:\t\tsrh = (struct ipv6_sr_hdr *)(skb-\u003edata + srhoff);\n 314:\t\tdaddr = \u0026ipv6_hdr(skb)-\u003edaddr;\n 315:\t\t/* nexthdr, hdrlen, type and segments_left */\n 316:\t\told = *(__be32 *)srh;\n 317:\t\n 318:\t\tsrh-\u003esegments_left--;\n 319:\t\taddr = srh-\u003esegments + srh-\u003esegments_left;\n 320:\t\n 321:\t\tif (skb-\u003eip_summed == CHECKSUM_COMPLETE) {\n 322:\t\t\tupdate_csum_diff4(skb, old, *(__be32 *)srh);\n 323:\t\t\tupdate_csum_diff16(skb, (__be32 *)daddr, (__be32 *)addr);\n 324:\t\t}\n 325:\t\n 326:\t\t*daddr = *addr;\n 327:\t\n 328:\t\treturn srh;\n 329:\t}\n"
} |
| 69/3 | 2026/11/01 14:21 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 21559 output: 40 thoughts: 374 Thoughts: **Analyzing IPv6 Header Manipulation and Checksum Updates** Okay, let's break down this code. I need to understand what's happening with `seg6_next_csid_advance_arg`. It looks like we're working with an IPv6 destination address (`daddr`) within an `skb`. The goal here seems to be to advance some argument, likely related to a segment routing header (SRH). First, I see the address is being moved. Specifically, `memmove` is used to shift bytes within the `s6_addr` array of the destination IPv6 address. This seems to be the core of the argument advancement. After the move, the shifted bytes are cleared with `memset` by filling them with 0x00. I need to keep in mind the meaning of `blk_octects` and `fnc_octects` - they are defining the number of octets we're manipulating. Now, the important part: checksum handling. If the packet's checksum is complete (`CHECKSUM_COMPLETE`), we have to call `update_csum_diff16`. `old` is initialized from the original `daddr` content, which is a `struct in6_addr`, and the new value is, of course, the modified `daddr`. I need to be sure that `old` and `addr` values were properly initialized for the `diff` to work correctly within `update_csum_diff16`. No apparent uninitialized variables here, that's good. Next, I need to look at `input_action_end_bpf`. The comment mentions that a BPF program might have modified the packet. And the SRH might be rewritten by `seg6_bpf_has_valid_srh()`. This is important because changing the SRH can affect the packet's checksum. If the program changes `skb` contents, `skb->csum` will no longer represent a complete checksum of the packet. Therefore, `skb_checksum_complete_unset(skb)` is called to indicate that the checksum is no longer valid. I need to investigate around line 1566 to understand the context a little better. |
| 70/3 | 2026/11/01 14:21 | tool | read-file |
0mArgs:{
"File": "net/ipv6/seg6_local.c",
"FirstLine": 1560,
"LineCount": 40
}Results: {
"Contents": "1560:\t\t * statement. It is also accessed by the bpf_lwt_seg6_* helpers via\n1561:\t\t * bpf_prog_run_save_cb().\n1562:\t\t */\n1563:\t\tlocal_lock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\n1564:\t\tsrh_state = this_cpu_ptr(\u0026seg6_bpf_srh_states);\n1565:\t\tsrh_state-\u003esrh = srh;\n1566:\t\tsrh_state-\u003ehdrlen = srh-\u003ehdrlen \u003c\u003c 3;\n1567:\t\tsrh_state-\u003evalid = true;\n1568:\t\n1569:\t\trcu_read_lock();\n1570:\t\tbpf_compute_data_pointers(skb);\n1571:\t\tret = bpf_prog_run_save_cb(slwt-\u003ebpf.prog, skb);\n1572:\t\trcu_read_unlock();\n1573:\t\n1574:\t\tswitch (ret) {\n1575:\t\tcase BPF_OK:\n1576:\t\tcase BPF_REDIRECT:\n1577:\t\t\tbreak;\n1578:\t\tcase BPF_DROP:\n1579:\t\t\tgoto drop;\n1580:\t\tdefault:\n1581:\t\t\tpr_warn_once(\"bpf-seg6local: Illegal return value %u\\n\", ret);\n1582:\t\t\tgoto drop;\n1583:\t\t}\n1584:\t\n1585:\t\t/* The program may have changed the packet and seg6_bpf_has_valid_srh()\n1586:\t\t * may rewrite the SRH Hdr Ext Len below.\n1587:\t\t * skb-\u003ecsum may then no longer be the checksum of the full packet.\n1588:\t\t */\n1589:\t\tskb_checksum_complete_unset(skb);\n1590:\t\n1591:\t\tif (srh_state-\u003esrh \u0026\u0026 !seg6_bpf_has_valid_srh(skb))\n1592:\t\t\tgoto drop;\n1593:\t\tlocal_unlock_nested_bh(\u0026seg6_bpf_srh_states.bh_lock);\n1594:\t\n1595:\t\tif (ret != BPF_REDIRECT)\n1596:\t\t\tseg6_lookup_nexthop(skb, NULL, 0);\n1597:\t\n1598:\t\treturn dst_input(skb);\n1599:\t\n"
} |
| 71/3 | 2026/11/01 14:21 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 23109 output: 22 thoughts: 14 Thoughts: Here's a summary of my thought process, as requested: **Diving into `skb_checksum_complete_unset`** Okay, time to dissect `skb_checksum_complete_unset`. My understanding is that this function plays a crucial role in managing checksum flags within the `sk_buff` structure. It's likely involved in clearing checksum completion status, potentially in scenarios where the checksum needs to be recalculated, or when the packet is modified. I need to understand the exact conditions under which this unset operation takes place. Is it always done preemptively before the checksum is verified or can it be called after verification? I'm thinking this function may be used when a packet undergoes manipulation, like reassembly or segmentation, where the initial checksum may no longer be valid. It probably involves interaction with hardware checksum offloading capabilities as well. I'll need to check the surrounding code for clues. Time to dig deeper and see what I can find. |
| 72/3 | 2026/11/01 14:21 | tool | grepper |
0mArgs:{
"Expression": "skb_checksum_complete_unset"
}Results: {
"Output": "drivers/net/ppp/ppp_generic.c=2474=ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)\ndrivers/net/ppp/ppp_generic.c-2475-{\ndrivers/net/ppp/ppp_generic.c:2476:\tskb_checksum_complete_unset(skb);\ndrivers/net/ppp/ppp_generic.c-2477-#ifdef CONFIG_PPP_MULTILINK\n--\ninclude/linux/skbuff.h=4857=static inline bool __skb_checksum_validate_needed(struct sk_buff *skb,\n--\ninclude/linux/skbuff.h-4880- */\ninclude/linux/skbuff.h:4881:static inline void skb_checksum_complete_unset(struct sk_buff *skb)\ninclude/linux/skbuff.h-4882-{\n--\nnet/ipv4/udp.c=2583=static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh)\n--\nnet/ipv4/udp.c-2603-\t\t */\nnet/ipv4/udp.c:2604:\t\tskb_checksum_complete_unset(skb);\nnet/ipv4/udp.c-2605-\t}\n--\nnet/ipv6/seg6_local.c=1538=static int input_action_end_bpf(struct sk_buff *skb,\n--\nnet/ipv6/seg6_local.c-1588-\t */\nnet/ipv6/seg6_local.c:1589:\tskb_checksum_complete_unset(skb);\nnet/ipv6/seg6_local.c-1590-\n--\nnet/ipv6/udp.c=1044=static int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh)\n--\nnet/ipv6/udp.c-1069-\t\t */\nnet/ipv6/udp.c:1070:\t\tskb_checksum_complete_unset(skb);\nnet/ipv6/udp.c-1071-\t}\n"
} |
| 73/3 | 2026/11/01 14:21 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 23902 output: 360 thoughts: 1069 Thoughts: **KMSAN Assessment: No New Risks Introduced**
Okay, let's break this down. First, I checked the new test files – `srv6_csum_complete.bpf.c` and the associated shell script – they're just selftests, nothing concerning in themselves.
Now, the main focus here is whether this patch warrants a KMSAN fuzzing session. I need to go through my mental checklist:
1. **Kernel data to userspace?** Nope. The changes don't touch any code paths that involve `copy_to_user`, `put_user`, netlink attributes, ioctl output arguments, socket options, or BPF buffers. No kernel data is being leaked out to user space, so that's a no.
2. **Conditional logic based on uninitialized data?** No again. The variables involved in branching logic (`skb->ip_summed`, `ipv6_hdr(skb)->hop_limit`) are all already properly initialized fields, or derived from them. No worries there.
3. **Complex data structures with potential uninitialized fields?** Not this time. The `diff` arrays in `update_csum_diff4` and `update_csum_diff16` are fully initialized on the stack right away: `__be32 diff[] = { ~from, to };` and `__be32 diff[] = { ~from[0], ~from[1], ~from[2], ~from[3], to[0], to[1], to[2], to[3] };`. The `old` variable in `ipv6_srh_rcv` is initialized via `old = *hlim_word;` and in `advance_nextseg` `old = *(__be32 *)srh;`, in `seg6_next_csid_advance_arg` `old = *addr;`.
4. **Bounds checks exposing uninitialized memory?** Doesn't look like it. The patch doesn't change packet buffer length or bounds checks, if anything the changes made make things more conservative with the use of `skb_checksum_complete_unset`.
So, what's this patch actually doing? It's fixing IPv6 Segment Routing (SRv6) `CHECKSUM_COMPLETE` handling: correcting some checksum calculations and ensuring `skb->csum` is kept updated. It modifies `skb->csum` when the hop limit is decremented and when segments/destination addresses are changed. It also resets `CHECKSUM_COMPLETE` when BPF programs might have mutated the packet content. Plus, it adds new self-tests.
The critical thing is, are any uninitialized memory risks being introduced? No. All the local variables (`old`, `diff`) are initialized before use, and packet headers are already populated. No data is being copied to userspace, no new structures with potential uninitialized fields are introduced, and no uninitialized padding is in play.
Therefore, this patch does *not* introduce any uninitialized memory risks. A KMSAN fuzzing session is not necessary here. Standard KASAN/sanitizers are perfectly adequate because it's purely networking checksum logic, and any out-of-bounds access or memory corruption would already be caught by them. KMSAN is for detecting info-leaks.
To clarify the reasoning, KASAN covers any out-of-bounds packet data access, pointer errors, or memory corruption. KMSAN detects the uses of uninitialized memory and information leaks to userspace. This patch purely corrects checksum math and maintains `skb->csum` consistency, or unsets `CHECKSUM_COMPLETE`. All the variables are immediately and fully initialized, and no kernel data is exposed to userspace. No KMSAN.
I'll call `set-results` with `NeedsKMSAN=false` and a detailed `KMSANReasoning`. Done.
|
| 74/3 | 2026/11/01 14:22 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch series addresses CHECKSUM_COMPLETE maintenance and checksum update formulas in IPv6 Segment Routing (SRv6). Specifically:\n1. It corrects the math in `update_csum_diff4` and `update_csum_diff16` by removing incorrect 1's complement inversions in `csum_partial`.\n2. It adds differential checksum updates (`update_csum_diff4` / `update_csum_diff16`) when modifying hop limit or destination addresses in `ipv6_srh_rcv`, `advance_nextseg`, and `seg6_next_csid_advance_arg`.\n3. It switches `skb_push` to `skb_push_rcsum` in `seg6_iptunnel.c` and calls `skb_checksum_complete_unset(skb)` in `seg6_local.c` after End.BPF actions.\n4. It adds selftests for CHECKSUM_COMPLETE validation under SRv6.\n\nNone of these changes introduce or expose uninitialized memory risks:\n- All new stack variables (`old`, `diff`) are immediately and fully initialized before read.\n- Packet accesses operate on verified, existing packet header buffers.\n- No data structures or padding bytes are copied to userspace or leaked.\n- Control flow branching does not depend on uninitialized variables.\n\nAny potential packet buffer boundary issues or memory corruptions are within the scope of standard KASAN/network stack checks. Thus, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch series addresses CHECKSUM_COMPLETE maintenance and checksum update formulas in IPv6 Segment Routing (SRv6). Specifically:\n1. It corrects the math in `update_csum_diff4` and `update_csum_diff16` by removing incorrect 1's complement inversions in `csum_partial`.\n2. It adds differential checksum updates (`update_csum_diff4` / `update_csum_diff16`) when modifying hop limit or destination addresses in `ipv6_srh_rcv`, `advance_nextseg`, and `seg6_next_csid_advance_arg`.\n3. It switches `skb_push` to `skb_push_rcsum` in `seg6_iptunnel.c` and calls `skb_checksum_complete_unset(skb)` in `seg6_local.c` after End.BPF actions.\n4. It adds selftests for CHECKSUM_COMPLETE validation under SRv6.\n\nNone of these changes introduce or expose uninitialized memory risks:\n- All new stack variables (`old`, `diff`) are immediately and fully initialized before read.\n- Packet accesses operate on verified, existing packet header buffers.\n- No data structures or padding bytes are copied to userspace or leaked.\n- Control flow branching does not depend on uninitialized variables.\n\nAny potential packet buffer boundary issues or memory corruptions are within the scope of standard KASAN/network stack checks. Thus, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|