| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/10/21 21:13 | flow | patch-triage |
6mArgs:null Results: {
"EnableConfigs": [
"DEBUG_NET",
"INET",
"IPV6",
"TLS",
"NET_CRC32C",
"IP_SCTP",
"SUNRPC"
],
"FocusSymbols": [
"skb_segment",
"skb_checksum_full",
"skb_copy_and_csum_bits",
"skb_crc32c_full",
"skb_crc32c_csum_help",
"skb_zerocopy",
"skb_try_coalesce",
"skb_copy_and_csum_dev",
"tls_sw_recvmsg",
"csum_partial_copy_to_xdr"
],
"KMSANReasoning": "The patch series refactors SKB checksum and CRC helpers (`skb_checksum_full`, `skb_copy_and_csum_bits`, `skb_crc32c_full`) to propagate error codes rather than silently returning 0 on unreadable frags or buffer overruns. It also replaces several `BUG_ON()` calls with error handling and adds checks against invalid nested frag_lists in `skb_segment()`.\n\nFrom a memory sanitization perspective:\n1. All out-pointer arguments (`csump`, `crcp`) are either initialized before calling or guarded by return value checks ensuring they are only read on success.\n2. `skb_copy_and_csum_bits()` explicitly zeroes out destination buffers with `memset()` on error paths to prevent callers from accessing stale/uninitialized memory.\n3. No kernel-to-userspace data leaks, uninitialized struct fields, or branching on uninitialized data are introduced.\n4. The bugs being addressed (buffer bounds, invalid frag geometry, BUG_ON conditions) are covered by KASAN and standard kernel debug assertions.\n\nTherefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false,
"Reasoning": "The patch series refactors core socket buffer (skbuff) checksumming and copying routines in net/core/skbuff.c and net/core/dev.c. It introduces skb_checksum_full() and skb_crc32c_full() to propagate errors, refactors skb_copy_and_csum_bits() and its call sites across core networking (IPv4, IPv6, SunRPC), updates GSO segmentation validation in skb_segment(), and adds multiple runtime assertions via DEBUG_NET_WARN_ON_ONCE() and WARN_ON_ONCE(). These reachable paths in core networking warrant fuzzing.",
"WorthFuzzing": true
} |
| 1/1 | 2026/10/21 21:13 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 9fec1e72dd0e9fa7934a768897145f6e40a2e828\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Oct 21 21:13:50 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/sun/sunvnet_common.c b/drivers/net/ethernet/sun/sunvnet_common.c\nindex 5cca958690521..4f229fcecc32f 100644\n--- a/drivers/net/ethernet/sun/sunvnet_common.c\n+++ b/drivers/net/ethernet/sun/sunvnet_common.c\n@@ -1167,9 +1167,13 @@ static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies)\n \n \t\t\t/* copy the rest, with csum calculation */\n \t\t\t*(__sum16 *)(skb-\u003edata + offset) = 0;\n-\t\t\tcsum = skb_copy_and_csum_bits(skb, start,\n-\t\t\t\t\t\t nskb-\u003edata + start,\n-\t\t\t\t\t\t skb-\u003elen - start);\n+\t\t\tif (skb_copy_and_csum_bits(skb, start,\n+\t\t\t\t\t\t nskb-\u003edata + start,\n+\t\t\t\t\t\t skb-\u003elen - start, \u0026csum)) {\n+\t\t\t\tdev_kfree_skb(nskb);\n+\t\t\t\tdev_kfree_skb(skb);\n+\t\t\t\treturn NULL;\n+\t\t\t}\n \n \t\t\t/* add in the header checksums */\n \t\t\tif (skb-\u003eprotocol == htons(ETH_P_IP)) {\ndiff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c\nindex fdcb91042f290..17811d81937c6 100644\n--- a/drivers/net/xen-netfront.c\n+++ b/drivers/net/xen-netfront.c\n@@ -695,7 +695,12 @@ static struct sk_buff *bounce_skb(const struct sk_buff *skb)\n \t/* Set the tail pointer and length */\n \tskb_put(n, skb-\u003elen);\n \n-\tBUG_ON(skb_copy_bits(skb, -headerlen, n-\u003ehead, headerlen + skb-\u003elen));\n+\tif (unlikely(skb_copy_bits(skb, -headerlen, n-\u003ehead,\n+\t\t\t\t headerlen + skb-\u003elen))) {\n+\t\tDEBUG_NET_WARN_ON_ONCE(1);\n+\t\tkfree_skb(n);\n+\t\treturn NULL;\n+\t}\n \n \tskb_copy_header(n, skb);\n \treturn n;\ndiff --git a/include/linux/skbuff.h b/include/linux/skbuff.h\nindex af1cbc2799b77..327a01a5d6d0b 100644\n--- a/include/linux/skbuff.h\n+++ b/include/linux/skbuff.h\n@@ -4277,8 +4277,10 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb);\n int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);\n int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);\n int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);\n-__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,\n-\t\t\t int len);\n+int __must_check skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\n+\t\t\t\t\tu8 *to, int len, __wsum *csum);\n+int __must_check skb_checksum_full(const struct sk_buff *skb, int offset,\n+\t\t\t\t int len, __wsum *csump);\n int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,\n \t\t struct pipe_inode_info *pipe, unsigned int len,\n \t\t unsigned int flags);\n@@ -4327,6 +4329,8 @@ static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)\n \n __wsum skb_checksum(const struct sk_buff *skb, int offset, int len,\n \t\t __wsum csum);\n+int __must_check skb_crc32c_full(const struct sk_buff *skb, int offset,\n+\t\t\t\t int len, u32 *crcp);\n u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc);\n \n static inline void * __must_check\ndiff --git a/net/core/dev.c b/net/core/dev.c\nindex 8eb9bf1ff9eb6..1d34fa4544a25 100644\n--- a/net/core/dev.c\n+++ b/net/core/dev.c\n@@ -3738,8 +3738,11 @@ int skb_crc32c_csum_help(struct sk_buff *skb)\n \tif (ret)\n \t\tgoto out;\n \n-\tcrc = ~skb_crc32c(skb, start, skb-\u003elen - start, ~0);\n-\t*(__le32 *)(skb-\u003edata + offset) = cpu_to_le32(crc);\n+\tcrc = ~0;\n+\tret = skb_crc32c_full(skb, start, skb-\u003elen - start, \u0026crc);\n+\tif (ret)\n+\t\tgoto out;\n+\t*(__le32 *)(skb-\u003edata + offset) = cpu_to_le32(~crc);\n \tskb_reset_csum_not_inet(skb);\n out:\n \treturn ret;\ndiff --git a/net/core/filter.c b/net/core/filter.c\nindex 3ee1a093337e3..f5bce0dc43fe0 100644\n--- a/net/core/filter.c\n+++ b/net/core/filter.c\n@@ -3696,9 +3696,9 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,\n \t\tshinfo-\u003egso_segs = 0;\n \n \t\t/* Due to header growth, MSS needs to be downgraded.\n-\t\t * There is a BUG_ON() when segmenting the frag_list with\n-\t\t * head_frag true, so linearize the skb after downgrading\n-\t\t * the MSS.\n+\t\t * Segmenting a frag_list with head_frag true at the new MSS\n+\t\t * fails and the packet gets dropped, so linearize the skb\n+\t\t * after downgrading the MSS.\n \t\t */\n \t\tif (!(flags \u0026 BPF_F_ADJ_ROOM_FIXED_GSO)) {\n \t\t\tskb_decrease_gso_size(shinfo, len_diff);\ndiff --git a/net/core/net_test.c b/net/core/net_test.c\nindex bc2ef7612e7df..222d24793591c 100644\n--- a/net/core/net_test.c\n+++ b/net/core/net_test.c\n@@ -39,6 +39,8 @@ enum gso_test_nr {\n \tGSO_TEST_RESEGMENT_MULTI,\n \tGSO_TEST_RESEGMENT_TAIL,\n \tGSO_TEST_RESEGMENT_ONE_MSS,\n+\tGSO_TEST_FRAG_LIST_NON_UNIFORM_SG,\n+\tGSO_TEST_FRAG_LIST_NESTED,\n };\n \n struct gso_test_case {\n@@ -57,6 +59,9 @@ struct gso_test_case {\n \tunsigned int nr_segs;\n \tconst unsigned int *segs;\n \tconst unsigned int *gso_segs;\n+\n+\t/* skb_segment() is expected to fail with this error */\n+\tint err;\n };\n \n static struct gso_test_case cases[] = {\n@@ -204,6 +209,28 @@ static struct gso_test_case cases[] = {\n \t\t},\n \t\t.gso_segs = (const unsigned int[]) { 0, 0, 0, 0 },\n \t},\n+\t{\n+\t\t/* frag_list members that don't end on gso_size boundaries\n+\t\t * can't be segmented with SG\n+\t\t */\n+\t\t.id = GSO_TEST_FRAG_LIST_NON_UNIFORM_SG,\n+\t\t.name = \"frag_list_non_uniform_sg\",\n+\t\t.linear_len = GSO_TEST_SIZE,\n+\t\t.nr_frag_skbs = 4,\n+\t\t.frag_skbs = (const unsigned int[]) { GSO_TEST_SIZE, 1, GSO_TEST_SIZE, 2 },\n+\t\t.err = -EINVAL,\n+\t},\n+\t{\n+\t\t/* the second frag_list member hangs off the first one's\n+\t\t * frag_list instead of off the head's\n+\t\t */\n+\t\t.id = GSO_TEST_FRAG_LIST_NESTED,\n+\t\t.name = \"frag_list_nested\",\n+\t\t.linear_len = GSO_TEST_SIZE,\n+\t\t.nr_frag_skbs = 2,\n+\t\t.frag_skbs = (const unsigned int[]) { GSO_TEST_SIZE, GSO_TEST_SIZE },\n+\t\t.err = -EINVAL,\n+\t},\n };\n \n static void gso_test_case_to_desc(struct gso_test_case *t, char *desc)\n@@ -283,19 +310,41 @@ static void gso_test_func(struct kunit *test)\n \n \t\tif (tcase-\u003eid == GSO_TEST_GSO_BY_FRAGS)\n \t\t\tskb_shinfo(skb)-\u003egso_size = GSO_BY_FRAGS;\n+\n+\t\tif (tcase-\u003eid == GSO_TEST_FRAG_LIST_NESTED) {\n+\t\t\tstruct sk_buff *first = skb_shinfo(skb)-\u003efrag_list;\n+\n+\t\t\tskb_shinfo(first)-\u003efrag_list = first-\u003enext;\n+\t\t\tfirst-\u003enext = NULL;\n+\t\t\tfirst-\u003elen += tcase-\u003efrag_skbs[1];\n+\t\t\tfirst-\u003edata_len += tcase-\u003efrag_skbs[1];\n+\t\t}\n \t}\n \n \tfeatures = NETIF_F_SG | NETIF_F_HW_CSUM;\n \tif (tcase-\u003eid == GSO_TEST_GSO_PARTIAL)\n \t\tfeatures |= NETIF_F_GSO_PARTIAL;\n \n-\t/* TODO: this should also work with SG,\n-\t * rather than hit BUG_ON(i \u003e= nfrags)\n+\t/* TODO: this should also work with SG, rather than fail the\n+\t * i \u003e= nfrags check in skb_segment()\n \t */\n \tif (tcase-\u003eid == GSO_TEST_FRAG_LIST_NON_UNIFORM)\n \t\tfeatures \u0026= ~NETIF_F_SG;\n \n \tSKB_GSO_CB(skb)-\u003emax_segs = tcase-\u003emax_segs;\n+\n+\tif (tcase-\u003eerr) {\n+\t\t/* the suppression block doesn't run if it can't be set up */\n+\t\tsegs = NULL;\n+\t\tkunit_warning_suppress(test) {\n+\t\t\tsegs = skb_segment(skb, features);\n+\t\t}\n+\t\tKUNIT_EXPECT_EQ(test, PTR_ERR_OR_ZERO(segs), tcase-\u003eerr);\n+\t\tif (!IS_ERR_OR_NULL(segs))\n+\t\t\tkfree_skb_list(segs);\n+\t\tgoto free_gso_skb;\n+\t}\n+\n \tsegs = skb_segment(skb, features);\n \tif (IS_ERR(segs)) {\n \t\tKUNIT_FAIL(test, \"segs error %pe\", segs);\ndiff --git a/net/core/skbuff.c b/net/core/skbuff.c\nindex 93c2f440b9ece..e0c8f2f6bfac1 100644\n--- a/net/core/skbuff.c\n+++ b/net/core/skbuff.c\n@@ -2829,9 +2829,13 @@ static int pskb_trim_rcsum_complete(struct sk_buff *skb, unsigned int len)\n \tint delta = skb-\u003elen - len;\n \n \tif (skb_frags_readable(skb)) {\n-\t\tskb-\u003ecsum = csum_block_sub(skb-\u003ecsum,\n-\t\t\t\t\t skb_checksum(skb, len, delta, 0),\n-\t\t\t\t\t len);\n+\t\t__wsum csum = 0;\n+\t\tint err;\n+\n+\t\terr = skb_checksum_full(skb, len, delta, \u0026csum);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t\tskb-\u003ecsum = csum_block_sub(skb-\u003ecsum, csum, len);\n \t\treturn 0;\n \t}\n \n@@ -3545,12 +3549,31 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)\n EXPORT_SYMBOL(skb_store_bits);\n \n /* Checksum skb data. */\n-__wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)\n+/**\n+ *\tskb_checksum_full - checksum a range of an skb\n+ *\t@skb: buffer to checksum\n+ *\t@offset: offset in @skb to start at\n+ *\t@len: number of bytes to checksum\n+ *\t@csump: the sum to add to; on success the range's sum is added to it\n+ *\n+ *\tReturn: 0 on success, -EINVAL if @len is negative, or -EFAULT if @skb\n+ *\thas unreadable frags in the range or runs out before @len does. On\n+ *\tfailure *@csump is not changed.\n+ */\n+int skb_checksum_full(const struct sk_buff *skb, int offset, int len,\n+\t\t __wsum *csump)\n {\n \tint start = skb_headlen(skb);\n \tint i, copy = start - offset;\n \tstruct sk_buff *frag_iter;\n+\t__wsum csum = *csump;\n \tint pos = 0;\n+\tint err;\n+\n+\tif (unlikely(len \u003c 0)) {\n+\t\tDEBUG_NET_WARN_ON_ONCE(1);\n+\t\treturn -EINVAL;\n+\t}\n \n \t/* Checksum header. */\n \tif (copy \u003e 0) {\n@@ -3558,13 +3581,13 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)\n \t\t\tcopy = len;\n \t\tcsum = csum_partial(skb-\u003edata + offset, copy, csum);\n \t\tif ((len -= copy) == 0)\n-\t\t\treturn csum;\n+\t\t\tgoto out;\n \t\toffset += copy;\n \t\tpos\t= copy;\n \t}\n \n-\tif (WARN_ON_ONCE(!skb_frags_readable(skb)))\n-\t\treturn 0;\n+\tif (!skb_frags_readable(skb))\n+\t\treturn -EFAULT;\n \n \tfor (i = 0; i \u003c skb_shinfo(skb)-\u003enr_frags; i++) {\n \t\tint end;\n@@ -3593,7 +3616,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)\n \t\t\t}\n \n \t\t\tif (!(len -= copy))\n-\t\t\t\treturn csum;\n+\t\t\t\tgoto out;\n \t\t\toffset += copy;\n \t\t}\n \t\tstart = end;\n@@ -3606,14 +3629,17 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)\n \n \t\tend = start + frag_iter-\u003elen;\n \t\tif ((copy = end - offset) \u003e 0) {\n-\t\t\t__wsum csum2;\n+\t\t\t__wsum csum2 = 0;\n+\n \t\t\tif (copy \u003e len)\n \t\t\t\tcopy = len;\n-\t\t\tcsum2 = skb_checksum(frag_iter, offset - start, copy,\n-\t\t\t\t\t 0);\n+\t\t\terr = skb_checksum_full(frag_iter, offset - start, copy,\n+\t\t\t\t\t\t\u0026csum2);\n+\t\t\tif (err)\n+\t\t\t\treturn err;\n \t\t\tcsum = csum_block_add(csum, csum2, pos);\n \t\t\tif ((len -= copy) == 0)\n-\t\t\t\treturn csum;\n+\t\t\t\tgoto out;\n \t\t\toffset += copy;\n \t\t\tpos += copy;\n \t\t}\n@@ -3621,23 +3647,59 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)\n \t}\n \tif (unlikely(len)) {\n \t\tDEBUG_NET_WARN_ON_ONCE(1);\n-\t\treturn 0;\n+\t\treturn -EFAULT;\n \t}\n+out:\n+\t*csump = csum;\n+\treturn 0;\n+}\n+EXPORT_SYMBOL(skb_checksum_full);\n \n+/* skb_checksum() has no way to report failure, so it returns 0, which is a\n+ * valid checksum. Use skb_checksum_full() in new code.\n+ */\n+__wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)\n+{\n+\tif (unlikely(skb_checksum_full(skb, offset, len, \u0026csum))) {\n+\t\tWARN_ON_ONCE(!skb_frags_readable(skb));\n+\t\treturn 0;\n+\t}\n \treturn csum;\n }\n EXPORT_SYMBOL(skb_checksum);\n \n /* Both of above in one bottle. */\n \n-__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\n-\t\t\t\t u8 *to, int len)\n+/**\n+ *\tskb_copy_and_csum_bits - copy data out of an skb and checksum it\n+ *\t@skb: source buffer\n+ *\t@offset: offset in @skb to start copying from\n+ *\t@to: destination buffer\n+ *\t@len: number of bytes to copy\n+ *\t@csump: where to store the checksum of the copied bytes\n+ *\n+ *\tReturn: 0 on success, -EINVAL if @len is negative, or -EFAULT if @skb\n+ *\thas unreadable frags or runs out before @len does. On failure *@csump\n+ *\tis not set, and on -EFAULT the part of @to that couldn't be filled is\n+ *\tzeroed.\n+ */\n+int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\n+\t\t\t u8 *to, int len, __wsum *csump)\n {\n \tint start = skb_headlen(skb);\n \tint i, copy = start - offset;\n \tstruct sk_buff *frag_iter;\n \tint pos = 0;\n \t__wsum csum = 0;\n+\tint err;\n+\n+\t/* Everything below clamps copies to @len, so a negative one would\n+\t * turn into a huge copy.\n+\t */\n+\tif (unlikely(len \u003c 0)) {\n+\t\tDEBUG_NET_WARN_ON_ONCE(1);\n+\t\treturn -EINVAL;\n+\t}\n \n \t/* Copy header. */\n \tif (copy \u003e 0) {\n@@ -3646,7 +3708,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\n \t\tcsum = csum_partial_copy_nocheck(skb-\u003edata + offset, to,\n \t\t\t\t\t\t copy);\n \t\tif ((len -= copy) == 0)\n-\t\t\treturn csum;\n+\t\t\tgoto out;\n \t\toffset += copy;\n \t\tto += copy;\n \t\tpos\t= copy;\n@@ -3656,7 +3718,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\n \t\t/* Don't hand the caller a buffer with stale bytes in it. */\n \t\tif (len \u003e 0)\n \t\t\tmemset(to, 0, len);\n-\t\treturn 0;\n+\t\treturn -EFAULT;\n \t}\n \n \tfor (i = 0; i \u003c skb_shinfo(skb)-\u003enr_frags; i++) {\n@@ -3688,7 +3750,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\n \t\t\t}\n \n \t\t\tif (!(len -= copy))\n-\t\t\t\treturn csum;\n+\t\t\t\tgoto out;\n \t\t\toffset += copy;\n \t\t\tto += copy;\n \t\t}\n@@ -3705,12 +3767,16 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\n \t\tif ((copy = end - offset) \u003e 0) {\n \t\t\tif (copy \u003e len)\n \t\t\t\tcopy = len;\n-\t\t\tcsum2 = skb_copy_and_csum_bits(frag_iter,\n-\t\t\t\t\t\t offset - start,\n-\t\t\t\t\t\t to, copy);\n+\t\t\terr = skb_copy_and_csum_bits(frag_iter, offset - start,\n+\t\t\t\t\t\t to, copy, \u0026csum2);\n+\t\t\tif (err) {\n+\t\t\t\t/* The child zeroed its part; zero the rest. */\n+\t\t\t\tmemset(to + copy, 0, len - copy);\n+\t\t\t\treturn err;\n+\t\t\t}\n \t\t\tcsum = csum_block_add(csum, csum2, pos);\n \t\t\tif ((len -= copy) == 0)\n-\t\t\t\treturn csum;\n+\t\t\t\tgoto out;\n \t\t\toffset += copy;\n \t\t\tto += copy;\n \t\t\tpos += copy;\n@@ -3720,32 +3786,51 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\n \tif (unlikely(len)) {\n \t\tDEBUG_NET_WARN_ON_ONCE(1);\n \t\t/* Don't hand the caller a buffer with stale bytes in it. */\n-\t\tif (len \u003e 0)\n-\t\t\tmemset(to, 0, len);\n-\t\treturn 0;\n+\t\tmemset(to, 0, len);\n+\t\treturn -EFAULT;\n \t}\n-\treturn csum;\n+out:\n+\t*csump = csum;\n+\treturn 0;\n }\n EXPORT_SYMBOL(skb_copy_and_csum_bits);\n \n #ifdef CONFIG_NET_CRC32C\n-u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)\n+/**\n+ *\tskb_crc32c_full - CRC32C a range of an skb\n+ *\t@skb: buffer to read\n+ *\t@offset: offset in @skb to start at\n+ *\t@len: number of bytes to include\n+ *\t@crcp: the CRC to continue from; on success, updated with the range\n+ *\n+ *\tReturn: 0 on success, -EINVAL if @len is negative, or -EFAULT if @skb\n+ *\thas unreadable frags in the range or runs out before @len does. On\n+ *\tfailure *@crcp is not changed.\n+ */\n+int skb_crc32c_full(const struct sk_buff *skb, int offset, int len, u32 *crcp)\n {\n \tint start = skb_headlen(skb);\n \tint i, copy = start - offset;\n \tstruct sk_buff *frag_iter;\n+\tu32 crc = *crcp;\n+\tint err;\n+\n+\tif (unlikely(len \u003c 0)) {\n+\t\tDEBUG_NET_WARN_ON_ONCE(1);\n+\t\treturn -EINVAL;\n+\t}\n \n \tif (copy \u003e 0) {\n \t\tcopy = min(copy, len);\n \t\tcrc = crc32c(crc, skb-\u003edata + offset, copy);\n \t\tlen -= copy;\n \t\tif (len == 0)\n-\t\t\treturn crc;\n+\t\t\tgoto out;\n \t\toffset += copy;\n \t}\n \n-\tif (WARN_ON_ONCE(!skb_frags_readable(skb)))\n-\t\treturn 0;\n+\tif (!skb_frags_readable(skb))\n+\t\treturn -EFAULT;\n \n \tfor (i = 0; i \u003c skb_shinfo(skb)-\u003enr_frags; i++) {\n \t\tint end;\n@@ -3770,7 +3855,7 @@ u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)\n \t\t\t}\n \t\t\tlen -= copy;\n \t\t\tif (len == 0)\n-\t\t\t\treturn crc;\n+\t\t\t\tgoto out;\n \t\t\toffset += copy;\n \t\t}\n \t\tstart = end;\n@@ -3785,19 +3870,36 @@ u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)\n \t\tcopy = end - offset;\n \t\tif (copy \u003e 0) {\n \t\t\tcopy = min(copy, len);\n-\t\t\tcrc = skb_crc32c(frag_iter, offset - start, copy, crc);\n+\t\t\terr = skb_crc32c_full(frag_iter, offset - start, copy,\n+\t\t\t\t\t \u0026crc);\n+\t\t\tif (err)\n+\t\t\t\treturn err;\n \t\t\tlen -= copy;\n \t\t\tif (len == 0)\n-\t\t\t\treturn crc;\n+\t\t\t\tgoto out;\n \t\t\toffset += copy;\n \t\t}\n \t\tstart = end;\n \t}\n \tif (unlikely(len)) {\n \t\tDEBUG_NET_WARN_ON_ONCE(1);\n-\t\treturn 0;\n+\t\treturn -EFAULT;\n \t}\n+out:\n+\t*crcp = crc;\n+\treturn 0;\n+}\n+EXPORT_SYMBOL(skb_crc32c_full);\n \n+/* skb_crc32c() has no way to report failure, so it returns 0, which is a\n+ * valid CRC. Use skb_crc32c_full() in new code.\n+ */\n+u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)\n+{\n+\tif (unlikely(skb_crc32c_full(skb, offset, len, \u0026crc))) {\n+\t\tWARN_ON_ONCE(!skb_frags_readable(skb));\n+\t\treturn 0;\n+\t}\n \treturn crc;\n }\n EXPORT_SYMBOL(skb_crc32c);\n@@ -3805,9 +3907,17 @@ EXPORT_SYMBOL(skb_crc32c);\n \n __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)\n {\n+\t__wsum csum = skb-\u003ecsum;\n \t__sum16 sum;\n \n-\tsum = csum_fold(skb_checksum(skb, 0, len, skb-\u003ecsum));\n+\t/* If the data can't be checksummed it can't be valid either. */\n+\tif (skb_checksum_full(skb, 0, len, \u0026csum)) {\n+\t\tif (!skb_shared(skb))\n+\t\t\tskb-\u003ecsum_valid = 0;\n+\t\treturn (__force __sum16)1;\n+\t}\n+\n+\tsum = csum_fold(csum);\n \t/* See comments in __skb_checksum_complete(). */\n \tif (likely(!sum)) {\n \t\tif (unlikely(skb-\u003eip_summed == CHECKSUM_COMPLETE) \u0026\u0026\n@@ -3831,10 +3941,17 @@ EXPORT_SYMBOL(__skb_checksum_complete_head);\n */\n __sum16 __skb_checksum_complete(struct sk_buff *skb)\n {\n-\t__wsum csum;\n+\t__wsum csum = 0;\n \t__sum16 sum;\n \n-\tcsum = skb_checksum(skb, 0, skb-\u003elen, 0);\n+\t/* If the data can't be checksummed it can't be valid either. Leave\n+\t * skb-\u003ecsum alone, it's not a full packet checksum.\n+\t */\n+\tif (skb_checksum_full(skb, 0, skb-\u003elen, \u0026csum)) {\n+\t\tif (!skb_shared(skb))\n+\t\t\tskb-\u003ecsum_valid = 0;\n+\t\treturn (__force __sum16)1;\n+\t}\n \n \tsum = csum_fold(csum_add(skb-\u003ecsum, csum));\n \t/* This check is inverted, because we already knew the hardware\n@@ -3905,8 +4022,9 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);\n *\tReturn value:\n *\t0: everything is OK\n *\t-ENOMEM: couldn't orphan frags of @from due to lack of memory\n- *\t-EFAULT: skb_copy_bits() found some problem with skb geometry, or readable head\n- * payload would be mixed with unreadable frags.\n+ *\t-EFAULT: skb_copy_bits() found some problem with skb geometry, @from has\n+ *\tno head_frag and @hlen is 0 while @len doesn't fit in @to's tailroom,\n+ *\tor readable head payload would be mixed with unreadable frags.\n */\n int\n skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)\n@@ -3917,15 +4035,18 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)\n \tstruct page *page;\n \tunsigned int offset;\n \n+\t/* dont bother with small payloads */\n+\tif (len \u003c= skb_tailroom(to))\n+\t\treturn skb_copy_bits(from, 0, skb_put(to, len), len);\n+\n+\t/* Without a head_frag the head can't be referenced as a page, so the\n+\t * caller has to ask for it to be copied.\n+\t */\n \tif (unlikely(!from-\u003ehead_frag \u0026\u0026 !hlen)) {\n \t\tDEBUG_NET_WARN_ON_ONCE(1);\n \t\treturn -EFAULT;\n \t}\n \n-\t/* dont bother with small payloads */\n-\tif (len \u003c= skb_tailroom(to))\n-\t\treturn skb_copy_bits(from, 0, skb_put(to, len), len);\n-\n \tif (hlen) {\n \t\tret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);\n \t\tif (unlikely(ret))\n@@ -3990,7 +4111,11 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)\n \telse\n \t\tcsstart = skb_headlen(skb);\n \n+\t/* skb_headlen() underflows if data_len is bigger than len, so check\n+\t * csstart against len as well.\n+\t */\n \tif (unlikely(csstart \u003c 0 || csstart \u003e skb_headlen(skb) ||\n+\t\t csstart \u003e skb-\u003elen ||\n \t\t (skb-\u003eip_summed == CHECKSUM_PARTIAL \u0026\u0026\n \t\t csstart + skb-\u003ecsum_offset + sizeof(__sum16) \u003e\n \t\t skb-\u003elen))) {\n@@ -4006,9 +4131,13 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)\n \tskb_copy_from_linear_data(skb, to, csstart);\n \n \tcsum = 0;\n-\tif (csstart != skb-\u003elen)\n-\t\tcsum = skb_copy_and_csum_bits(skb, csstart, to + csstart,\n-\t\t\t\t\t skb-\u003elen - csstart);\n+\t/* On failure the rest of @to is zeroed; leave the checksum alone so\n+\t * the frame goes out with a bad one.\n+\t */\n+\tif (csstart != skb-\u003elen \u0026\u0026\n+\t skb_copy_and_csum_bits(skb, csstart, to + csstart,\n+\t\t\t\t skb-\u003elen - csstart, \u0026csum))\n+\t\treturn;\n \n \tif (skb-\u003eip_summed == CHECKSUM_PARTIAL) {\n \t\tlong csstuff = csstart + skb-\u003ecsum_offset;\n@@ -4958,6 +5087,15 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,\n \t\tint size;\n \n \t\tif (unlikely(gso_by_frags)) {\n+\t\t\t/* The walk only goes one level deep: running out of\n+\t\t\t * members, or finding one with its own frag_list, means\n+\t\t\t * a nested frag_list that head_skb-\u003elen counts.\n+\t\t\t */\n+\t\t\tif (unlikely(!list_skb || skb_has_frag_list(list_skb))) {\n+\t\t\t\tDEBUG_NET_WARN_ON_ONCE(1);\n+\t\t\t\terr = -EINVAL;\n+\t\t\t\tgoto err;\n+\t\t\t}\n \t\t\tlen = list_skb-\u003elen;\n \t\t} else {\n \t\t\tlen = head_skb-\u003elen - offset;\n@@ -4967,9 +5105,11 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,\n \n \t\thsize = skb_headlen(head_skb) - offset;\n \n-\t\tif (hsize \u003c= 0 \u0026\u0026 i \u003e= nfrags \u0026\u0026 skb_headlen(list_skb) \u0026\u0026\n+\t\tif (hsize \u003c= 0 \u0026\u0026 i \u003e= nfrags \u0026\u0026 list_skb \u0026\u0026\n+\t\t skb_headlen(list_skb) \u0026\u0026\n \t\t (skb_headlen(list_skb) == len || sg)) {\n-\t\t\tif (unlikely(skb_headlen(list_skb) \u003e len)) {\n+\t\t\tif (unlikely(skb_headlen(list_skb) \u003e len ||\n+\t\t\t\t skb_has_frag_list(list_skb))) {\n \t\t\t\tDEBUG_NET_WARN_ON_ONCE(1);\n \t\t\t\terr = -EINVAL;\n \t\t\t\tgoto err;\n@@ -5057,11 +5197,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,\n \t\t\tif (!csum) {\n \t\t\t\tif (!nskb-\u003eremcsum_offload)\n \t\t\t\t\tnskb-\u003eip_summed = CHECKSUM_NONE;\n-\t\t\t\tSKB_GSO_CB(nskb)-\u003ecsum =\n-\t\t\t\t\tskb_copy_and_csum_bits(head_skb, offset,\n-\t\t\t\t\t\t\t skb_put(nskb,\n-\t\t\t\t\t\t\t\t len),\n-\t\t\t\t\t\t\t len);\n+\t\t\t\tif (skb_copy_and_csum_bits(head_skb, offset,\n+\t\t\t\t\t\t\t skb_put(nskb, len),\n+\t\t\t\t\t\t\t len,\n+\t\t\t\t\t\t\t \u0026SKB_GSO_CB(nskb)-\u003ecsum)) {\n+\t\t\t\t\terr = -EFAULT;\n+\t\t\t\t\tgoto err;\n+\t\t\t\t}\n \t\t\t\tSKB_GSO_CB(nskb)-\u003ecsum_start =\n \t\t\t\t\tskb_headroom(nskb) + doffset;\n \t\t\t} else {\n@@ -5085,6 +5227,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,\n \n \t\twhile (pos \u003c offset + len) {\n \t\t\tif (i \u003e= nfrags) {\n+\t\t\t\tif (unlikely(!list_skb ||\n+\t\t\t\t\t skb_has_frag_list(list_skb))) {\n+\t\t\t\t\tDEBUG_NET_WARN_ON_ONCE(1);\n+\t\t\t\t\terr = -EINVAL;\n+\t\t\t\t\tgoto err;\n+\t\t\t\t}\n+\n \t\t\t\tif (skb_orphan_frags(list_skb, GFP_ATOMIC) ||\n \t\t\t\t skb_zerocopy_clone(nskb, list_skb,\n \t\t\t\t\t\t GFP_ATOMIC))\n@@ -5163,9 +5312,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,\n \n \t\t\tif (!nskb-\u003eremcsum_offload)\n \t\t\t\tnskb-\u003eip_summed = CHECKSUM_NONE;\n-\t\t\tSKB_GSO_CB(nskb)-\u003ecsum =\n-\t\t\t\tskb_checksum(nskb, doffset,\n-\t\t\t\t\t nskb-\u003elen - doffset, 0);\n+\t\t\tSKB_GSO_CB(nskb)-\u003ecsum = 0;\n+\t\t\tif (skb_checksum_full(nskb, doffset,\n+\t\t\t\t\t nskb-\u003elen - doffset,\n+\t\t\t\t\t \u0026SKB_GSO_CB(nskb)-\u003ecsum)) {\n+\t\t\t\terr = -EFAULT;\n+\t\t\t\tgoto err;\n+\t\t\t}\n \t\t\tSKB_GSO_CB(nskb)-\u003ecsum_start =\n \t\t\t\tskb_headroom(nskb) + doffset;\n \t\t}\n@@ -5398,8 +5551,9 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len,\n *\n *\tFill the specified scatter-gather list with mappings/pointers into a\n *\tregion of the buffer space attached to a socket buffer. Returns either\n- *\tthe number of scatterlist items used, or -EMSGSIZE if the contents\n- *\tcould not fit.\n+ *\tthe number of scatterlist items used, -EMSGSIZE if the contents\n+ *\tcould not fit, or -EINVAL if @offset and @len run past the end of\n+ *\tthe skb.\n */\n int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)\n {\n@@ -6269,7 +6423,8 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,\n \t\t bool *fragstolen, int *delta_truesize)\n {\n \tstruct skb_shared_info *to_shinfo, *from_shinfo;\n-\tint i, delta, len = from-\u003elen;\n+\tunsigned int len = from-\u003elen;\n+\tint i, delta;\n \n \t*fragstolen = false;\n \n@@ -6340,7 +6495,7 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,\n \t\tdelta = from-\u003etruesize - SKB_TRUESIZE(skb_end_offset(from));\n \t}\n \n-\tWARN_ON_ONCE(delta \u003c len);\n+\tWARN_ON_ONCE(delta \u003c 0 || delta \u003c len);\n \n \tmemcpy(to_shinfo-\u003efrags + to_shinfo-\u003enr_frags,\n \t from_shinfo-\u003efrags,\ndiff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c\nindex 90c0e22c29bea..35008785e3d22 100644\n--- a/net/ipv4/icmp.c\n+++ b/net/ipv4/icmp.c\n@@ -364,12 +364,15 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,\n \tDEFINE_RAW_FLEX(struct icmp_bxm, icmp_param, replyopts.opt.__data,\n \t\t\tIP_OPTIONS_DATA_FIXED_SIZE);\n \t__wsum csum;\n+\tint err;\n \n \ticmp_param = from;\n \n-\tcsum = skb_copy_and_csum_bits(icmp_param-\u003eskb,\n-\t\t\t\t icmp_param-\u003eoffset + offset,\n-\t\t\t\t to, len);\n+\terr = skb_copy_and_csum_bits(icmp_param-\u003eskb,\n+\t\t\t\t icmp_param-\u003eoffset + offset,\n+\t\t\t\t to, len, \u0026csum);\n+\tif (err)\n+\t\treturn err;\n \n \tskb-\u003ecsum = csum_block_add(skb-\u003ecsum, csum, odd);\n \tif (icmp_param-\u003edata.icmph.type \u003c= NR_ICMP_TYPES \u0026\u0026\ndiff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c\nindex 3396f177a18d0..f7da4538d05b5 100644\n--- a/net/ipv4/ip_output.c\n+++ b/net/ipv4/ip_output.c\n@@ -1162,9 +1162,14 @@ static int __ip_append_data(struct sock *sk,\n \t\t\tdata += fragheaderlen + exthdrlen;\n \n \t\t\tif (fraggap) {\n-\t\t\t\tskb-\u003ecsum = skb_copy_and_csum_bits(\n-\t\t\t\t\tskb_prev, maxfraglen,\n-\t\t\t\t\tdata + transhdrlen, fraggap);\n+\t\t\t\tif (skb_copy_and_csum_bits(skb_prev, maxfraglen,\n+\t\t\t\t\t\t\t data + transhdrlen,\n+\t\t\t\t\t\t\t fraggap,\n+\t\t\t\t\t\t\t \u0026skb-\u003ecsum)) {\n+\t\t\t\t\terr = -EFAULT;\n+\t\t\t\t\tkfree_skb(skb);\n+\t\t\t\t\tgoto error;\n+\t\t\t\t}\n \t\t\t\tskb_prev-\u003ecsum = csum_sub(skb_prev-\u003ecsum,\n \t\t\t\t\t\t\t skb-\u003ecsum);\n \t\t\t\tdata += fraggap;\ndiff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c\nindex a95b0351824f3..31ca3da80b1f1 100644\n--- a/net/ipv6/icmp.c\n+++ b/net/ipv6/icmp.c\n@@ -322,9 +322,12 @@ static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, st\n \tstruct icmpv6_msg *msg = (struct icmpv6_msg *) from;\n \tstruct sk_buff *org_skb = msg-\u003eskb;\n \t__wsum csum;\n+\tint err;\n \n-\tcsum = skb_copy_and_csum_bits(org_skb, msg-\u003eoffset + offset,\n-\t\t\t\t to, len);\n+\terr = skb_copy_and_csum_bits(org_skb, msg-\u003eoffset + offset,\n+\t\t\t\t to, len, \u0026csum);\n+\tif (err)\n+\t\treturn err;\n \tskb-\u003ecsum = csum_block_add(skb-\u003ecsum, csum, odd);\n \tif (!(msg-\u003etype \u0026 ICMPV6_INFOMSG_MASK))\n \t\tnf_ct_attach(skb, org_skb);\ndiff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c\nindex 25fe0ba98b1a6..d259e7dca8ba2 100644\n--- a/net/ipv6/ip6_output.c\n+++ b/net/ipv6/ip6_output.c\n@@ -1724,9 +1724,14 @@ static int __ip6_append_data(struct sock *sk,\n \t\t\tskb-\u003etransport_header = (skb-\u003enetwork_header +\n \t\t\t\t\t\t fragheaderlen);\n \t\t\tif (fraggap) {\n-\t\t\t\tskb-\u003ecsum = skb_copy_and_csum_bits(\n-\t\t\t\t\tskb_prev, maxfraglen,\n-\t\t\t\t\tdata + transhdrlen, fraggap);\n+\t\t\t\tif (skb_copy_and_csum_bits(skb_prev, maxfraglen,\n+\t\t\t\t\t\t\t data + transhdrlen,\n+\t\t\t\t\t\t\t fraggap,\n+\t\t\t\t\t\t\t \u0026skb-\u003ecsum)) {\n+\t\t\t\t\terr = -EFAULT;\n+\t\t\t\t\tkfree_skb(skb);\n+\t\t\t\t\tgoto error;\n+\t\t\t\t}\n \t\t\t\tskb_prev-\u003ecsum = csum_sub(skb_prev-\u003ecsum,\n \t\t\t\t\t\t\t skb-\u003ecsum);\n \t\t\t\tdata += fraggap;\ndiff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c\nindex d8d8842c7de5c..5d780ad4ae3a0 100644\n--- a/net/sunrpc/socklib.c\n+++ b/net/sunrpc/socklib.c\n@@ -49,7 +49,9 @@ xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len)\n \tif (desc-\u003eneed_checksum) {\n \t\t__wsum csum;\n \n-\t\tcsum = skb_copy_and_csum_bits(desc-\u003eskb, desc-\u003eoffset, to, len);\n+\t\tif (unlikely(skb_copy_and_csum_bits(desc-\u003eskb, desc-\u003eoffset,\n+\t\t\t\t\t\t to, len, \u0026csum)))\n+\t\t\treturn 0;\n \t\tdesc-\u003ecsum = csum_block_add(desc-\u003ecsum, csum, desc-\u003eoffset);\n \t} else {\n \t\tif (unlikely(skb_copy_bits(desc-\u003eskb, desc-\u003eoffset, to, len)))\n@@ -142,11 +144,6 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)\n \tdesc.csum = csum_partial(skb-\u003edata, desc.offset, skb-\u003ecsum);\n \tif (xdr_partial_copy_from_skb(xdr, \u0026desc) \u003c 0)\n \t\treturn -1;\n-\tif (desc.offset != skb-\u003elen) {\n-\t\t__wsum csum2;\n-\t\tcsum2 = skb_checksum(skb, desc.offset, skb-\u003elen - desc.offset, 0);\n-\t\tdesc.csum = csum_block_add(desc.csum, csum2, desc.offset);\n-\t}\n \tif (desc.count)\n \t\treturn -1;\n \tif (csum_fold(desc.csum))\ndiff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c\nindex 312e51270f293..1c578ea47a1b3 100644\n--- a/net/tls/tls_sw.c\n+++ b/net/tls/tls_sw.c\n@@ -142,7 +142,10 @@ static int __skb_nsg(struct sk_buff *skb, int offset, int len,\n start = end;\n }\n }\n- BUG_ON(len);\n+\tif (unlikely(len)) {\n+\t\tDEBUG_NET_WARN_ON_ONCE(1);\n+\t\treturn -EINVAL;\n+\t}\n return elt;\n }\n \n"
} |
| 2/1 | 2026/10/21 21:13 | agent | patch-evaluator |
3mModel:core Args: null Results: {
"EnableConfigs": [
"DEBUG_NET",
"INET",
"IPV6",
"TLS",
"NET_CRC32C",
"IP_SCTP",
"SUNRPC"
],
"FocusSymbols": [
"skb_segment",
"skb_checksum_full",
"skb_copy_and_csum_bits",
"skb_crc32c_full",
"skb_crc32c_csum_help",
"skb_zerocopy",
"skb_try_coalesce",
"skb_copy_and_csum_dev",
"tls_sw_recvmsg",
"csum_partial_copy_to_xdr"
],
"Reasoning": "The patch series refactors core socket buffer (skbuff) checksumming and copying routines in net/core/skbuff.c and net/core/dev.c. It introduces skb_checksum_full() and skb_crc32c_full() to propagate errors, refactors skb_copy_and_csum_bits() and its call sites across core networking (IPv4, IPv6, SunRPC), updates GSO segmentation validation in skb_segment(), and adds multiple runtime assertions via DEBUG_NET_WARN_ON_ONCE() and WARN_ON_ONCE(). These reachable paths in core networking warrant fuzzing.",
"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 9fec1e72dd0e9fa7934a768897145f6e40a2e828
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Oct 21 21:13:50 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/sun/sunvnet_common.c b/drivers/net/ethernet/sun/sunvnet_common.c
index 5cca958690521..4f229fcecc32f 100644
--- a/drivers/net/ethernet/sun/sunvnet_common.c
+++ b/drivers/net/ethernet/sun/sunvnet_common.c
@@ -1167,9 +1167,13 @@ static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies)
/* copy the rest, with csum calculation */
*(__sum16 *)(skb->data + offset) = 0;
- csum = skb_copy_and_csum_bits(skb, start,
- nskb->data + start,
- skb->len - start);
+ if (skb_copy_and_csum_bits(skb, start,
+ nskb->data + start,
+ skb->len - start, &csum)) {
+ dev_kfree_skb(nskb);
+ dev_kfree_skb(skb);
+ return NULL;
+ }
/* add in the header checksums */
if (skb->protocol == htons(ETH_P_IP)) {
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index fdcb91042f290..17811d81937c6 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -695,7 +695,12 @@ static struct sk_buff *bounce_skb(const struct sk_buff *skb)
/* Set the tail pointer and length */
skb_put(n, skb->len);
- BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len));
+ if (unlikely(skb_copy_bits(skb, -headerlen, n->head,
+ headerlen + skb->len))) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ kfree_skb(n);
+ return NULL;
+ }
skb_copy_header(n, skb);
return n;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index af1cbc2799b77..327a01a5d6d0b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -4277,8 +4277,10 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
-__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
- int len);
+int __must_check skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
+ u8 *to, int len, __wsum *csum);
+int __must_check skb_checksum_full(const struct sk_buff *skb, int offset,
+ int len, __wsum *csump);
int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int len,
unsigned int flags);
@@ -4327,6 +4329,8 @@ static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)
__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
__wsum csum);
+int __must_check skb_crc32c_full(const struct sk_buff *skb, int offset,
+ int len, u32 *crcp);
u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc);
static inline void * __must_check
diff --git a/net/core/dev.c b/net/core/dev.c
index 8eb9bf1ff9eb6..1d34fa4544a25 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3738,8 +3738,11 @@ int skb_crc32c_csum_help(struct sk_buff *skb)
if (ret)
goto out;
- crc = ~skb_crc32c(skb, start, skb->len - start, ~0);
- *(__le32 *)(skb->data + offset) = cpu_to_le32(crc);
+ crc = ~0;
+ ret = skb_crc32c_full(skb, start, skb->len - start, &crc);
+ if (ret)
+ goto out;
+ *(__le32 *)(skb->data + offset) = cpu_to_le32(~crc);
skb_reset_csum_not_inet(skb);
out:
return ret;
diff --git a/net/core/filter.c b/net/core/filter.c
index 3ee1a093337e3..f5bce0dc43fe0 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3696,9 +3696,9 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
shinfo->gso_segs = 0;
/* Due to header growth, MSS needs to be downgraded.
- * There is a BUG_ON() when segmenting the frag_list with
- * head_frag true, so linearize the skb after downgrading
- * the MSS.
+ * Segmenting a frag_list with head_frag true at the new MSS
+ * fails and the packet gets dropped, so linearize the skb
+ * after downgrading the MSS.
*/
if (!(flags & BPF_F_ADJ_ROOM_FIXED_GSO)) {
skb_decrease_gso_size(shinfo, len_diff);
diff --git a/net/core/net_test.c b/net/core/net_test.c
index bc2ef7612e7df..222d24793591c 100644
--- a/net/core/net_test.c
+++ b/net/core/net_test.c
@@ -39,6 +39,8 @@ enum gso_test_nr {
GSO_TEST_RESEGMENT_MULTI,
GSO_TEST_RESEGMENT_TAIL,
GSO_TEST_RESEGMENT_ONE_MSS,
+ GSO_TEST_FRAG_LIST_NON_UNIFORM_SG,
+ GSO_TEST_FRAG_LIST_NESTED,
};
struct gso_test_case {
@@ -57,6 +59,9 @@ struct gso_test_case {
unsigned int nr_segs;
const unsigned int *segs;
const unsigned int *gso_segs;
+
+ /* skb_segment() is expected to fail with this error */
+ int err;
};
static struct gso_test_case cases[] = {
@@ -204,6 +209,28 @@ static struct gso_test_case cases[] = {
},
.gso_segs = (const unsigned int[]) { 0, 0, 0, 0 },
},
+ {
+ /* frag_list members that don't end on gso_size boundaries
+ * can't be segmented with SG
+ */
+ .id = GSO_TEST_FRAG_LIST_NON_UNIFORM_SG,
+ .name = "frag_list_non_uniform_sg",
+ .linear_len = GSO_TEST_SIZE,
+ .nr_frag_skbs = 4,
+ .frag_skbs = (const unsigned int[]) { GSO_TEST_SIZE, 1, GSO_TEST_SIZE, 2 },
+ .err = -EINVAL,
+ },
+ {
+ /* the second frag_list member hangs off the first one's
+ * frag_list instead of off the head's
+ */
+ .id = GSO_TEST_FRAG_LIST_NESTED,
+ .name = "frag_list_nested",
+ .linear_len = GSO_TEST_SIZE,
+ .nr_frag_skbs = 2,
+ .frag_skbs = (const unsigned int[]) { GSO_TEST_SIZE, GSO_TEST_SIZE },
+ .err = -EINVAL,
+ },
};
static void gso_test_case_to_desc(struct gso_test_case *t, char *desc)
@@ -283,19 +310,41 @@ static void gso_test_func(struct kunit *test)
if (tcase->id == GSO_TEST_GSO_BY_FRAGS)
skb_shinfo(skb)->gso_size = GSO_BY_FRAGS;
+
+ if (tcase->id == GSO_TEST_FRAG_LIST_NESTED) {
+ struct sk_buff *first = skb_shinfo(skb)->frag_list;
+
+ skb_shinfo(first)->frag_list = first->next;
+ first->next = NULL;
+ first->len += tcase->frag_skbs[1];
+ first->data_len += tcase->frag_skbs[1];
+ }
}
features = NETIF_F_SG | NETIF_F_HW_CSUM;
if (tcase->id == GSO_TEST_GSO_PARTIAL)
features |= NETIF_F_GSO_PARTIAL;
- /* TODO: this should also work with SG,
- * rather than hit BUG_ON(i >= nfrags)
+ /* TODO: this should also work with SG, rather than fail the
+ * i >= nfrags check in skb_segment()
*/
if (tcase->id == GSO_TEST_FRAG_LIST_NON_UNIFORM)
features &= ~NETIF_F_SG;
SKB_GSO_CB(skb)->max_segs = tcase->max_segs;
+
+ if (tcase->err) {
+ /* the suppression block doesn't run if it can't be set up */
+ segs = NULL;
+ kunit_warning_suppress(test) {
+ segs = skb_segment(skb, features);
+ }
+ KUNIT_EXPECT_EQ(test, PTR_ERR_OR_ZERO(segs), tcase->err);
+ if (!IS_ERR_OR_NULL(segs))
+ kfree_skb_list(segs);
+ goto free_gso_skb;
+ }
+
segs = skb_segment(skb, features);
if (IS_ERR(segs)) {
KUNIT_FAIL(test, "segs error %pe", segs);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 93c2f440b9ece..e0c8f2f6bfac1 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2829,9 +2829,13 @@ static int pskb_trim_rcsum_complete(struct sk_buff *skb, unsigned int len)
int delta = skb->len - len;
if (skb_frags_readable(skb)) {
- skb->csum = csum_block_sub(skb->csum,
- skb_checksum(skb, len, delta, 0),
- len);
+ __wsum csum = 0;
+ int err;
+
+ err = skb_checksum_full(skb, len, delta, &csum);
+ if (err)
+ return err;
+ skb->csum = csum_block_sub(skb->csum, csum, len);
return 0;
}
@@ -3545,12 +3549,31 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
EXPORT_SYMBOL(skb_store_bits);
/* Checksum skb data. */
-__wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
+/**
+ * skb_checksum_full - checksum a range of an skb
+ * @skb: buffer to checksum
+ * @offset: offset in @skb to start at
+ * @len: number of bytes to checksum
+ * @csump: the sum to add to; on success the range's sum is added to it
+ *
+ * Return: 0 on success, -EINVAL if @len is negative, or -EFAULT if @skb
+ * has unreadable frags in the range or runs out before @len does. On
+ * failure *@csump is not changed.
+ */
+int skb_checksum_full(const struct sk_buff *skb, int offset, int len,
+ __wsum *csump)
{
int start = skb_headlen(skb);
int i, copy = start - offset;
struct sk_buff *frag_iter;
+ __wsum csum = *csump;
int pos = 0;
+ int err;
+
+ if (unlikely(len < 0)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
/* Checksum header. */
if (copy > 0) {
@@ -3558,13 +3581,13 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
copy = len;
csum = csum_partial(skb->data + offset, copy, csum);
if ((len -= copy) == 0)
- return csum;
+ goto out;
offset += copy;
pos = copy;
}
- if (WARN_ON_ONCE(!skb_frags_readable(skb)))
- return 0;
+ if (!skb_frags_readable(skb))
+ return -EFAULT;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
@@ -3593,7 +3616,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
}
if (!(len -= copy))
- return csum;
+ goto out;
offset += copy;
}
start = end;
@@ -3606,14 +3629,17 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
end = start + frag_iter->len;
if ((copy = end - offset) > 0) {
- __wsum csum2;
+ __wsum csum2 = 0;
+
if (copy > len)
copy = len;
- csum2 = skb_checksum(frag_iter, offset - start, copy,
- 0);
+ err = skb_checksum_full(frag_iter, offset - start, copy,
+ &csum2);
+ if (err)
+ return err;
csum = csum_block_add(csum, csum2, pos);
if ((len -= copy) == 0)
- return csum;
+ goto out;
offset += copy;
pos += copy;
}
@@ -3621,23 +3647,59 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
}
if (unlikely(len)) {
DEBUG_NET_WARN_ON_ONCE(1);
- return 0;
+ return -EFAULT;
}
+out:
+ *csump = csum;
+ return 0;
+}
+EXPORT_SYMBOL(skb_checksum_full);
+/* skb_checksum() has no way to report failure, so it returns 0, which is a
+ * valid checksum. Use skb_checksum_full() in new code.
+ */
+__wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
+{
+ if (unlikely(skb_checksum_full(skb, offset, len, &csum))) {
+ WARN_ON_ONCE(!skb_frags_readable(skb));
+ return 0;
+ }
return csum;
}
EXPORT_SYMBOL(skb_checksum);
/* Both of above in one bottle. */
-__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
- u8 *to, int len)
+/**
+ * skb_copy_and_csum_bits - copy data out of an skb and checksum it
+ * @skb: source buffer
+ * @offset: offset in @skb to start copying from
+ * @to: destination buffer
+ * @len: number of bytes to copy
+ * @csump: where to store the checksum of the copied bytes
+ *
+ * Return: 0 on success, -EINVAL if @len is negative, or -EFAULT if @skb
+ * has unreadable frags or runs out before @len does. On failure *@csump
+ * is not set, and on -EFAULT the part of @to that couldn't be filled is
+ * zeroed.
+ */
+int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
+ u8 *to, int len, __wsum *csump)
{
int start = skb_headlen(skb);
int i, copy = start - offset;
struct sk_buff *frag_iter;
int pos = 0;
__wsum csum = 0;
+ int err;
+
+ /* Everything below clamps copies to @len, so a negative one would
+ * turn into a huge copy.
+ */
+ if (unlikely(len < 0)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
/* Copy header. */
if (copy > 0) {
@@ -3646,7 +3708,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
csum = csum_partial_copy_nocheck(skb->data + offset, to,
copy);
if ((len -= copy) == 0)
- return csum;
+ goto out;
offset += copy;
to += copy;
pos = copy;
@@ -3656,7 +3718,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
/* Don't hand the caller a buffer with stale bytes in it. */
if (len > 0)
memset(to, 0, len);
- return 0;
+ return -EFAULT;
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
@@ -3688,7 +3750,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
}
if (!(len -= copy))
- return csum;
+ goto out;
offset += copy;
to += copy;
}
@@ -3705,12 +3767,16 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- csum2 = skb_copy_and_csum_bits(frag_iter,
- offset - start,
- to, copy);
+ err = skb_copy_and_csum_bits(frag_iter, offset - start,
+ to, copy, &csum2);
+ if (err) {
+ /* The child zeroed its part; zero the rest. */
+ memset(to + copy, 0, len - copy);
+ return err;
+ }
csum = csum_block_add(csum, csum2, pos);
if ((len -= copy) == 0)
- return csum;
+ goto out;
offset += copy;
to += copy;
pos += copy;
@@ -3720,32 +3786,51 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
if (unlikely(len)) {
DEBUG_NET_WARN_ON_ONCE(1);
/* Don't hand the caller a buffer with stale bytes in it. */
- if (len > 0)
- memset(to, 0, len);
- return 0;
+ memset(to, 0, len);
+ return -EFAULT;
}
- return csum;
+out:
+ *csump = csum;
+ return 0;
}
EXPORT_SYMBOL(skb_copy_and_csum_bits);
#ifdef CONFIG_NET_CRC32C
-u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
+/**
+ * skb_crc32c_full - CRC32C a range of an skb
+ * @skb: buffer to read
+ * @offset: offset in @skb to start at
+ * @len: number of bytes to include
+ * @crcp: the CRC to continue from; on success, updated with the range
+ *
+ * Return: 0 on success, -EINVAL if @len is negative, or -EFAULT if @skb
+ * has unreadable frags in the range or runs out before @len does. On
+ * failure *@crcp is not changed.
+ */
+int skb_crc32c_full(const struct sk_buff *skb, int offset, int len, u32 *crcp)
{
int start = skb_headlen(skb);
int i, copy = start - offset;
struct sk_buff *frag_iter;
+ u32 crc = *crcp;
+ int err;
+
+ if (unlikely(len < 0)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
if (copy > 0) {
copy = min(copy, len);
crc = crc32c(crc, skb->data + offset, copy);
len -= copy;
if (len == 0)
- return crc;
+ goto out;
offset += copy;
}
- if (WARN_ON_ONCE(!skb_frags_readable(skb)))
- return 0;
+ if (!skb_frags_readable(skb))
+ return -EFAULT;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
@@ -3770,7 +3855,7 @@ u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
}
len -= copy;
if (len == 0)
- return crc;
+ goto out;
offset += copy;
}
start = end;
@@ -3785,19 +3870,36 @@ u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
copy = end - offset;
if (copy > 0) {
copy = min(copy, len);
- crc = skb_crc32c(frag_iter, offset - start, copy, crc);
+ err = skb_crc32c_full(frag_iter, offset - start, copy,
+ &crc);
+ if (err)
+ return err;
len -= copy;
if (len == 0)
- return crc;
+ goto out;
offset += copy;
}
start = end;
}
if (unlikely(len)) {
DEBUG_NET_WARN_ON_ONCE(1);
- return 0;
+ return -EFAULT;
}
+out:
+ *crcp = crc;
+ return 0;
+}
+EXPORT_SYMBOL(skb_crc32c_full);
+/* skb_crc32c() has no way to report failure, so it returns 0, which is a
+ * valid CRC. Use skb_crc32c_full() in new code.
+ */
+u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
+{
+ if (unlikely(skb_crc32c_full(skb, offset, len, &crc))) {
+ WARN_ON_ONCE(!skb_frags_readable(skb));
+ return 0;
+ }
return crc;
}
EXPORT_SYMBOL(skb_crc32c);
@@ -3805,9 +3907,17 @@ EXPORT_SYMBOL(skb_crc32c);
__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
{
+ __wsum csum = skb->csum;
__sum16 sum;
- sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
+ /* If the data can't be checksummed it can't be valid either. */
+ if (skb_checksum_full(skb, 0, len, &csum)) {
+ if (!skb_shared(skb))
+ skb->csum_valid = 0;
+ return (__force __sum16)1;
+ }
+
+ sum = csum_fold(csum);
/* See comments in __skb_checksum_complete(). */
if (likely(!sum)) {
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
@@ -3831,10 +3941,17 @@ EXPORT_SYMBOL(__skb_checksum_complete_head);
*/
__sum16 __skb_checksum_complete(struct sk_buff *skb)
{
- __wsum csum;
+ __wsum csum = 0;
__sum16 sum;
- csum = skb_checksum(skb, 0, skb->len, 0);
+ /* If the data can't be checksummed it can't be valid either. Leave
+ * skb->csum alone, it's not a full packet checksum.
+ */
+ if (skb_checksum_full(skb, 0, skb->len, &csum)) {
+ if (!skb_shared(skb))
+ skb->csum_valid = 0;
+ return (__force __sum16)1;
+ }
sum = csum_fold(csum_add(skb->csum, csum));
/* This check is inverted, because we already knew the hardware
@@ -3905,8 +4022,9 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
* Return value:
* 0: everything is OK
* -ENOMEM: couldn't orphan frags of @from due to lack of memory
- * -EFAULT: skb_copy_bits() found some problem with skb geometry, or readable head
- * payload would be mixed with unreadable frags.
+ * -EFAULT: skb_copy_bits() found some problem with skb geometry, @from has
+ * no head_frag and @hlen is 0 while @len doesn't fit in @to's tailroom,
+ * or readable head payload would be mixed with unreadable frags.
*/
int
skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
@@ -3917,15 +4035,18 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
struct page *page;
unsigned int offset;
+ /* dont bother with small payloads */
+ if (len <= skb_tailroom(to))
+ return skb_copy_bits(from, 0, skb_put(to, len), len);
+
+ /* Without a head_frag the head can't be referenced as a page, so the
+ * caller has to ask for it to be copied.
+ */
if (unlikely(!from->head_frag && !hlen)) {
DEBUG_NET_WARN_ON_ONCE(1);
return -EFAULT;
}
- /* dont bother with small payloads */
- if (len <= skb_tailroom(to))
- return skb_copy_bits(from, 0, skb_put(to, len), len);
-
if (hlen) {
ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
if (unlikely(ret))
@@ -3990,7 +4111,11 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
else
csstart = skb_headlen(skb);
+ /* skb_headlen() underflows if data_len is bigger than len, so check
+ * csstart against len as well.
+ */
if (unlikely(csstart < 0 || csstart > skb_headlen(skb) ||
+ csstart > skb->len ||
(skb->ip_summed == CHECKSUM_PARTIAL &&
csstart + skb->csum_offset + sizeof(__sum16) >
skb->len))) {
@@ -4006,9 +4131,13 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
skb_copy_from_linear_data(skb, to, csstart);
csum = 0;
- if (csstart != skb->len)
- csum = skb_copy_and_csum_bits(skb, csstart, to + csstart,
- skb->len - csstart);
+ /* On failure the rest of @to is zeroed; leave the checksum alone so
+ * the frame goes out with a bad one.
+ */
+ if (csstart != skb->len &&
+ skb_copy_and_csum_bits(skb, csstart, to + csstart,
+ skb->len - csstart, &csum))
+ return;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
long csstuff = csstart + skb->csum_offset;
@@ -4958,6 +5087,15 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
int size;
if (unlikely(gso_by_frags)) {
+ /* The walk only goes one level deep: running out of
+ * members, or finding one with its own frag_list, means
+ * a nested frag_list that head_skb->len counts.
+ */
+ if (unlikely(!list_skb || skb_has_frag_list(list_skb))) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ err = -EINVAL;
+ goto err;
+ }
len = list_skb->len;
} else {
len = head_skb->len - offset;
@@ -4967,9 +5105,11 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
hsize = skb_headlen(head_skb) - offset;
- if (hsize <= 0 && i >= nfrags && skb_headlen(list_skb) &&
+ if (hsize <= 0 && i >= nfrags && list_skb &&
+ skb_headlen(list_skb) &&
(skb_headlen(list_skb) == len || sg)) {
- if (unlikely(skb_headlen(list_skb) > len)) {
+ if (unlikely(skb_headlen(list_skb) > len ||
+ skb_has_frag_list(list_skb))) {
DEBUG_NET_WARN_ON_ONCE(1);
err = -EINVAL;
goto err;
@@ -5057,11 +5197,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
if (!csum) {
if (!nskb->remcsum_offload)
nskb->ip_summed = CHECKSUM_NONE;
- SKB_GSO_CB(nskb)->csum =
- skb_copy_and_csum_bits(head_skb, offset,
- skb_put(nskb,
- len),
- len);
+ if (skb_copy_and_csum_bits(head_skb, offset,
+ skb_put(nskb, len),
+ len,
+ &SKB_GSO_CB(nskb)->csum)) {
+ err = -EFAULT;
+ goto err;
+ }
SKB_GSO_CB(nskb)->csum_start =
skb_headroom(nskb) + doffset;
} else {
@@ -5085,6 +5227,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
while (pos < offset + len) {
if (i >= nfrags) {
+ if (unlikely(!list_skb ||
+ skb_has_frag_list(list_skb))) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ err = -EINVAL;
+ goto err;
+ }
+
if (skb_orphan_frags(list_skb, GFP_ATOMIC) ||
skb_zerocopy_clone(nskb, list_skb,
GFP_ATOMIC))
@@ -5163,9 +5312,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
if (!nskb->remcsum_offload)
nskb->ip_summed = CHECKSUM_NONE;
- SKB_GSO_CB(nskb)->csum =
- skb_checksum(nskb, doffset,
- nskb->len - doffset, 0);
+ SKB_GSO_CB(nskb)->csum = 0;
+ if (skb_checksum_full(nskb, doffset,
+ nskb->len - doffset,
+ &SKB_GSO_CB(nskb)->csum)) {
+ err = -EFAULT;
+ goto err;
+ }
SKB_GSO_CB(nskb)->csum_start =
skb_headroom(nskb) + doffset;
}
@@ -5398,8 +5551,9 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len,
*
* Fill the specified scatter-gather list with mappings/pointers into a
* region of the buffer space attached to a socket buffer. Returns either
- * the number of scatterlist items used, or -EMSGSIZE if the contents
- * could not fit.
+ * the number of scatterlist items used, -EMSGSIZE if the contents
+ * could not fit, or -EINVAL if @offset and @len run past the end of
+ * the skb.
*/
int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
{
@@ -6269,7 +6423,8 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
bool *fragstolen, int *delta_truesize)
{
struct skb_shared_info *to_shinfo, *from_shinfo;
- int i, delta, len = from->len;
+ unsigned int len = from->len;
+ int i, delta;
*fragstolen = false;
@@ -6340,7 +6495,7 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
delta = from->truesize - SKB_TRUESIZE(skb_end_offset(from));
}
- WARN_ON_ONCE(delta < len);
+ WARN_ON_ONCE(delta < 0 || delta < len);
memcpy(to_shinfo->frags + to_shinfo->nr_frags,
from_shinfo->frags,
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 90c0e22c29bea..35008785e3d22 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -364,12 +364,15 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
DEFINE_RAW_FLEX(struct icmp_bxm, icmp_param, replyopts.opt.__data,
IP_OPTIONS_DATA_FIXED_SIZE);
__wsum csum;
+ int err;
icmp_param = from;
- csum = skb_copy_and_csum_bits(icmp_param->skb,
- icmp_param->offset + offset,
- to, len);
+ err = skb_copy_and_csum_bits(icmp_param->skb,
+ icmp_param->offset + offset,
+ to, len, &csum);
+ if (err)
+ return err;
skb->csum = csum_block_add(skb->csum, csum, odd);
if (icmp_param->data.icmph.type <= NR_ICMP_TYPES &&
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 3396f177a18d0..f7da4538d05b5 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1162,9 +1162,14 @@ static int __ip_append_data(struct sock *sk,
data += fragheaderlen + exthdrlen;
if (fraggap) {
- skb->csum = skb_copy_and_csum_bits(
- skb_prev, maxfraglen,
- data + transhdrlen, fraggap);
+ if (skb_copy_and_csum_bits(skb_prev, maxfraglen,
+ data + transhdrlen,
+ fraggap,
+ &skb->csum)) {
+ err = -EFAULT;
+ kfree_skb(skb);
+ goto error;
+ }
skb_prev->csum = csum_sub(skb_prev->csum,
skb->csum);
data += fraggap;
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index a95b0351824f3..31ca3da80b1f1 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -322,9 +322,12 @@ static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, st
struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
struct sk_buff *org_skb = msg->skb;
__wsum csum;
+ int err;
- csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
- to, len);
+ err = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
+ to, len, &csum);
+ if (err)
+ return err;
skb->csum = csum_block_add(skb->csum, csum, odd);
if (!(msg->type & ICMPV6_INFOMSG_MASK))
nf_ct_attach(skb, org_skb);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 25fe0ba98b1a6..d259e7dca8ba2 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1724,9 +1724,14 @@ static int __ip6_append_data(struct sock *sk,
skb->transport_header = (skb->network_header +
fragheaderlen);
if (fraggap) {
- skb->csum = skb_copy_and_csum_bits(
- skb_prev, maxfraglen,
- data + transhdrlen, fraggap);
+ if (skb_copy_and_csum_bits(skb_prev, maxfraglen,
+ data + transhdrlen,
+ fraggap,
+ &skb->csum)) {
+ err = -EFAULT;
+ kfree_skb(skb);
+ goto error;
+ }
skb_prev->csum = csum_sub(skb_prev->csum,
skb->csum);
data += fraggap;
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
index d8d8842c7de5c..5d780ad4ae3a0 100644
--- a/net/sunrpc/socklib.c
+++ b/net/sunrpc/socklib.c
@@ -49,7 +49,9 @@ xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len)
if (desc->need_checksum) {
__wsum csum;
- csum = skb_copy_and_csum_bits(desc->skb, desc->offset, to, len);
+ if (unlikely(skb_copy_and_csum_bits(desc->skb, desc->offset,
+ to, len, &csum)))
+ return 0;
desc->csum = csum_block_add(desc->csum, csum, desc->offset);
} else {
if (unlikely(skb_copy_bits(desc->skb, desc->offset, to, len)))
@@ -142,11 +144,6 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
desc.csum = csum_partial(skb->data, desc.offset, skb->csum);
if (xdr_partial_copy_from_skb(xdr, &desc) < 0)
return -1;
- if (desc.offset != skb->len) {
- __wsum csum2;
- csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0);
- desc.csum = csum_block_add(desc.csum, csum2, desc.offset);
- }
if (desc.count)
return -1;
if (csum_fold(desc.csum))
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 312e51270f293..1c578ea47a1b3 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -142,7 +142,10 @@ static int __skb_nsg(struct sk_buff *skb, int offset, int len,
start = end;
}
}
- BUG_ON(len);
+ if (unlikely(len)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
return elt;
}
|
| 3/2 | 2026/10/21 21:13 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 15059 output: 33 thoughts: 874 Thoughts: **Patch Analysis: Fuzzing Potential and Configuration Requirements** Okay, let's break this down. My initial assessment is that this patch *definitely* warrants fuzzing. The guidelines are pretty clear. The core principle is reachability, and this touches a *lot* of core networking components. The "WorthFuzzing=true" criteria are screaming at me: modifications to core networking, changes to `skb` handling, and runtime assertions. This is fertile ground. Specifically, I'm seeing changes in crucial areas: `net/core/skbuff.c` (that's *the* SKB layer!), `net/ipv4/`, `net/ipv6/`, and even `net/tls/`. That’s a good target for fuzzing. Functions like `skb_copy_and_csum_bits`, the addition of `skb_checksum_full`, `skb_crc32c_full`, and modifications to `skb_segment` (which I immediately recognize as GSO segmentation!) - these are all points of interest. Plus, the inclusion of error handling and the `DEBUG_NET_WARN_ON_ONCE` indicates there's potential for interesting states or corner cases. I'll need to focus on those as well. The patch touches several drivers like `sunvnet_common.c`, and `xen-netfront.c`. It's worthwhile to inspect these to look for new interfaces which may be entrypoints for exploitation. Now I need to drill down and identify the specific *FocusSymbols*. Based on the rules, I need to avoid ubiquitous hot-paths, and target specific feature logic and entrypoints. I'll need to carefully examine the functions to extract feature-specific entrypoints. Compiler-inlined static functions will be something to look out for. And, of course, the `EnableConfigs` are crucial. I'll need to identify all the relevant `CONFIG_` options; I know that, from experience, networking patches often depend on a multitude of configs, so this will be important for reproducibility. I'm ready to dive into the code now using my preferred tools. I'll start with a detailed code review, probably using a grepper or similar tools to examine the modified functions, and understand the control flow, identifying interesting entry points and potential vulnerabilities. I expect this will be a good one. |
| 4/2 | 2026/10/21 21:14 | tool | grepper |
0mArgs:{
"Expression": "skb_segment",
"PathPrefixes": [
"net/core/skbuff.c"
]
}Results: {
"Output": "net/core/skbuff.c=4859=static inline skb_frag_t skb_head_frag_to_page_desc(struct sk_buff *frag_skb)\n--\nnet/core/skbuff.c-4870-\nnet/core/skbuff.c:4871:struct sk_buff *skb_segment_list(struct sk_buff *skb,\nnet/core/skbuff.c-4872-\t\t\t\t netdev_features_t features,\n--\nnet/core/skbuff.c-4962-}\nnet/core/skbuff.c:4963:EXPORT_SYMBOL_GPL(skb_segment_list);\nnet/core/skbuff.c-4964-\nnet/core/skbuff.c-4965-/**\nnet/core/skbuff.c:4966: *\tskb_segment - Perform protocol segmentation on skb.\nnet/core/skbuff.c-4967- *\t@head_skb: buffer to segment\n--\nnet/core/skbuff.c-4973- */\nnet/core/skbuff.c:4974:struct sk_buff *skb_segment(struct sk_buff *head_skb,\nnet/core/skbuff.c-4975-\t\t\t netdev_features_t features)\n--\nnet/core/skbuff.c-5272-\t\t\t\tnet_warn_ratelimited(\nnet/core/skbuff.c:5273:\t\t\t\t\t\"skb_segment: too many frags: %u %u\\n\",\nnet/core/skbuff.c-5274-\t\t\t\t\tpos, mss);\n--\nnet/core/skbuff.c-5372-}\nnet/core/skbuff.c:5373:EXPORT_SYMBOL_GPL(skb_segment);\nnet/core/skbuff.c-5374-\n"
} |
| 5/2 | 2026/10/21 21:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 16953 output: 29 thoughts: 111 Thoughts: **Investigating the Impact of CONFIG_NET_CRC32C** Alright, let's dive into this. My initial approach is to zero in on the changes – specifically, the lines modified in `net/core/skbuff.c` and any related files. I need to understand the scope of this. My focus is on determining what depends on this Kconfig setting, `CONFIG_NET_CRC32C`. Okay, I'm looking at `net/core/skbuff.c` now. Right away, I see it: the familiar `#ifdef CONFIG_NET_CRC32C`. This tells me that functions like `skb_crc32c_full` and `skb_crc32c` are conditionally compiled based on this configuration option. I need to determine the extent of its usage. Now, I'll need to expand my search. My next step is a broad sweep across the Kconfig files. Time to grep for `NET_CRC32C`. I'm hoping to get a clearer picture of how `CONFIG_NET_CRC32C` is used, where it's defined, and what other modules or features might be affected. This will give me a comprehensive understanding of what's controlled by that option. |
| 6/2 | 2026/10/21 21:14 | tool | grepper |
0mArgs:{
"Expression": "NET_CRC32C",
"PathPrefixes": [
"net/"
]
}Results: {
"Output": "net/Kconfig=74=config NET_SHAPER\n--\nnet/Kconfig-76-\nnet/Kconfig:77:config NET_CRC32C\nnet/Kconfig-78-\tbool\n--\nnet/batman-adv/Kconfig=34=config BATMAN_ADV_BLA\n--\nnet/batman-adv/Kconfig-37-\tselect CRC16\nnet/batman-adv/Kconfig:38:\tselect NET_CRC32C\nnet/batman-adv/Kconfig-39-\tdefault y\n--\nnet/core/datagram.c=389=static int __skb_datagram_iter(const struct sk_buff *skb, int offset,\n--\nnet/core/datagram.c-485-\nnet/core/datagram.c:486:#ifdef CONFIG_NET_CRC32C\nnet/core/datagram.c-487-static size_t crc32c_and_copy_to_iter(const void *addr, size_t bytes,\n--\nnet/core/datagram.c=515=EXPORT_SYMBOL(skb_copy_and_crc32c_datagram_iter);\nnet/core/datagram.c:516:#endif /* CONFIG_NET_CRC32C */\nnet/core/datagram.c-517-\n--\nnet/core/dev.c=3708=EXPORT_SYMBOL(skb_checksum_help);\nnet/core/dev.c-3709-\nnet/core/dev.c:3710:#ifdef CONFIG_NET_CRC32C\nnet/core/dev.c-3711-int skb_crc32c_csum_help(struct sk_buff *skb)\n--\nnet/core/dev.c=3750=EXPORT_SYMBOL(skb_crc32c_csum_help);\nnet/core/dev.c:3751:#endif /* CONFIG_NET_CRC32C */\nnet/core/dev.c-3752-\n--\nnet/core/skbuff.c=3796=EXPORT_SYMBOL(skb_copy_and_csum_bits);\nnet/core/skbuff.c-3797-\nnet/core/skbuff.c:3798:#ifdef CONFIG_NET_CRC32C\nnet/core/skbuff.c-3799-/**\n--\nnet/core/skbuff.c=3905=EXPORT_SYMBOL(skb_crc32c);\nnet/core/skbuff.c:3906:#endif /* CONFIG_NET_CRC32C */\nnet/core/skbuff.c-3907-\n--\nnet/netfilter/Kconfig=201=config NF_CT_PROTO_SCTP\n--\nnet/netfilter/Kconfig-204-\tdefault y\nnet/netfilter/Kconfig:205:\tselect NET_CRC32C\nnet/netfilter/Kconfig-206-\thelp\n--\nnet/netfilter/Kconfig=455=config NF_TABLES\nnet/netfilter/Kconfig-456-\tselect NETFILTER_NETLINK\nnet/netfilter/Kconfig:457:\tselect NET_CRC32C\nnet/netfilter/Kconfig-458-\ttristate \"Netfilter nf_tables support\"\n--\nnet/netfilter/ipvs/Kconfig=106=config IP_VS_PROTO_SCTP\nnet/netfilter/ipvs/Kconfig-107-\tbool \"SCTP load balancing support\"\nnet/netfilter/ipvs/Kconfig:108:\tselect NET_CRC32C\nnet/netfilter/ipvs/Kconfig-109-\thelp\n--\nnet/openvswitch/Kconfig=6=config OPENVSWITCH\n--\nnet/openvswitch/Kconfig-14-\tselect MPLS\nnet/openvswitch/Kconfig:15:\tselect NET_CRC32C\nnet/openvswitch/Kconfig-16-\tselect NET_MPLS_GSO\n--\nnet/sched/Kconfig=808=config NET_ACT_CSUM\n--\nnet/sched/Kconfig-810-\tdepends on NET_CLS_ACT \u0026\u0026 INET\nnet/sched/Kconfig:811:\tselect NET_CRC32C\nnet/sched/Kconfig-812-\thelp\n--\nnet/sctp/Kconfig=6=menuconfig IP_SCTP\n--\nnet/sctp/Kconfig-11-\tselect CRYPTO_LIB_UTILS\nnet/sctp/Kconfig:12:\tselect NET_CRC32C\nnet/sctp/Kconfig-13-\tselect NET_UDP_TUNNEL\n"
} |
| 7/2 | 2026/10/21 21:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 18544 output: 31 thoughts: 334 Thoughts: **Analyzing the Configuration Dependencies for NET_CRC32C and DEBUG_NET** Okay, let's dive into this. I need to understand how `NET_CRC32C` gets selected. I see it's linked to `IP_SCTP`, `NF_TABLES`, `OPENVSWITCH`, and `NET_ACT_CSUM` among others. But hold on, `NET_CRC32C` itself is defined as a `bool` without a prompt in the Kconfig file. That's unusual. Can a user directly enable it with `CONFIG_NET_CRC32C=y`? I don't think so, unless something else selects it, or if it's defined in a defconfig, of course. Aha! The key is `IP_SCTP=y`. That's the link. So `NET_CRC32C` *can* be specified, although indirectly. I remember Syzkaller's Kconfig generator handles this; it'll try to set `CONFIG_NET_CRC32C=y` directly if `NET_CRC32C` has no prompt, or will look for an option like `IP_SCTP` that selects it. The interesting thing is that we usually list either `NET_CRC32C`, `IP_SCTP` or `INET`. Syzkaller should try both `CONFIG_NET_CRC32C=y` and `CONFIG_IP_SCTP=y`. Makes sense. Now, what about `DEBUG_NET`? I see it's used in the patch with `DEBUG_NET_WARN_ON_ONCE(1)`. I need to figure out where `DEBUG_NET` is defined. Let's quickly search for it within `net/Kconfig` and `lib/Kconfig.debug`. That'll tell me its dependencies and how it's controlled. |
| 8/2 | 2026/10/21 21:14 | tool | grepper |
0mArgs:{
"Expression": "DEBUG_NET",
"PathPrefixes": [
"net/",
"lib/"
]
}Results: {
"Output": "\nFull output is too long, showing 200 out of 970 lines.\nUse more precise expression or PathPrefixes if possible.\n\nNumber of matching lines per file (69 files in total):\nnet/Kconfig.debug:2\nnet/core/Makefile:1\nnet/core/dev.c:16\nnet/core/dev.h:1\nnet/core/dst_cache.c:2\nnet/core/filter.c:2\nnet/core/flow_dissector.c:1\nnet/core/gro.c:1\nnet/core/lwtunnel.c:1\nnet/core/neighbour.c:2\nnet/core/net_namespace.c:1\nnet/core/rtnetlink.c:3\nnet/core/skbuff.c:36\nnet/core/sock.c:3\nnet/ethtool/netlink.h:1\nnet/ipv4/fib_semantics.c:4\nnet/ipv4/inet_diag.c:1\nnet/ipv4/ip_tunnel.c:1\nnet/ipv4/netfilter/nf_tproxy_ipv4.c:1\nnet/ipv4/tcp_diag.c:1\nnet/ipv4/tcp_input.c:1\nnet/ipv4/tcp_output.c:3\nnet/ipv4/udp.c:1\nnet/ipv6/ip6_gre.c:1\nnet/ipv6/netfilter/nf_tproxy_ipv6.c:1\nnet/ipv6/udp.c:1\nnet/mptcp/fastopen.c:1\nnet/mptcp/protocol.c:3\nnet/mptcp/protocol.h:3\nnet/mptcp/subflow.c:1\nnet/netfilter/ipset/ip_set_bitmap_gen.h:1\nnet/netfilter/ipset/ip_set_list_set.c:1\nnet/netfilter/nf_conncount.c:3\nnet/netfilter/nf_conntrack_core.c:1\nnet/netfilter/nf_conntrack_expect.c:1\nnet/netfilter/nf_conntrack_proto_gre.c:2\nnet/netfilter/nf_nat_sip.c:1\nnet/netfilter/nf_tables_api.c:11\nnet/netfilter/nf_tables_core.c:2\nnet/netfilter/nf_tables_offload.c:1\nnet/netfilter/nf_tables_trace.c:2\nnet/netfilter/nft_ct.c:1\nnet/netfilter/nft_ct_fast.c:1\nnet/netfilter/nft_exthdr.c:1\nnet/netfilter/nft_fib.c:1\nnet/netfilter/nft_inner.c:1\nnet/netfilter/nft_lookup.c:1\nnet/netfilter/nft_masq.c:1\nnet/netfilter/nft_meta.c:5\nnet/netfilter/nft_payload.c:3\n... and 19 more files\n\nnet/Kconfig.debug=12=config NET_NS_REFCNT_TRACKER\n--\nnet/Kconfig.debug-20-\nnet/Kconfig.debug:21:config DEBUG_NET\nnet/Kconfig.debug-22-\tbool \"Add generic networking debug\"\n--\nnet/Kconfig.debug-27-\nnet/Kconfig.debug:28:config DEBUG_NET_SMALL_RTNL\nnet/Kconfig.debug-29-\tbool \"Add extra per-netns mutex inside RTNL\"\n--\nnet/core/Makefile=52=obj-$(CONFIG_NET_DEVMEM) += devmem.o\nnet/core/Makefile:53:obj-$(CONFIG_DEBUG_NET) += lock_debug.o\nnet/core/Makefile-54-obj-$(CONFIG_FAIL_SKB_REALLOC) += skb_fault_injection.o\n--\nnet/core/dev.c=3594=static u16 skb_tx_hash(const struct net_device *dev,\n--\nnet/core/dev.c-3617-\tif (skb_rx_queue_recorded(skb)) {\nnet/core/dev.c:3618:\t\tDEBUG_NET_WARN_ON_ONCE(qcount == 0);\nnet/core/dev.c-3619-\t\thash = skb_get_rx_queue(skb);\n--\nnet/core/dev.c=4359=static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,\n--\nnet/core/dev.c-4450-\nnet/core/dev.c:4451:\t\tDEBUG_NET_WARN_ON_ONCE(skb != llist_entry(ll_list,\nnet/core/dev.c-4452-\t\t\t\t\t\t\t struct sk_buff,\n--\nnet/core/dev.c=4515=int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)\n--\nnet/core/dev.c-4521-\t\tskb-\u003eip_summed = CHECKSUM_UNNECESSARY;\nnet/core/dev.c:4522:\tDEBUG_NET_WARN_ON_ONCE(!skb_dst(skb));\nnet/core/dev.c-4523-\tskb_dst_force(skb);\n--\nnet/core/dev.c=5156=static inline void ____napi_schedule(struct softnet_data *sd,\n--\nnet/core/dev.c-5181-use_local_napi:\nnet/core/dev.c:5182:\tDEBUG_NET_WARN_ON_ONCE(!list_empty(\u0026napi-\u003epoll_list));\nnet/core/dev.c-5183-\tlist_add_tail(\u0026napi-\u003epoll_list, \u0026sd-\u003epoll_list);\n--\nnet/core/dev.c=6178=static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc,\n--\nnet/core/dev.c-6196-\tskb_reset_network_header(skb);\nnet/core/dev.c:6197:#if !defined(CONFIG_DEBUG_NET)\nnet/core/dev.c-6198-\t/* We plan to no longer reset the transport header here.\n--\nnet/core/dev.c=7994=static int napi_poll(struct napi_struct *n, struct list_head *repoll)\n--\nnet/core/dev.c-8006-\tif (do_repoll) {\nnet/core/dev.c:8007:#if defined(CONFIG_DEBUG_NET)\nnet/core/dev.c-8008-\t\tif (unlikely(!napi_is_scheduled(n)))\n--\nnet/core/dev.c=11017=static int dev_index_reserve(struct net *net, u32 ifindex)\n--\nnet/core/dev.c-11021-\tif (ifindex \u003e INT_MAX) {\nnet/core/dev.c:11022:\t\tDEBUG_NET_WARN_ON_ONCE(1);\nnet/core/dev.c-11023-\t\treturn -EINVAL;\n--\nnet/core/dev.c=12271=struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,\n--\nnet/core/dev.c-12335-\tINIT_LIST_HEAD(\u0026dev-\u003eunreg_list);\nnet/core/dev.c:12336:#ifdef CONFIG_DEBUG_NET_SMALL_RTNL\nnet/core/dev.c-12337-\tINIT_LIST_HEAD(\u0026dev-\u003eunreg_list_net);\n--\nnet/core/dev.c=12552=void unregister_netdevice_queue(struct net_device *dev, struct list_head *head)\n--\nnet/core/dev.c-12555-\nnet/core/dev.c:12556:#ifdef CONFIG_DEBUG_NET_SMALL_RTNL\nnet/core/dev.c:12557:\tDEBUG_NET_WARN_ON_ONCE(!list_empty(\u0026dev-\u003eunreg_list_net));\nnet/core/dev.c-12558-#endif\n--\nnet/core/dev.c=12629=void unregister_netdevice_many_notify(struct list_head *head,\n--\nnet/core/dev.c-12741-\tlist_for_each_entry(dev, head, unreg_list) {\nnet/core/dev.c:12742:#ifdef CONFIG_DEBUG_NET_SMALL_RTNL\nnet/core/dev.c-12743-\t\tstruct net *net = dev_net(dev);\n--\nnet/core/dev.c=12772=EXPORT_SYMBOL(unregister_netdevice_many);\nnet/core/dev.c-12773-\nnet/core/dev.c:12774:#ifdef CONFIG_DEBUG_NET_SMALL_RTNL\nnet/core/dev.c-12775-void unregister_netdevice_queue_net(struct net *net, struct net_device *dev,\n--\nnet/core/dev.c-12789-\nnet/core/dev.c:12790:\tDEBUG_NET_WARN_ON_ONCE(!list_empty(\u0026dev-\u003eunreg_list));\nnet/core/dev.c:12791:\tDEBUG_NET_WARN_ON_ONCE(!list_empty(\u0026dev-\u003eunreg_list_net));\nnet/core/dev.c-12792-\n--\nnet/core/dev.c=12802=void unregister_netdevice_queue_many_net(struct net *net, struct list_head *head)\n--\nnet/core/dev.c-12813-\nnet/core/dev.c:12814:\t\tDEBUG_NET_WARN_ONCE(!net_eq(dev_net(dev), net),\nnet/core/dev.c-12815-\t\t\t\t \"%s was unregistered from a different netns.\\n\",\n--\nnet/core/dev.c=12883=int __dev_change_net_namespace(struct net_device *dev, struct net *net,\n--\nnet/core/dev.c-13025-\nnet/core/dev.c:13026:#ifdef CONFIG_DEBUG_NET_SMALL_RTNL\nnet/core/dev.c-13027-\tunregister_netdevice_move_net(net_old, net, dev);\n--\nnet/core/dev.h=391=int rps_cpumask_housekeeping(struct cpumask *mask);\nnet/core/dev.h-392-\nnet/core/dev.h:393:#if defined(CONFIG_DEBUG_NET) \u0026\u0026 defined(CONFIG_BPF_SYSCALL)\nnet/core/dev.h-394-void xdp_do_check_flushed(struct napi_struct *napi);\n--\nnet/core/dst_cache.c=28=static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache,\n--\nnet/core/dst_cache.c-30-{\nnet/core/dst_cache.c:31:\tDEBUG_NET_WARN_ON_ONCE(!in_softirq());\nnet/core/dst_cache.c-32-\tdst_release(dst_cache-\u003edst);\n--\nnet/core/dst_cache.c=40=static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,\n--\nnet/core/dst_cache.c-44-\nnet/core/dst_cache.c:45:\tDEBUG_NET_WARN_ON_ONCE(!in_softirq());\nnet/core/dst_cache.c-46-\tdst = idst-\u003edst;\n--\nnet/core/filter.c=1681=static inline int __bpf_try_make_writable(struct sk_buff *skb,\n--\nnet/core/filter.c-1683-{\nnet/core/filter.c:1684:#ifdef CONFIG_DEBUG_NET\nnet/core/filter.c-1685-\t/* Avoid a splat in pskb_may_pull_reason() */\n--\nnet/core/filter.c=4533=EXPORT_SYMBOL_GPL(xdp_do_flush);\nnet/core/filter.c-4534-\nnet/core/filter.c:4535:#if defined(CONFIG_DEBUG_NET) \u0026\u0026 defined(CONFIG_BPF_SYSCALL)\nnet/core/filter.c-4536-void xdp_do_check_flushed(struct napi_struct *napi)\n--\nnet/core/flow_dissector.c=1059=bool __skb_flow_dissect(const struct net *net,\n--\nnet/core/flow_dissector.c-1133-\nnet/core/flow_dissector.c:1134:\tDEBUG_NET_WARN_ON_ONCE(!net);\nnet/core/flow_dissector.c-1135-\tif (net) {\n--\nnet/core/gro.c=428=static void gro_pull_from_frag0(struct sk_buff *skb, int grow)\n--\nnet/core/gro.c-431-\nnet/core/gro.c:432:\tDEBUG_NET_WARN_ON_ONCE(skb-\u003eend - skb-\u003etail \u003c grow);\nnet/core/gro.c-433-\n--\nnet/core/lwtunnel.c=432=int lwtunnel_input(struct sk_buff *skb)\n--\nnet/core/lwtunnel.c-438-\nnet/core/lwtunnel.c:439:\tDEBUG_NET_WARN_ON_ONCE(!in_softirq());\nnet/core/lwtunnel.c-440-\n--\nnet/core/neighbour.c=80=static struct hlist_head *neigh_get_dev_table(struct net_device *dev, int family)\n--\nnet/core/neighbour.c-85-\tdefault:\nnet/core/neighbour.c:86:\t\tDEBUG_NET_WARN_ON_ONCE(1);\nnet/core/neighbour.c-87-\t\tfallthrough; /* to avoid panic by null-ptr-deref */\n--\nnet/core/neighbour.c=460=static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,\n--\nnet/core/neighbour.c-466-\t} else {\nnet/core/neighbour.c:467:\t\tDEBUG_NET_WARN_ON_ONCE(skip_perm);\nnet/core/neighbour.c-468-\t\tneigh_flush_table(tbl);\n--\nnet/core/net_namespace.c=403=static __net_init void preinit_net(struct net *net, struct user_namespace *user_ns)\n--\nnet/core/net_namespace.c-416-\nnet/core/net_namespace.c:417:#ifdef CONFIG_DEBUG_NET_SMALL_RTNL\nnet/core/net_namespace.c-418-\tmutex_init(\u0026net-\u003ertnl_mutex);\n--\nnet/core/rtnetlink.c=184=EXPORT_SYMBOL(lockdep_rtnl_is_held);\n--\nnet/core/rtnetlink.c-186-\nnet/core/rtnetlink.c:187:#ifdef CONFIG_DEBUG_NET_SMALL_RTNL\nnet/core/rtnetlink.c-188-void __rtnl_net_lock(struct net *net)\n--\nnet/core/rtnetlink.c=342=static void rtnl_nets_add(struct rtnl_nets *rtnl_nets, struct net *net)\n--\nnet/core/rtnetlink.c-345-\nnet/core/rtnetlink.c:346:\tDEBUG_NET_WARN_ON_ONCE(rtnl_nets-\u003elen == ARRAY_SIZE(rtnl_nets-\u003enet));\nnet/core/rtnetlink.c-347-\n--\nnet/core/rtnetlink.c=7303=void __init rtnetlink_init(void)\n--\nnet/core/rtnetlink.c-7311-\nnet/core/rtnetlink.c:7312:#ifdef CONFIG_DEBUG_NET_SMALL_RTNL\nnet/core/rtnetlink.c-7313-\trtnl_net_wq = create_workqueue(\"rtnl_net\");\n--\nnet/core/skbuff.c=674=struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,\n--\nnet/core/skbuff.c-733-\t\tBUILD_BUG_ON(SKB_FCLONE_UNAVAILABLE != 0);\nnet/core/skbuff.c:734:\t\tDEBUG_NET_WARN_ON_ONCE(skb-\u003efclone != SKB_FCLONE_UNAVAILABLE);\nnet/core/skbuff.c-735-\t\tskb-\u003efclone |= SKB_FCLONE_ORIG;\n--\nnet/core/skbuff.c=838=struct sk_buff *napi_alloc_skb(struct napi_struct *napi, unsigned int len)\n--\nnet/core/skbuff.c-845-\nnet/core/skbuff.c:846:\tDEBUG_NET_WARN_ON_ONCE(!in_softirq());\nnet/core/skbuff.c-847-\tlen += NET_SKB_PAD + NET_IP_ALIGN;\n--\nnet/core/skbuff.c=897=void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size,\n--\nnet/core/skbuff.c-901-\nnet/core/skbuff.c:902:\tDEBUG_NET_WARN_ON_ONCE(size \u003e truesize);\nnet/core/skbuff.c-903-\n--\nnet/core/skbuff.c=1169=void skb_release_head_state(struct sk_buff *skb)\n--\nnet/core/skbuff.c-1172-\tif (skb-\u003edestructor) {\n\n"
} |
| 9/2 | 2026/10/21 21:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 23935 output: 33 thoughts: 64 Thoughts: Okay, here's my assessment of the situation: **Investigating a Network Debug Warning** Alright, I see this `DEBUG_NET` macro is active, and specifically, it's tied to `DEBUG_NET_WARN_ON_ONCE`. Hmm, that's interesting. I need to understand what that macro actually *does*. The warning strongly suggests there's a specific condition being checked, and likely only warned once. Let's dig into the headers. I'll need to locate the definition of `DEBUG_NET_WARN_ON_ONCE`. My gut says it'll be in something like `include/net/net_debug.h`, or maybe a related debug header. Time to go hunting and see where this conditional warning is coming from. Once I've got the definition, I can determine exactly what's being flagged. |
| 10/2 | 2026/10/21 21:14 | tool | grepper |
0mArgs:{
"Expression": "DEBUG_NET_WARN_ON_ONCE",
"PathPrefixes": [
"include/"
]
}Results: {
"Output": "include/linux/netdevice.h=2730=struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev,\n--\ninclude/linux/netdevice.h-2732-{\ninclude/linux/netdevice.h:2733:\tDEBUG_NET_WARN_ON_ONCE(index \u003e= dev-\u003enum_tx_queues);\ninclude/linux/netdevice.h-2734-\treturn \u0026dev-\u003e_tx[index];\n--\ninclude/linux/skbuff.h=1174=static inline void skb_dst_check_unset(struct sk_buff *skb)\ninclude/linux/skbuff.h-1175-{\ninclude/linux/skbuff.h:1176:\tDEBUG_NET_WARN_ON_ONCE((skb-\u003e_skb_refdst \u0026 SKB_DST_PTRMASK) \u0026\u0026\ninclude/linux/skbuff.h-1177-\t\t\t !(skb-\u003e_skb_refdst \u0026 SKB_DST_NOREF));\n--\ninclude/linux/skbuff.h=2679=static inline void skb_add_rx_frag_netmem(struct sk_buff *skb, int i,\n--\ninclude/linux/skbuff.h-2682-{\ninclude/linux/skbuff.h:2683:\tDEBUG_NET_WARN_ON_ONCE(size \u003e truesize);\ninclude/linux/skbuff.h-2684-\n--\ninclude/linux/skbuff.h=2814=static inline void *__skb_push(struct sk_buff *skb, unsigned int len)\ninclude/linux/skbuff.h-2815-{\ninclude/linux/skbuff.h:2816:\tDEBUG_NET_WARN_ON_ONCE(len \u003e INT_MAX);\ninclude/linux/skbuff.h-2817-\ninclude/linux/skbuff.h-2818-\tskb-\u003edata -= len;\ninclude/linux/skbuff.h:2819:\tDEBUG_NET_WARN_ON_ONCE(skb-\u003edata \u003c skb-\u003ehead);\ninclude/linux/skbuff.h-2820-\tskb-\u003elen += len;\n--\ninclude/linux/skbuff.h=2825=static __always_inline void *__skb_pull(struct sk_buff *skb, unsigned int len)\ninclude/linux/skbuff.h-2826-{\ninclude/linux/skbuff.h:2827:\tDEBUG_NET_WARN_ON_ONCE(len \u003e INT_MAX);\ninclude/linux/skbuff.h-2828-\n--\ninclude/linux/skbuff.h=2851=pskb_may_pull_reason(struct sk_buff *skb, unsigned int len)\ninclude/linux/skbuff.h-2852-{\ninclude/linux/skbuff.h:2853:\tDEBUG_NET_WARN_ON_ONCE(len \u003e INT_MAX);\ninclude/linux/skbuff.h-2854-\tskb_might_realloc(skb);\n--\ninclude/linux/skbuff.h=2989=static inline void skb_reset_mac_len(struct sk_buff *skb)\n--\ninclude/linux/skbuff.h-2991-\tif (!skb_mac_header_was_set(skb)) {\ninclude/linux/skbuff.h:2992:\t\tDEBUG_NET_WARN_ON_ONCE(1);\ninclude/linux/skbuff.h-2993-\t\tskb-\u003emac_len = 0;\n--\ninclude/linux/skbuff.h=3010=static inline void skb_reset_inner_transport_header(struct sk_buff *skb)\n--\ninclude/linux/skbuff.h-3013-\ninclude/linux/skbuff.h:3014:\tDEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb-\u003einner_transport_header))offset);\ninclude/linux/skbuff.h-3015-\tskb-\u003einner_transport_header = offset;\n--\ninclude/linux/skbuff.h=3030=static inline void skb_reset_inner_network_header(struct sk_buff *skb)\n--\ninclude/linux/skbuff.h-3033-\ninclude/linux/skbuff.h:3034:\tDEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb-\u003einner_network_header))offset);\ninclude/linux/skbuff.h-3035-\tskb-\u003einner_network_header = offset;\n--\ninclude/linux/skbuff.h=3055=static inline void skb_reset_inner_mac_header(struct sk_buff *skb)\n--\ninclude/linux/skbuff.h-3058-\ninclude/linux/skbuff.h:3059:\tDEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb-\u003einner_mac_header))offset);\ninclude/linux/skbuff.h-3060-\tskb-\u003einner_mac_header = offset;\n--\ninclude/linux/skbuff.h=3079=static inline unsigned char *skb_transport_header(const struct sk_buff *skb)\ninclude/linux/skbuff.h-3080-{\ninclude/linux/skbuff.h:3081:\tDEBUG_NET_WARN_ON_ONCE(!skb_transport_header_was_set(skb));\ninclude/linux/skbuff.h-3082-\treturn skb-\u003ehead + skb-\u003etransport_header;\n--\ninclude/linux/skbuff.h=3085=static inline void skb_reset_transport_header(struct sk_buff *skb)\n--\ninclude/linux/skbuff.h-3088-\ninclude/linux/skbuff.h:3089:\tDEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb-\u003etransport_header))offset);\ninclude/linux/skbuff.h-3090-\tskb-\u003etransport_header = offset;\n--\ninclude/linux/skbuff.h=3152=static inline void skb_reset_network_header(struct sk_buff *skb)\n--\ninclude/linux/skbuff.h-3155-\ninclude/linux/skbuff.h:3156:\tDEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb-\u003enetwork_header))offset);\ninclude/linux/skbuff.h-3157-\tskb-\u003enetwork_header = offset;\n--\ninclude/linux/skbuff.h=3166=static inline unsigned char *skb_mac_header(const struct sk_buff *skb)\ninclude/linux/skbuff.h-3167-{\ninclude/linux/skbuff.h:3168:\tDEBUG_NET_WARN_ON_ONCE(!skb_mac_header_was_set(skb));\ninclude/linux/skbuff.h-3169-\treturn skb-\u003ehead + skb-\u003emac_header;\n--\ninclude/linux/skbuff.h=3177=static inline u32 skb_mac_header_len(const struct sk_buff *skb)\ninclude/linux/skbuff.h-3178-{\ninclude/linux/skbuff.h:3179:\tDEBUG_NET_WARN_ON_ONCE(!skb_mac_header_was_set(skb));\ninclude/linux/skbuff.h-3180-\treturn skb-\u003enetwork_header - skb-\u003emac_header;\n--\ninclude/linux/skbuff.h=3188=static inline void skb_reset_mac_header(struct sk_buff *skb)\n--\ninclude/linux/skbuff.h-3191-\ninclude/linux/skbuff.h:3192:\tDEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb-\u003emac_header))offset);\ninclude/linux/skbuff.h-3193-\tskb-\u003emac_header = offset;\n--\ninclude/linux/skbuff.h=3259=static inline u32 skb_network_header_len(const struct sk_buff *skb)\ninclude/linux/skbuff.h-3260-{\ninclude/linux/skbuff.h:3261:\tDEBUG_NET_WARN_ON_ONCE(!skb_transport_header_was_set(skb));\ninclude/linux/skbuff.h-3262-\treturn skb-\u003etransport_header - skb-\u003enetwork_header;\n--\ninclude/linux/skbuff.h=4686=static inline void skb_postpull_data_move(struct sk_buff *skb,\n--\ninclude/linux/skbuff.h-4689-{\ninclude/linux/skbuff.h:4690:\tDEBUG_NET_WARN_ON_ONCE(len \u003e INT_MAX);\ninclude/linux/skbuff.h-4691-\tskb_data_move(skb, len, n);\n--\ninclude/linux/skbuff.h=4702=static inline void skb_postpush_data_move(struct sk_buff *skb,\n--\ninclude/linux/skbuff.h-4705-{\ninclude/linux/skbuff.h:4706:\tDEBUG_NET_WARN_ON_ONCE(len \u003e INT_MAX);\ninclude/linux/skbuff.h-4707-\tskb_data_move(skb, -len, n);\n--\ninclude/linux/skbuff.h=5032=static inline void skb_set_nfct(struct sk_buff *skb, unsigned long nfct)\n--\ninclude/linux/skbuff.h-5034-#if IS_ENABLED(CONFIG_NF_CONNTRACK)\ninclude/linux/skbuff.h:5035:\tDEBUG_NET_WARN_ON_ONCE(skb-\u003e_nfct \u0026 NFCT_PTRMASK);\ninclude/linux/skbuff.h-5036-\tskb-\u003eslow_gro |= !!nfct;\n--\ninclude/linux/skbuff.h=5372=static inline void skb_checksum_none_assert(const struct sk_buff *skb)\ninclude/linux/skbuff.h-5373-{\ninclude/linux/skbuff.h:5374:\tDEBUG_NET_WARN_ON_ONCE(skb-\u003eip_summed != CHECKSUM_NONE);\ninclude/linux/skbuff.h-5375-}\n--\ninclude/linux/udp.h=47=static inline void udp_set_len_short(struct udphdr *uh, unsigned int len)\ninclude/linux/udp.h-48-{\ninclude/linux/udp.h:49:\tDEBUG_NET_WARN_ON_ONCE(len \u003e= GRO_LEGACY_MAX_SIZE);\ninclude/linux/udp.h-50-\tuh-\u003elen = htons(len);\n--\ninclude/linux/virtio_vsock.h=50=static inline void virtio_vsock_skb_put(struct sk_buff *skb, u32 len)\ninclude/linux/virtio_vsock.h-51-{\ninclude/linux/virtio_vsock.h:52:\tDEBUG_NET_WARN_ON_ONCE(skb-\u003elen);\ninclude/linux/virtio_vsock.h-53-\n--\ninclude/net/ip6_fib.h=340=static inline void fib6_info_release(struct fib6_info *f6i)\n--\ninclude/net/ip6_fib.h-342-\tif (f6i \u0026\u0026 refcount_dec_and_test(\u0026f6i-\u003efib6_ref)) {\ninclude/net/ip6_fib.h:343:\t\tDEBUG_NET_WARN_ON_ONCE(!hlist_unhashed(\u0026f6i-\u003egc_link));\ninclude/net/ip6_fib.h-344-\t\tcall_rcu_hurry(\u0026f6i-\u003ercu, fib6_info_destroy_rcu);\n--\ninclude/net/net_debug.h=114=do {\t\t\t\t\t\t\t\t\\\n--\ninclude/net/net_debug.h-151-#if defined(CONFIG_DEBUG_NET)\ninclude/net/net_debug.h:152:#define DEBUG_NET_WARN_ON_ONCE(cond) ((void)WARN_ON_ONCE(cond))\ninclude/net/net_debug.h-153-#define DEBUG_NET_WARN_ONCE(cond, format...) ((void)WARN_ONCE(cond, format))\ninclude/net/net_debug.h-154-#else\ninclude/net/net_debug.h:155:#define DEBUG_NET_WARN_ON_ONCE(cond) BUILD_BUG_ON_INVALID(cond)\ninclude/net/net_debug.h-156-#define DEBUG_NET_WARN_ONCE(cond, format...) BUILD_BUG_ON_INVALID(cond)\n--\ninclude/net/netlink.h=2261=static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start)\n--\ninclude/net/netlink.h-2264-\ninclude/net/netlink.h:2265:\tDEBUG_NET_WARN_ON_ONCE(diff \u003e U16_MAX);\ninclude/net/netlink.h-2266-\tstart-\u003enla_len = diff;\n--\ninclude/net/netmem.h=179=static inline struct net_iov *netmem_to_net_iov(netmem_ref netmem)\n--\ninclude/net/netmem.h-184-\ninclude/net/netmem.h:185:\tDEBUG_NET_WARN_ON_ONCE(true);\ninclude/net/netmem.h-186-\treturn NULL;\n--\ninclude/net/netmem.h=220=static inline unsigned long netmem_pfn_trace(netmem_ref netmem)\n--\ninclude/net/netmem.h-240-({\t\t\t\t\t\t\t\t\t\\\ninclude/net/netmem.h:241:\tDEBUG_NET_WARN_ON_ONCE(!page_pool_page_is_pp(p));\t\t\\\ninclude/net/netmem.h-242-\t__pp_page_to_nmdesc(p);\t\t\t\t\t\t\\\n--\ninclude/net/request_sock.h=128=static inline void reqsk_free(struct request_sock *req)\ninclude/net/request_sock.h-129-{\ninclude/net/request_sock.h:130:\tDEBUG_NET_WARN_ON_ONCE(refcount_read(\u0026req-\u003ersk_refcnt) != 0);\ninclude/net/request_sock.h-131-\t__reqsk_free(req);\n--\ninclude/net/sch_generic.h=918=static inline unsigned int qdisc_pkt_segs(const struct sk_buff *skb)\n--\ninclude/net/sch_generic.h-921-\ninclude/net/sch_generic.h:922:\tDEBUG_NET_WARN_ON_ONCE(pkt_segs !=\ninclude/net/sch_generic.h-923-\t\t\t(skb_is_gso(skb) ? skb_shinfo(skb)-\u003egso_segs : 1));\n--\ninclude/net/sch_generic.h=1236=static inline void qdisc_dequeue_drop(struct Qdisc *q, struct sk_buff *skb,\n--\ninclude/net/sch_generic.h-1240-\ninclude/net/sch_generic.h:1241:\tDEBUG_NET_WARN_ON_ONCE(!(q-\u003eflags \u0026 TCQ_F_DEQUEUE_DROPS));\ninclude/net/sch_generic.h:1242:\tDEBUG_NET_WARN_ON_ONCE(q-\u003eflags \u0026 TCQ_F_NOLOCK);\ninclude/net/sch_generic.h-1243-\n--\ninclude/net/sock.h=1823=static inline void sock_release_ownership(struct sock *sk)\ninclude/net/sock.h-1824-{\ninclude/net/sock.h:1825:\tDEBUG_NET_WARN_ON_ONCE(!sock_owned_by_user_nocheck(sk));\ninclude/net/sock.h-1826-\tsk-\u003esk_lock.owned = 0;\n--\ninclude/net/sock.h=2800=static inline int sk_drops_read(const struct sock *sk)\n--\ninclude/net/sock.h-2804-\tif (ndc) {\ninclude/net/sock.h:2805:\t\tDEBUG_NET_WARN_ON_ONCE(atomic_read(\u0026sk-\u003esk_drops));\ninclude/net/sock.h-2806-\t\treturn numa_drop_read(ndc);\n--\ninclude/net/tcp.h=830=static inline void tcp_add_receive_queue(struct sock *sk, struct sk_buff *skb)\ninclude/net/tcp.h-831-{\ninclude/net/tcp.h:832:\tDEBUG_NET_WARN_ON_ONCE(skb_dst(skb));\ninclude/net/tcp.h:833:\tDEBUG_NET_WARN_ON_ONCE(secpath_exists(skb));\ninclude/net/tcp.h-834-\t__skb_queue_tail(\u0026sk-\u003esk_receive_queue, skb);\n"
} |
| 11/2 | 2026/10/21 21:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 28564 output: 27 thoughts: 942 Thoughts: **Analyzing Network Debugging and Configuration Dependencies** Okay, here's what I'm seeing. This patch introduces `DEBUG_NET_WARN_ON_ONCE` throughout the networking code, but it's gated by `CONFIG_DEBUG_NET`. This seems like a pretty significant addition, especially given its presence in multiple core areas: `xen-netfront`, several `skbuff.c` functions dealing with checksums, copying, and segmentation, and even `tls_sw.c`. The fact that it's conditionally compiled based on `CONFIG_DEBUG_NET` is key. My immediate thought is, "This is good, this gives us a non-invasive way to enable some specific checks and see if there are any errors!" I need to confirm if this new `CONFIG_DEBUG_NET` is really just enabling the printk. From looking at the Kconfig, it seems to depend on `DEBUG_KERNEL` and `NET`, so that makes sense. Seems like enabling `CONFIG_DEBUG_NET` is going to be important to enable these debug checks. Next I'm thinking about the other configs mentioned in the code: `INET`, `NET_CRC32C`, and `TLS`. I see `INET` being used in several IPv4 and IPv6 files, which I'd expect. `NET_CRC32C` is used by a few checksum-related functions. Wait...is `NET_CRC32C` enabled by default, or is it selected by other configs? Looking at the Kconfig, it *doesn't* have a prompt, which means it can't be set directly in the `.config` unless selected by something else. That's a crucial point for syzkaller; if fragments are merged, a standalone `CONFIG_NET_CRC32C=y` might just disappear unless something explicitly selects it. I need to be sure the configs that depend on `NET_CRC32C` are properly set. It also looks like the `TLS` config is used for the `tls_sw.c` file, and I need to double-check that this is setup correctly. I need to quickly review which configurations select `NET_CRC32C` -- I have a list of a few, but a refresher is needed -- and then I should also confirm what `CONFIG_TLS` depends on as well. This is all about ensuring the right build environment is in place to catch potential issues introduced by this patch and to use these new debug prints. |
| 12/2 | 2026/10/21 21:14 | tool | grepper |
0mArgs:{
"Expression": "config TLS\\b",
"PathPrefixes": [
"net/"
]
}Results: {
"Output": "net/tls/Kconfig-4-#\nnet/tls/Kconfig:5:config TLS\nnet/tls/Kconfig-6-\ttristate \"Transport Layer Security support\"\n"
} |
| 13/2 | 2026/10/21 21:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 30115 output: 32 thoughts: 23 Thoughts: Here's my thought process, as if I were considering this myself: **Investigating the `CONFIG_TLS` Configuration** Okay, so I need a deeper dive on this `CONFIG_TLS` setting. Rather than just relying on immediate assumptions, let's establish the *source of truth* – the definitive documentation. My immediate instinct is to look within the kernel configuration system itself, so I'm thinking the logical place to start is `net/tls/Kconfig`. That file should contain the comprehensive description, dependencies, and potential options related to `CONFIG_TLS`. A quick peek there will confirm the exact scope of this configuration and save me time chasing down inaccurate assumptions. Let's see what we can find. |
| 14/2 | 2026/10/21 21:14 | tool | read-file |
0mArgs:{
"File": "net/tls/Kconfig",
"FirstLine": 1,
"LineCount": 40
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\t#\n 3:\t# TLS configuration\n 4:\t#\n 5:\tconfig TLS\n 6:\t\ttristate \"Transport Layer Security support\"\n 7:\t\tdepends on INET\n 8:\t\tselect CRYPTO\n 9:\t\tselect CRYPTO_AES\n 10:\t\tselect CRYPTO_GCM\n 11:\t\tselect NET_SOCK_MSG\n 12:\t\tdefault n\n 13:\t\thelp\n 14:\t\tEnable kernel support for TLS protocol. This allows symmetric\n 15:\t\tencryption handling of the TLS protocol to be done in-kernel.\n 16:\t\n 17:\t\tIf unsure, say N.\n 18:\t\n 19:\tconfig TLS_DEVICE\n 20:\t\tbool \"Transport Layer Security HW offload\"\n 21:\t\tdepends on TLS\n 22:\t\tselect SKB_DECRYPTED\n 23:\t\tselect SOCK_VALIDATE_XMIT\n 24:\t\tselect SOCK_RX_QUEUE_MAPPING\n 25:\t\tdefault n\n 26:\t\thelp\n 27:\t\tEnable kernel support for HW offload of the TLS protocol.\n 28:\t\n 29:\t\tIf unsure, say N.\n"
} |
| 15/2 | 2026/10/21 21:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 30646 output: 34 thoughts: 97 Thoughts: **Compilation Dependencies and Configuration Checks** Okay, so I'm looking at this build process and my initial thought is, "Right, `TLS` correctly compiles `net/tls/tls_sw.c`." That's good, expected behavior. Now, let's broaden the scope a bit. What about `net/sunrpc/socklib.c`? Ah, yes, that's under the `CONFIG_SUNRPC` umbrella, so the build should handle that correctly as well, assuming the configuration is set appropriately. Moving on, I need to check the IPv6 components in `net/ipv6/` – is the build properly managing the dependencies there, specifically the `IPV6` configuration? And then the final point I need to check are the Xen-related network device drivers, specifically `drivers/net/xen-netfront.c` -- I think that will be governed by the `XEN_NETDEV_FRONTEND` option. Therefore, I should explicitly verify that `XEN_NETDEV_FRONTEND` is correctly considered during the build. |
| 16/2 | 2026/10/21 21:14 | tool | grepper |
0mArgs:{
"Expression": "config XEN_NETDEV_FRONTEND",
"PathPrefixes": [
"drivers/net/"
]
}Results: {
"Output": "drivers/net/Kconfig=542=source \"drivers/net/wwan/Kconfig\"\ndrivers/net/Kconfig-543-\ndrivers/net/Kconfig:544:config XEN_NETDEV_FRONTEND\ndrivers/net/Kconfig-545-\ttristate \"Xen network device frontend driver\"\n"
} |
| 17/2 | 2026/10/21 21:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 31096 output: 33 thoughts: 34 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **Investigating `sunvnet` and Its Place** Right, let's see, what's this about? Ah, it's about network drivers. The filename `sunvnet_common.c` sticks out – that's a familiar naming convention, indicating a common component within the `sunvnet` driver set. So, the question is, what's the deal with `sunvnet` specifically? I need to quickly refresh my memory on the significance of that driver. Let's dig into `sunvnet` and see what comes up. Time to investigate. |
| 18/2 | 2026/10/21 21:14 | tool | grepper |
0mArgs:{
"Expression": "sunvnet",
"PathPrefixes": [
"drivers/net/ethernet/sun/"
]
}Results: {
"Output": "\nFull output is too long, showing 200 out of 341 lines.\nUse more precise expression or PathPrefixes if possible.\n\nNumber of matching lines per file (5 files in total):\ndrivers/net/ethernet/sun/Makefile:2\ndrivers/net/ethernet/sun/ldmvsw.c:18\ndrivers/net/ethernet/sun/sunvnet.c:21\ndrivers/net/ethernet/sun/sunvnet_common.c:41\ndrivers/net/ethernet/sun/sunvnet_common.h:17\n\ndrivers/net/ethernet/sun/Makefile=10=obj-$(CONFIG_CASSINI) += cassini.o\ndrivers/net/ethernet/sun/Makefile:11:obj-$(CONFIG_SUNVNET_COMMON) += sunvnet_common.o\ndrivers/net/ethernet/sun/Makefile:12:obj-$(CONFIG_SUNVNET) += sunvnet.o\ndrivers/net/ethernet/sun/Makefile-13-obj-$(CONFIG_LDMVSW) += ldmvsw.o\n--\ndrivers/net/ethernet/sun/ldmvsw.c-32-\ndrivers/net/ethernet/sun/ldmvsw.c:33:/* This driver makes use of the common code in sunvnet_common.c */\ndrivers/net/ethernet/sun/ldmvsw.c:34:#include \"sunvnet_common.h\"\ndrivers/net/ethernet/sun/ldmvsw.c-35-\n--\ndrivers/net/ethernet/sun/ldmvsw.c=115=static netdev_tx_t vsw_start_xmit(struct sk_buff *skb, struct net_device *dev)\ndrivers/net/ethernet/sun/ldmvsw.c-116-{\ndrivers/net/ethernet/sun/ldmvsw.c:117:\treturn sunvnet_start_xmit_common(skb, dev, vsw_tx_port_find);\ndrivers/net/ethernet/sun/ldmvsw.c-118-}\n--\ndrivers/net/ethernet/sun/ldmvsw.c=120=static void vsw_set_rx_mode(struct net_device *dev)\n--\ndrivers/net/ethernet/sun/ldmvsw.c-123-\ndrivers/net/ethernet/sun/ldmvsw.c:124:\treturn sunvnet_set_rx_mode_common(dev, port-\u003evp);\ndrivers/net/ethernet/sun/ldmvsw.c-125-}\n--\ndrivers/net/ethernet/sun/ldmvsw.c=141=static void vsw_poll_controller(struct net_device *dev)\n--\ndrivers/net/ethernet/sun/ldmvsw.c-144-\ndrivers/net/ethernet/sun/ldmvsw.c:145:\treturn sunvnet_poll_controller_common(dev, port-\u003evp);\ndrivers/net/ethernet/sun/ldmvsw.c-146-}\n--\ndrivers/net/ethernet/sun/ldmvsw.c=149=static const struct net_device_ops vsw_ops = {\ndrivers/net/ethernet/sun/ldmvsw.c-150-\t.ndo_open\t\t= ldmvsw_open,\ndrivers/net/ethernet/sun/ldmvsw.c:151:\t.ndo_stop\t\t= sunvnet_close_common,\ndrivers/net/ethernet/sun/ldmvsw.c-152-\t.ndo_set_rx_mode\t= vsw_set_rx_mode,\ndrivers/net/ethernet/sun/ldmvsw.c:153:\t.ndo_set_mac_address\t= sunvnet_set_mac_addr_common,\ndrivers/net/ethernet/sun/ldmvsw.c-154-\t.ndo_validate_addr\t= eth_validate_addr,\ndrivers/net/ethernet/sun/ldmvsw.c:155:\t.ndo_tx_timeout\t\t= sunvnet_tx_timeout_common,\ndrivers/net/ethernet/sun/ldmvsw.c-156-\t.ndo_start_xmit\t\t= vsw_start_xmit,\n--\ndrivers/net/ethernet/sun/ldmvsw.c=260=static struct ldc_channel_config vsw_ldc_cfg = {\ndrivers/net/ethernet/sun/ldmvsw.c:261:\t.event\t\t= sunvnet_event_common,\ndrivers/net/ethernet/sun/ldmvsw.c-262-\t.mtu\t\t= 64,\n--\ndrivers/net/ethernet/sun/ldmvsw.c=266=static struct vio_driver_ops vsw_vio_ops = {\ndrivers/net/ethernet/sun/ldmvsw.c:267:\t.send_attr\t\t= sunvnet_send_attr_common,\ndrivers/net/ethernet/sun/ldmvsw.c:268:\t.handle_attr\t\t= sunvnet_handle_attr_common,\ndrivers/net/ethernet/sun/ldmvsw.c:269:\t.handshake_complete\t= sunvnet_handshake_complete_common,\ndrivers/net/ethernet/sun/ldmvsw.c-270-};\n--\ndrivers/net/ethernet/sun/ldmvsw.c=275=static int vsw_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)\n--\ndrivers/net/ethernet/sun/ldmvsw.c-341-\t * rather than the net_device in the vnet (which is used\ndrivers/net/ethernet/sun/ldmvsw.c:342:\t * by sunvnet). This bit is used by the VNET_PORT_TO_NET_DEVICE\ndrivers/net/ethernet/sun/ldmvsw.c-343-\t * macro.\n--\ndrivers/net/ethernet/sun/ldmvsw.c-358-\ndrivers/net/ethernet/sun/ldmvsw.c:359:\tnetif_napi_add(dev, \u0026port-\u003enapi, sunvnet_poll_common);\ndrivers/net/ethernet/sun/ldmvsw.c-360-\n--\ndrivers/net/ethernet/sun/ldmvsw.c-364-\ndrivers/net/ethernet/sun/ldmvsw.c:365:\ttimer_setup(\u0026port-\u003eclean_timer, sunvnet_clean_timer_expire_common, 0);\ndrivers/net/ethernet/sun/ldmvsw.c-366-\n--\ndrivers/net/ethernet/sun/ldmvsw.c-373-\tspin_lock_irqsave(\u0026vp-\u003elock, flags);\ndrivers/net/ethernet/sun/ldmvsw.c:374:\tsunvnet_port_add_txq_common(port);\ndrivers/net/ethernet/sun/ldmvsw.c-375-\tspin_unlock_irqrestore(\u0026vp-\u003elock, flags);\n--\ndrivers/net/ethernet/sun/ldmvsw.c=405=static void vsw_port_remove(struct vio_dev *vdev)\n--\ndrivers/net/ethernet/sun/ldmvsw.c-420-\t\tspin_lock_irqsave(\u0026port-\u003evp-\u003elock, flags);\ndrivers/net/ethernet/sun/ldmvsw.c:421:\t\tsunvnet_port_rm_txq_common(port);\ndrivers/net/ethernet/sun/ldmvsw.c-422-\t\tspin_unlock_irqrestore(\u0026port-\u003evp-\u003elock, flags);\ndrivers/net/ethernet/sun/ldmvsw.c-423-\t\tnetif_napi_del(\u0026port-\u003enapi);\ndrivers/net/ethernet/sun/ldmvsw.c:424:\t\tsunvnet_port_free_tx_bufs_common(port);\ndrivers/net/ethernet/sun/ldmvsw.c-425-\t\tvio_ldc_free(\u0026port-\u003evio);\n--\ndrivers/net/ethernet/sun/sunvnet.c-1-// SPDX-License-Identifier: GPL-2.0\ndrivers/net/ethernet/sun/sunvnet.c:2:/* sunvnet.c: Sun LDOM Virtual Network Driver.\ndrivers/net/ethernet/sun/sunvnet.c-3- *\n--\ndrivers/net/ethernet/sun/sunvnet.c-33-\ndrivers/net/ethernet/sun/sunvnet.c:34:#include \"sunvnet_common.h\"\ndrivers/net/ethernet/sun/sunvnet.c-35-\n--\ndrivers/net/ethernet/sun/sunvnet.c-40-\ndrivers/net/ethernet/sun/sunvnet.c:41:#define DRV_MODULE_NAME\t\t\"sunvnet\"\ndrivers/net/ethernet/sun/sunvnet.c-42-#define DRV_MODULE_VERSION\t\"2.0\"\n--\ndrivers/net/ethernet/sun/sunvnet.c=191=static struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb)\n--\ndrivers/net/ethernet/sun/sunvnet.c-197-\thlist_for_each_entry_rcu(port, hp, hash) {\ndrivers/net/ethernet/sun/sunvnet.c:198:\t\tif (!sunvnet_port_is_up_common(port))\ndrivers/net/ethernet/sun/sunvnet.c-199-\t\t\tcontinue;\n--\ndrivers/net/ethernet/sun/sunvnet.c-205-\t\t\tcontinue;\ndrivers/net/ethernet/sun/sunvnet.c:206:\t\tif (!sunvnet_port_is_up_common(port))\ndrivers/net/ethernet/sun/sunvnet.c-207-\t\t\tcontinue;\n--\ndrivers/net/ethernet/sun/sunvnet.c=235=static netdev_tx_t vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)\ndrivers/net/ethernet/sun/sunvnet.c-236-{\ndrivers/net/ethernet/sun/sunvnet.c:237:\treturn sunvnet_start_xmit_common(skb, dev, vnet_tx_port_find);\ndrivers/net/ethernet/sun/sunvnet.c-238-}\n--\ndrivers/net/ethernet/sun/sunvnet.c=240=static void vnet_set_rx_mode(struct net_device *dev)\n--\ndrivers/net/ethernet/sun/sunvnet.c-243-\ndrivers/net/ethernet/sun/sunvnet.c:244:\treturn sunvnet_set_rx_mode_common(dev, vp);\ndrivers/net/ethernet/sun/sunvnet.c-245-}\n--\ndrivers/net/ethernet/sun/sunvnet.c=248=static void vnet_poll_controller(struct net_device *dev)\n--\ndrivers/net/ethernet/sun/sunvnet.c-251-\ndrivers/net/ethernet/sun/sunvnet.c:252:\treturn sunvnet_poll_controller_common(dev, vp);\ndrivers/net/ethernet/sun/sunvnet.c-253-}\n--\ndrivers/net/ethernet/sun/sunvnet.c=256=static const struct net_device_ops vnet_ops = {\ndrivers/net/ethernet/sun/sunvnet.c:257:\t.ndo_open\t\t= sunvnet_open_common,\ndrivers/net/ethernet/sun/sunvnet.c:258:\t.ndo_stop\t\t= sunvnet_close_common,\ndrivers/net/ethernet/sun/sunvnet.c-259-\t.ndo_set_rx_mode\t= vnet_set_rx_mode,\ndrivers/net/ethernet/sun/sunvnet.c:260:\t.ndo_set_mac_address\t= sunvnet_set_mac_addr_common,\ndrivers/net/ethernet/sun/sunvnet.c-261-\t.ndo_validate_addr\t= eth_validate_addr,\ndrivers/net/ethernet/sun/sunvnet.c:262:\t.ndo_tx_timeout\t\t= sunvnet_tx_timeout_common,\ndrivers/net/ethernet/sun/sunvnet.c-263-\t.ndo_start_xmit\t\t= vnet_start_xmit,\n--\ndrivers/net/ethernet/sun/sunvnet.c=397=static struct ldc_channel_config vnet_ldc_cfg = {\ndrivers/net/ethernet/sun/sunvnet.c:398:\t.event\t\t= sunvnet_event_common,\ndrivers/net/ethernet/sun/sunvnet.c-399-\t.mtu\t\t= 64,\n--\ndrivers/net/ethernet/sun/sunvnet.c=403=static struct vio_driver_ops vnet_vio_ops = {\ndrivers/net/ethernet/sun/sunvnet.c:404:\t.send_attr\t\t= sunvnet_send_attr_common,\ndrivers/net/ethernet/sun/sunvnet.c:405:\t.handle_attr\t\t= sunvnet_handle_attr_common,\ndrivers/net/ethernet/sun/sunvnet.c:406:\t.handshake_complete\t= sunvnet_handshake_complete_common,\ndrivers/net/ethernet/sun/sunvnet.c-407-};\n--\ndrivers/net/ethernet/sun/sunvnet.c=411=static int vnet_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)\n--\ndrivers/net/ethernet/sun/sunvnet.c-458-\ndrivers/net/ethernet/sun/sunvnet.c:459:\tnetif_napi_add(port-\u003evp-\u003edev, \u0026port-\u003enapi, sunvnet_poll_common);\ndrivers/net/ethernet/sun/sunvnet.c-460-\n--\ndrivers/net/ethernet/sun/sunvnet.c-477-\t\t\t \u0026vp-\u003eport_hash[vnet_hashfn(port-\u003eraddr)]);\ndrivers/net/ethernet/sun/sunvnet.c:478:\tsunvnet_port_add_txq_common(port);\ndrivers/net/ethernet/sun/sunvnet.c-479-\tspin_unlock_irqrestore(\u0026vp-\u003elock, flags);\n--\ndrivers/net/ethernet/sun/sunvnet.c-485-\ndrivers/net/ethernet/sun/sunvnet.c:486:\ttimer_setup(\u0026port-\u003eclean_timer, sunvnet_clean_timer_expire_common, 0);\ndrivers/net/ethernet/sun/sunvnet.c-487-\n--\ndrivers/net/ethernet/sun/sunvnet.c=503=static void vnet_port_remove(struct vio_dev *vdev)\n--\ndrivers/net/ethernet/sun/sunvnet.c-516-\t\ttimer_shutdown_sync(\u0026port-\u003eclean_timer);\ndrivers/net/ethernet/sun/sunvnet.c:517:\t\tsunvnet_port_rm_txq_common(port);\ndrivers/net/ethernet/sun/sunvnet.c-518-\t\tnetif_napi_del(\u0026port-\u003enapi);\ndrivers/net/ethernet/sun/sunvnet.c:519:\t\tsunvnet_port_free_tx_bufs_common(port);\ndrivers/net/ethernet/sun/sunvnet.c-520-\t\tvio_ldc_free(\u0026port-\u003evio);\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-1-// SPDX-License-Identifier: GPL-2.0\ndrivers/net/ethernet/sun/sunvnet_common.c:2:/* sunvnet.c: Sun LDOM Virtual Network Driver.\ndrivers/net/ethernet/sun/sunvnet_common.c-3- *\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-20-#define CREATE_TRACE_POINTS\ndrivers/net/ethernet/sun/sunvnet_common.c:21:#include \u003ctrace/events/sunvnet.h\u003e\ndrivers/net/ethernet/sun/sunvnet_common.c-22-\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-34-\ndrivers/net/ethernet/sun/sunvnet_common.c:35:#include \"sunvnet_common.h\"\ndrivers/net/ethernet/sun/sunvnet_common.c-36-\n--\ndrivers/net/ethernet/sun/sunvnet_common.c=67=static int vnet_port_alloc_tx_ring(struct vnet_port *port);\ndrivers/net/ethernet/sun/sunvnet_common.c-68-\ndrivers/net/ethernet/sun/sunvnet_common.c:69:int sunvnet_send_attr_common(struct vio_driver_state *vio)\ndrivers/net/ethernet/sun/sunvnet_common.c-70-{\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-129-}\ndrivers/net/ethernet/sun/sunvnet_common.c:130:EXPORT_SYMBOL_GPL(sunvnet_send_attr_common);\ndrivers/net/ethernet/sun/sunvnet_common.c-131-\n--\ndrivers/net/ethernet/sun/sunvnet_common.c=233=static int handle_attr_nack(struct vio_driver_state *vio,\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-240-\ndrivers/net/ethernet/sun/sunvnet_common.c:241:int sunvnet_handle_attr_common(struct vio_driver_state *vio, void *arg)\ndrivers/net/ethernet/sun/sunvnet_common.c-242-{\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-258-}\ndrivers/net/ethernet/sun/sunvnet_common.c:259:EXPORT_SYMBOL_GPL(sunvnet_handle_attr_common);\ndrivers/net/ethernet/sun/sunvnet_common.c-260-\ndrivers/net/ethernet/sun/sunvnet_common.c:261:void sunvnet_handshake_complete_common(struct vio_driver_state *vio)\ndrivers/net/ethernet/sun/sunvnet_common.c-262-{\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-272-}\ndrivers/net/ethernet/sun/sunvnet_common.c:273:EXPORT_SYMBOL_GPL(sunvnet_handshake_complete_common);\ndrivers/net/ethernet/sun/sunvnet_common.c-274-\n--\ndrivers/net/ethernet/sun/sunvnet_common.c=760=static void maybe_tx_wakeup(struct vnet_port *port)\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-771-\ndrivers/net/ethernet/sun/sunvnet_common.c:772:bool sunvnet_port_is_up_common(struct vnet_port *vnet)\ndrivers/net/ethernet/sun/sunvnet_common.c-773-{\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-777-}\ndrivers/net/ethernet/sun/sunvnet_common.c:778:EXPORT_SYMBOL_GPL(sunvnet_port_is_up_common);\ndrivers/net/ethernet/sun/sunvnet_common.c-779-\ndrivers/net/ethernet/sun/sunvnet_common.c=780=static int vnet_event_napi(struct vnet_port *port, int budget)\n\n"
} |
| 19/2 | 2026/10/21 21:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 36394 output: 29 thoughts: 28 Thoughts: Here's the summary, tailored for an expert audience: **Sunvnet Kconfig Verification** Okay, so Sunvnet... right, that's the SPARC LDOM virtual network driver. Given my familiarity with SPARC and virtualization, I need to confirm the Kconfig setup for it. I'm going to quickly drill down into the Kconfig files, focusing on the SUNVNET configuration. I'll be looking for the dependencies, specifically how it’s tied to the SPARC architecture and LDOM features. I'll need to verify its build-time options and make sure everything is defined as expected within the context of the larger networking subsystem. My primary goal here is to ensure the configuration is accurate and complete, particularly in any context-sensitive configuration options. |
| 20/2 | 2026/10/21 21:15 | tool | grepper |
0mArgs:{
"Expression": "config SUNVNET",
"PathPrefixes": [
"drivers/net/"
]
}Results: {
"Output": "drivers/net/ethernet/sun/Kconfig=65=config CASSINI\n--\ndrivers/net/ethernet/sun/Kconfig-72-\ndrivers/net/ethernet/sun/Kconfig:73:config SUNVNET_COMMON\ndrivers/net/ethernet/sun/Kconfig-74-\ttristate \"Common routines to support Sun Virtual Networking\"\n--\ndrivers/net/ethernet/sun/Kconfig-78-\ndrivers/net/ethernet/sun/Kconfig:79:config SUNVNET\ndrivers/net/ethernet/sun/Kconfig-80-\ttristate \"Sun Virtual Network support\"\n"
} |
| 21/2 | 2026/10/21 21:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 36778 output: 38 thoughts: 23 Thoughts: Here's a summary of my thought process, tailored for an expert like you: **Diving into the Network Driver Configuration** Okay, so I need to zero in on a specific area within the kernel configuration. The task at hand likely involves some kind of network interface configuration or a potential issue with a Sun Ethernet driver. My immediate instinct is to look at `drivers/net/ethernet/sun/Kconfig`, specifically around line 73. That line or the surrounding context within that file is probably where the relevant configuration options or dependencies for that driver reside. I'm hoping to quickly identify the pertinent configuration variable or logic that needs further inspection. It could be a simple option that's misconfigured, or perhaps a more complex dependency tree is involved. This is my starting point to quickly understand the current configuration state and identify the relevant piece of code. |
| 22/2 | 2026/10/21 21:15 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/sun/Kconfig",
"FirstLine": 70,
"LineCount": 25
}Results: {
"Contents": " 70:\t\t Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also\n 71:\t\t \u003chttp://docs.oracle.com/cd/E19113-01/giga.ether.pci/817-4341-10/817-4341-10.pdf\u003e.\n 72:\t\n 73:\tconfig SUNVNET_COMMON\n 74:\t\ttristate \"Common routines to support Sun Virtual Networking\"\n 75:\t\tdepends on SUN_LDOMS\n 76:\t\tdepends on INET\n 77:\t\tdefault m\n 78:\t\n 79:\tconfig SUNVNET\n 80:\t\ttristate \"Sun Virtual Network support\"\n 81:\t\tdefault m\n 82:\t\tdepends on SUN_LDOMS\n 83:\t\tdepends on SUNVNET_COMMON\n 84:\t\thelp\n 85:\t\t Support for virtual network devices under Sun Logical Domains.\n 86:\t\n 87:\tconfig LDMVSW\n 88:\t\ttristate \"Sun4v LDoms Virtual Switch support\"\n 89:\t\tdefault m\n 90:\t\tdepends on SUN_LDOMS\n 91:\t\tdepends on SUNVNET_COMMON\n 92:\t\thelp\n 93:\t\t Support for virtual switch devices under Sun4v Logical Domains.\n 94:\t\t This driver adds a network interface for every vsw-port node\n"
} |
| 23/2 | 2026/10/21 21:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 37384 output: 31 thoughts: 1653 Thoughts: **Focusing the Fuzzer: A Networking Deep Dive** Okay, so `SUN_LDOMS` is definitely SPARC-specific, which means sunvnet isn't relevant to amd64, but that's not the core issue. My initial read suggested it was the main focus, but the real meat is in the networking code. I need to pivot my analysis. This patch is a goldmine for fuzzing! It touches core networking components – skbuff, dev, ip, ip6, tls – and introduces runtime assertions and significant refactoring with crucial error handling. This is prime territory. The changes are expansive: `skb_checksum_full` and `skb_crc32c_full` are brand new, exported helper functions in skbuff, which screams 'vulnerable surface'. The change in `skb_copy_and_csum_bits`'s API with updated call sites further widens the scope, implicating various networking paths. Moreover the refactoring touches checks and assertions in `skb_segment`, `skb_zerocopy`, `skb_try_coalesce` and `__skb_nsg`! This is where things get interesting. Now, I need to prevent dilution of the fuzzing effort. I'm thinking about focus symbols. I have to avoid those ubiquitous lifecycle hot-paths. `skb_checksum` - is it ubiquitous? Let's drill down. Wait, no, `skb_segment` looks like a winner! GSO/TSO segmentation is specific. Not called everywhere! That's a target. `skb_copy_and_csum_bits` - same story. It's called in specific paths that I can isolate: `vnet_skb_shape`, `icmp_glue_bits`, `__ip_append_data`, `icmpv6_getfrag`, `__ip6_append_data`, `xdr_skb_read_bits`, `skb_segment` and `skb_copy_and_csum_dev`. Let's also look at `skb_checksum_full` and `skb_crc32c_full`, newly exported and therefore distinct symbols, so those are definitely in scope. `skb_crc32c_csum_help` is called for CRC32c csum offload, a well-defined use case. What about `skb_try_coalesce` and `skb_zerocopy`? More to examine! Also, I need to check which callers use `__skb_nsg`, as it is static, to ensure I'm not missing entrypoints. |
| 24/2 | 2026/10/21 21:15 | tool | grepper |
0mArgs:{
"Expression": "__skb_nsg",
"PathPrefixes": [
"net/tls/"
]
}Results: {
"Output": "net/tls/tls_sw.c=71=noinline void tls_err_abort(struct sock *sk, int err)\n--\nnet/tls/tls_sw.c-80-\nnet/tls/tls_sw.c:81:static int __skb_nsg(struct sk_buff *skb, int offset, int len,\nnet/tls/tls_sw.c-82- unsigned int recursion_level)\n--\nnet/tls/tls_sw.c-131- chunk = len;\nnet/tls/tls_sw.c:132: ret = __skb_nsg(frag_iter, offset - start, chunk,\nnet/tls/tls_sw.c-133- recursion_level + 1);\n--\nnet/tls/tls_sw.c=155=static int skb_nsg(struct sk_buff *skb, int offset, int len)\nnet/tls/tls_sw.c-156-{\nnet/tls/tls_sw.c:157: return __skb_nsg(skb, offset, len, 0);\nnet/tls/tls_sw.c-158-}\n"
} |
| 25/2 | 2026/10/21 21:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 39943 output: 30 thoughts: 25 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Analyzing `skb_nsg` Calls in `net/tls/tls_sw.c`** Alright, let's dive into this. My initial instinct is to pinpoint every single call site of `skb_nsg` within `net/tls/tls_sw.c`. This isn't just a casual exploration; it's about understanding the control flow and data manipulation within the TLS software path. I want a complete picture. What are the specific contexts, the conditions under which `skb_nsg` is invoked? What's the impact on the skb lifecycle when this function is called? Is there any interesting usage of the nsg argument to be found? I want to know where and how network segments are being managed within the TLS layer. This is going to give me a good handle on memory management, potential fragmentation issues, or optimization opportunities in the TLS software path. Any interesting patterns within this function may provide clues to how the TLS stack interacts with hardware offloading and the overall performance implications. This deeper dive could uncover subtle inefficiencies or potential vulnerabilities related to network segment manipulation. Time to dig in. |
| 26/2 | 2026/10/21 21:15 | tool | grepper |
0mArgs:{
"Expression": "skb_nsg",
"PathPrefixes": [
"net/tls/"
]
}Results: {
"Output": "net/tls/tls_sw.c=71=noinline void tls_err_abort(struct sock *sk, int err)\n--\nnet/tls/tls_sw.c-80-\nnet/tls/tls_sw.c:81:static int __skb_nsg(struct sk_buff *skb, int offset, int len,\nnet/tls/tls_sw.c-82- unsigned int recursion_level)\n--\nnet/tls/tls_sw.c-131- chunk = len;\nnet/tls/tls_sw.c:132: ret = __skb_nsg(frag_iter, offset - start, chunk,\nnet/tls/tls_sw.c-133- recursion_level + 1);\n--\nnet/tls/tls_sw.c-154- */\nnet/tls/tls_sw.c:155:static int skb_nsg(struct sk_buff *skb, int offset, int len)\nnet/tls/tls_sw.c-156-{\nnet/tls/tls_sw.c:157: return __skb_nsg(skb, offset, len, 0);\nnet/tls/tls_sw.c-158-}\n--\nnet/tls/tls_sw.c=1268=static int tls_decrypt_sg(struct sock *sk, struct iov_iter *out_iov,\n--\nnet/tls/tls_sw.c-1288-\nnet/tls/tls_sw.c:1289:\tn_sgin = skb_nsg(skb, rxm-\u003eoffset + prot-\u003eprepend_size,\nnet/tls/tls_sw.c-1290-\t\t\t rxm-\u003efull_len - prot-\u003eprepend_size);\n"
} |
| 27/2 | 2026/10/21 21:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 40701 output: 35 thoughts: 303 Thoughts: **Analyzing Network Stack Modifications** Okay, let's break this down. I see that `tls_decrypt_sg` calls `skb_nsg`, which in turn calls `__skb_nsg`. Hmm, I should trace back where `tls_decrypt_sg` is being called from. Ah, `tls_sw_recvmsg`. That makes sense in the context of TLS processing. Now, let's shift focus to the other modified functions. A quick scan of `net/core/skbuff.c` reveals several changes: `skb_checksum_full` (a new exported symbol, interesting), `skb_copy_and_csum_bits` (modified, also exported - a critical piece), `skb_crc32c_full` (another new checksum-related function), `skb_segment` (modified – packet segmentation is a common area for optimization), `skb_zerocopy` (modified – always good to see more zero-copy), `skb_try_coalesce` (modified – SKB coalescing is crucial for performance), `skb_copy_and_csum_dev` (modified, related to hardware offload probably), `__skb_checksum_complete` (modified, lower-level checksumming), and `__skb_checksum_complete_head` (another checksum-related, head-specific modification). And, looking at `net/core/dev.c` now, `skb_crc32c_csum_help` is also modified and exported. A lot of activity around checksumming, segmentation and SKB manipulation. Wait, what's this about `bounce_skb` in `drivers/net/xen-netfront.c`? That feels out of place. I need to investigate that file now. This looks like a potentially important piece of the puzzle. Let's see what's going on there. |
| 28/2 | 2026/10/21 21:15 | tool | grepper |
0mArgs:{
"Expression": "bounce_skb",
"PathPrefixes": [
"drivers/net/xen-netfront.c"
]
}Results: {
"Output": "drivers/net/xen-netfront.c=644=static int xennet_xdp_xmit(struct net_device *dev, int n,\n--\ndrivers/net/xen-netfront.c-675-\ndrivers/net/xen-netfront.c:676:static struct sk_buff *bounce_skb(const struct sk_buff *skb)\ndrivers/net/xen-netfront.c-677-{\n--\ndrivers/net/xen-netfront.c=711=static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)\n--\ndrivers/net/xen-netfront.c-766-\tif (np-\u003ebounce || unlikely(PAGE_SIZE - offset \u003c ETH_HLEN)) {\ndrivers/net/xen-netfront.c:767:\t\tnskb = bounce_skb(skb);\ndrivers/net/xen-netfront.c-768-\t\tif (!nskb)\n"
} |
| 29/2 | 2026/10/21 21:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 41708 output: 30 thoughts: 1990 Thoughts: **Deep Dive into Skb Segmentation and Checksumming** Okay, let's break this down. It seems the initial focus on `xennet_start_xmit` and `bounce_skb` was a bit of a sidetrack; the core of these changes lies in how we handle `sk_buff` (skb) segmentation and checksumming, particularly in scenarios where we might have fragmented or nested lists. The core focus seems to be on `skbuff.c` and related network core functions. I should review these core skb functions and how they relate to the GSO (Generic Segmentation Offload) operations, including changes in checksumming. The `net/core/filter.c` change was minor, just a comment update, nothing significant there. Similarly, the `net/core/net_test.c` updates introducing KUnit tests for GSO fragmentation, while interesting for testing, aren't the heart of the functional changes. Now, looking at `net/core/skbuff.c`, the following changes have been made in `skb_segment`: * **Error Handling and Nested Frags:** We're seeing more robust error handling related to nested fragment lists. The code now actively checks for and handles cases where a GSO segment is nested within another frag_list, and the nested fragments are detected through checks like `skb_has_frag_list`. The `DEBUG_NET_WARN_ON_ONCE(1)` macro is popping up, indicating potential unexpected states. This should be investigated for its implications for any performance impact of the extra checks. * **Checksumming Integration:** There's now integration of checksum calculations within `skb_segment`, and several new error checks are added regarding checksum calculations: `skb_copy_and_csum_bits` and `skb_checksum_full`. The checksum value and its position are crucial for performance. * **Checksum Errors:** The code now has error handling and explicitly goes to the `err` label when errors occur: `-EFAULT` and `-EINVAL` are returned to propagate the error. `skb_checksum_full` is a new function! It calculates the checksum of a range within an skb, with a lot of boundary checks and debugging macros. It is called by several critical functions which indicates that this function is critical for network performance. `skb_copy_and_csum_bits` also got a significant overhaul! We're seeing the addition of `DEBUG_NET_WARN_ON_ONCE(1)` for negative lengths or leftover length, along with memory zeroing on `-EFAULT`. This is significant because it's used in a wide array of functions; any subtle bug here could have a widespread impact. The function's role in checksum calculation is apparent. `skb_crc32c_full` is another addition. This is good to see as new CRC32c features appear. We might have to check if the new CRC32c functions are actually implemented on all interfaces in use. `skb_zerocopy` has changed logic to check `skb_tailroom`, indicating improvements in optimization. The code is optimized by using `skb_copy_bits`. `skb_try_coalesce` changes are less significant, it just changed an assertion. Both `__skb_checksum_complete` and `__skb_checksum_complete_head` now use `skb_checksum_full`. `skb_copy_and_csum_dev` gets increased checking and error handling for `skb_copy_and_csum_bits`. And finally, `tls_decrypt_sg` and related functions in `net/tls/tls_sw.c`. While I need to check the exact calls, these may be related to secure networking. The fact that `__skb_nsg` is static inline/static suggests it's a helper internal to the TLS implementation. We might look more into the calls from `tls_decrypt_sg`. The overarching theme is a tightening of error handling, particularly around checksumming and segmentation, along with additions of features for new crc32c capabilities. There might be some performance trade-offs, particularly due to the added checks and error handling, but the added robustness is definitely welcome. I'll need to dig into the performance implications with some benchmarks, and make sure that any bugs are caught and tracked. |
| 30/2 | 2026/10/21 21:15 | tool | grepper |
0mArgs:{
"Expression": "tls_decrypt_sg",
"PathPrefixes": [
"net/tls/"
]
}Results: {
"Output": "net/tls/tls_sw.c=1226=tls_alloc_clrtxt_skb(struct sock *sk, struct sk_buff *skb,\n--\nnet/tls/tls_sw.c-1267- */\nnet/tls/tls_sw.c:1268:static int tls_decrypt_sg(struct sock *sk, struct iov_iter *out_iov,\nnet/tls/tls_sw.c-1269-\t\t\t struct scatterlist *out_sg,\n--\nnet/tls/tls_sw.c=1443=tls_decrypt_sw(struct sock *sk, struct tls_context *tls_ctx,\n--\nnet/tls/tls_sw.c-1450-\nnet/tls/tls_sw.c:1451:\terr = tls_decrypt_sg(sk, \u0026msg-\u003emsg_iter, NULL, darg);\nnet/tls/tls_sw.c-1452-\tif (err \u003c 0) {\n--\nnet/tls/tls_sw.c=1591=int decrypt_skb(struct sock *sk, struct scatterlist *sgout)\n--\nnet/tls/tls_sw.c-1594-\nnet/tls/tls_sw.c:1595:\treturn tls_decrypt_sg(sk, NULL, sgout, \u0026darg);\nnet/tls/tls_sw.c-1596-}\n"
} |
| 31/2 | 2026/10/21 21:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 45032 output: 29 thoughts: 608 Thoughts: **Focusing on the Right Targets** Okay, so I'm diving into this patch and trying to figure out the most effective FocusSymbols for fuzzing. `decrypt_skb` and `tls_decrypt_sw` are called by `tls_sw_recvmsg`, so they are interesting candidates, but I have to be careful not to pick ubiquitous functions. Let's see what's happening with `icmp_glue_bits` and the append data functions. I recall they can be called everywhere. `__ip_append_data` is static and called by `ip_append_data` and `ip_make_skb`. Same deal for IPv6. I've got to avoid those, as the guidance says to avoid hot-paths. Right, back to the key question: What are the functions *specifically* implementing the logic being added or altered? Let's go through the modified symbols: * `skb_segment`: Aha! This has new validation logic, error handling related to fragmentation (DEBUG_NET_WARN_ON_ONCE and frag_list checks) and checksum failures. This is a GSO segmentation entrypoint, so it's a good place to be! * `skb_checksum_full`: This is a *new* function. It's specifically added for checksum and error handling. That's a good target. * `skb_copy_and_csum_bits`: It's been modified with bounds checks, error codes, and even zeroing buffers on error! Another likely candidate. And more DEBUG_NET_WARN_ON_ONCE! * `skb_crc32c_full`: Another new function, dedicated to CRC32C with error handling. This has a high likelihood of being interesting. * `skb_crc32c_csum_help`: Modified to use the full version. * `skb_zerocopy`: Reordering checks and DEBUG_NET_WARN_ON_ONCE added. * `skb_try_coalesce`: Has a WARN_ON_ONCE assertion. * `skb_copy_and_csum_dev`: Bounds checks and error handling are added. Now, back to the TLS-related symbols. Is it `tls_sw_recvmsg` or `decrypt_skb`? Let me see... yes, `decrypt_skb` is exported in `net/tls/tls_sw.c`. *That's* likely a better target. I need to investigate `decrypt_skb`. |
| 32/2 | 2026/10/21 21:15 | tool | grepper |
0mArgs:{
"Expression": "decrypt_skb",
"PathPrefixes": [
"net/tls/"
]
}Results: {
"Output": "net/tls/tls.h=179=int tls_process_cmsg(struct sock *sk, struct msghdr *msg,\nnet/tls/tls.h-180-\t\t unsigned char *record_type);\nnet/tls/tls.h:181:int decrypt_skb(struct sock *sk, struct scatterlist *sgout);\nnet/tls/tls.h-182-\n--\nnet/tls/tls_device.c=886=tls_device_reencrypt(struct sock *sk, struct tls_context *tls_ctx)\n--\nnet/tls/tls_device.c-921-\t/* We are interested only in the decrypted data not the auth */\nnet/tls/tls_device.c:922:\terr = decrypt_skb(sk, sg);\nnet/tls/tls_device.c-923-\tif (err != -EBADMSG)\n--\nnet/tls/tls_sw.c=1567=static int tls_rx_one_record(struct sock *sk, struct msghdr *msg,\n--\nnet/tls/tls_sw.c-1590-\nnet/tls/tls_sw.c:1591:int decrypt_skb(struct sock *sk, struct scatterlist *sgout)\nnet/tls/tls_sw.c-1592-{\n"
} |
| 33/2 | 2026/10/21 21:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 46565 output: 31 thoughts: 44 Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective: **Diving into the TLS Receive Logic** Alright, the puzzle piece just clicked. `tls_sw_recvmsg`... that's the *recvmsg* handler specifically for TLS sockets, right? It's the one that takes in data over the encrypted connection. Now, I need to get into the nitty-gritty. Let's head straight to `net/tls/tls_sw.c` and take a good look at `tls_sw_recvmsg`. I want to understand exactly how the incoming TLS data is being handled at the socket layer. That's the key to figuring out the whole picture. |
| 34/2 | 2026/10/21 21:16 | tool | grepper |
0mArgs:{
"Expression": "tls_sw_recvmsg",
"PathPrefixes": [
"net/tls/"
]
}Results: {
"Output": "net/tls/tls.h=162=void tls_sw_free_ctx_rx(struct tls_context *tls_ctx);\nnet/tls/tls.h:163:int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,\nnet/tls/tls.h-164-\t\t int flags);\n--\nnet/tls/tls_main.c=996=static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],\n--\nnet/tls/tls_main.c-1009-\tprot[TLS_BASE][TLS_SW] = prot[TLS_BASE][TLS_BASE];\nnet/tls/tls_main.c:1010:\tprot[TLS_BASE][TLS_SW].recvmsg\t\t = tls_sw_recvmsg;\nnet/tls/tls_main.c-1011-\tprot[TLS_BASE][TLS_SW].sock_is_readable = tls_sw_sock_is_readable;\n--\nnet/tls/tls_main.c-1014-\tprot[TLS_SW][TLS_SW] = prot[TLS_SW][TLS_BASE];\nnet/tls/tls_main.c:1015:\tprot[TLS_SW][TLS_SW].recvmsg\t\t= tls_sw_recvmsg;\nnet/tls/tls_main.c-1016-\tprot[TLS_SW][TLS_SW].sock_is_readable = tls_sw_sock_is_readable;\n--\nnet/tls/tls_sw.c=1803=static void tls_rx_reader_unlock(struct sock *sk, struct tls_sw_context_rx *ctx)\n--\nnet/tls/tls_sw.c-1808-\nnet/tls/tls_sw.c:1809:int tls_sw_recvmsg(struct sock *sk,\nnet/tls/tls_sw.c-1810-\t\t struct msghdr *msg,\n"
} |
| 35/2 | 2026/10/21 21:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 47294 output: 37 thoughts: 908 Thoughts: **Analyzing Potential Focus Symbols in the Kernel for Fuzzing** Okay, so I'm looking at `tls_sw_recvmsg` and how it ties into `skb_nsg` via `tls_decrypt_sg` / `tls_decrypt_sw`. But something else just jumped out at me: `csum_partial_copy_to_xdr` in `net/sunrpc/socklib.c`. I need to figure out what changed there. Right, lines 142-149... they deleted that extra checksum block! That's a significant change. Also, `xdr_skb_read_bits` now has an `unlikely` check that uses `skb_copy_and_csum_bits` within an if statement. And I see that `csum_partial_copy_to_xdr` is exported, so it's a potential focus. Now, I need to evaluate if functions like `skb_checksum_full`, `skb_copy_and_csum_bits`, `skb_segment`, `skb_crc32c_full`, `skb_crc32c_csum_help`, `skb_zerocopy`, and `skb_try_coalesce` are good candidates for focus symbols. The key is to avoid "ubiquitous lifecycle hot-paths" that'll dilute the fuzzing effort. These aren't general memory allocators or deallocators or page-fault handlers or core synchronization primitives. Nor are they ubiquitous socket syscalls. * `skb_segment` is only called for GSO segmentation. * `skb_copy_and_csum_bits` is used in specific skb copy+checksum paths (e.g., fragmentation, icmp, vnet, sunrpc). * `skb_checksum_full` is for full checksum validation. * `skb_crc32c_full` / `skb_crc32c_csum_help` is used for CRC32c checksum calculation, like in SCTP. * `skb_zerocopy` is called in zerocopy networking paths (tuntap, xen, vhost). * `skb_try_coalesce` is called when coalescing skbs, like in the TCP receive path or GRO. These seem to be specific enough to be interesting, not overly general. I should check callers of `skb_zerocopy` across the entire kernel to get a clearer picture of its usage, and then I can refine my candidates. |
| 36/2 | 2026/10/21 21:16 | tool | grepper |
0mArgs:{
"Expression": "skb_zerocopy\\(",
"PathPrefixes": [
"net/",
"drivers/net/"
]
}Results: {
"Output": "net/core/skbuff.c=3980=EXPORT_SYMBOL(__skb_checksum_complete);\n--\nnet/core/skbuff.c-3982- /**\nnet/core/skbuff.c:3983: *\tskb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy()\nnet/core/skbuff.c-3984- *\t@from: source buffer\n--\nnet/core/skbuff.c-3986- *\tCalculates the amount of linear headroom needed in the 'to' skb passed\nnet/core/skbuff.c:3987: *\tinto skb_zerocopy().\nnet/core/skbuff.c-3988- */\n--\nnet/core/skbuff.c=4029=int\nnet/core/skbuff.c:4030:skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)\nnet/core/skbuff.c-4031-{\n--\nnet/netfilter/nfnetlink_queue.c=719=nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,\n--\nnet/netfilter/nfnetlink_queue.c-967-\nnet/netfilter/nfnetlink_queue.c:968:\t\tif (skb_zerocopy(skb, entskb, data_len, hlen))\nnet/netfilter/nfnetlink_queue.c-969-\t\t\tgoto nla_put_failure;\n--\nnet/openvswitch/datapath.c=452=static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,\n--\nnet/openvswitch/datapath.c-588-\t/* Only reserve room for attribute header, packet data is added\nnet/openvswitch/datapath.c:589:\t * in skb_zerocopy() */\nnet/openvswitch/datapath.c-590-\tif (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {\n--\nnet/openvswitch/datapath.c-595-\nnet/openvswitch/datapath.c:596:\terr = skb_zerocopy(user_skb, skb, skb_len, hlen);\nnet/openvswitch/datapath.c-597-\tif (err)\n--\nnet/xdp/xsk.c=988=static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,\n--\nnet/xdp/xsk.c-1032-\nnet/xdp/xsk.c:1033:static struct sk_buff *xsk_build_skb_zerocopy(struct xdp_sock *xs,\nnet/xdp/xsk.c-1034-\t\t\t\t\t struct xdp_desc *desc)\n--\nnet/xdp/xsk.c=1109=static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,\n--\nnet/xdp/xsk.c-1116-\tif (dev-\u003epriv_flags \u0026 IFF_TX_SKB_NO_LINEAR) {\nnet/xdp/xsk.c:1117:\t\tskb = xsk_build_skb_zerocopy(xs, desc);\nnet/xdp/xsk.c-1118-\t\tif (IS_ERR(skb)) {\n"
} |
| 37/2 | 2026/10/21 21:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 49700 output: 32 thoughts: 56 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **Investigating the Scope of `skb_zerocopy` & `skb_try_coalesce`** Right, `skb_zerocopy`... that function is pretty tightly coupled with a few specialized areas. I'm immediately thinking of `nfnetlink_queue`, the way it's used in `openvswitch`, and the XDP Socket (XSK) path. It's a key optimization, but it's not a general-purpose memory management trick. The specificity is important to keep in mind. But that makes me think, what about the other side of that coin: `skb_try_coalesce`? That sounds much more like a general optimization in SKB handling. Let's see how much that one's used, how many call sites are there, and in what context. A broader review might surface areas where improvements are possible or where we can ensure efficient usage. I need to understand its breadth of influence. |
| 38/2 | 2026/10/21 21:16 | tool | grepper |
0mArgs:{
"Expression": "skb_try_coalesce\\(",
"PathPrefixes": [
"net/"
]
}Results: {
"Output": "net/core/skbuff.c=6413=EXPORT_SYMBOL(kfree_skb_partial);\n--\nnet/core/skbuff.c-6421- */\nnet/core/skbuff.c:6422:bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,\nnet/core/skbuff.c-6423-\t\t bool *fragstolen, int *delta_truesize)\n--\nnet/ipv4/inet_fragment.c=615=void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,\n--\nnet/ipv4/inet_fragment.c-648-\nnet/ipv4/inet_fragment.c:649:\t\t\tif (try_coalesce \u0026\u0026 skb_try_coalesce(head, fp, \u0026stolen,\nnet/ipv4/inet_fragment.c-650-\t\t\t\t\t\t\t \u0026delta)) {\n--\nnet/ipv4/tcp_input.c=5250=static bool tcp_try_coalesce(struct sock *sk,\n--\nnet/ipv4/tcp_input.c-5265-\nnet/ipv4/tcp_input.c:5266:\tif (!skb_try_coalesce(to, from, fragstolen, \u0026delta))\nnet/ipv4/tcp_input.c-5267-\t\treturn false;\n--\nnet/ipv4/tcp_ipv4.c=1904=enum skb_drop_reason tcp_add_backlog(struct sock *sk, struct sk_buff *skb)\n--\nnet/ipv4/tcp_ipv4.c-1974-\nnet/ipv4/tcp_ipv4.c:1975:\tif (skb_try_coalesce(tail, skb, \u0026fragstolen, \u0026delta)) {\nnet/ipv4/tcp_ipv4.c-1976-\t\tTCP_SKB_CB(tail)-\u003eend_seq = TCP_SKB_CB(skb)-\u003eend_seq;\n--\nnet/mptcp/protocol.c=163=static bool __mptcp_try_coalesce(struct sock *sk, struct sk_buff *to,\n--\nnet/mptcp/protocol.c-171-\t ((to-\u003elen + from-\u003elen) \u003e (limit \u003e\u003e 3)) ||\nnet/mptcp/protocol.c:172:\t !skb_try_coalesce(to, from, fragstolen, delta))\nnet/mptcp/protocol.c-173-\t\treturn false;\n--\nnet/tipc/msg.c=124=int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)\n--\nnet/tipc/msg.c-163-\t*buf = NULL;\nnet/tipc/msg.c:164:\tif (skb_try_coalesce(head, frag, \u0026headstolen, \u0026delta)) {\nnet/tipc/msg.c-165-\t\tkfree_skb_partial(frag, headstolen);\n"
} |
| 39/2 | 2026/10/21 21:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 50803 output: 31 thoughts: 663 Thoughts: **My Analysis of `skb_try_coalesce` and Related Kernel Configurations** Okay, so I'm digging into `skb_try_coalesce`. I know it's crucial during fragment reassembly, and it's also called within TCP input, MPTCP, and TIPC. My job is to see how this function and related ones are configured to be available in the kernel. Let's start with a systematic look at the relevant kernel configurations. First, `CONFIG_DEBUG_NET` is important because it enables `DEBUG_NET_WARN_ON_ONCE`. This macro is sprinkled throughout several key functions I need to consider, including `bounce_skb`, `skb_checksum_full`, `skb_copy_and_csum_bits`, `skb_crc32c_full`, `skb_zerocopy`, `skb_segment`, and `__skb_nsg`. I'll keep that in mind. Then, the obvious core networking configs: `CONFIG_NET`, `CONFIG_INET` (IPv4, checksumming, TCP), `CONFIG_IPV6` (IPv6, ICMP). These are foundational for the code paths in question. And `CONFIG_TLS` is critical, impacting `net/tls/tls_sw.c`. For checksums I will make sure that `CONFIG_NET_CRC32C` is included for `skb_crc32c_full`, and `skb_crc32c`. I will also remember that `CONFIG_IP_SCTP` selects `NET_CRC32C`. So that would either be a good configuration to add or to include `NET_CRC32C`. I should also include `CONFIG_SUNRPC` for `net/sunrpc/socklib.c`. I'm thinking, are there other config options I should be aware of? Let me consider `KUNIT` – I see it's used for unit tests in `net/core/net_test.c`, but that isn't directly reachable through syscalls. So, probably not important for fuzzing. Then I thought about `XEN_NETDEV_FRONTEND`. That's Xen-specific, so it's worth mentioning but probably omit. The core networking changes make fuzzing definitely worthwhile. Now, let's nail down a more specific focus. These are the *specific* symbols I think are most relevant for fuzzing: - `skb_segment` - `skb_checksum_full` - `skb_copy_and_csum_bits` - `skb_crc32c_full` - `skb_crc32c_csum_help` - `skb_zerocopy` - `skb_try_coalesce` - `skb_copy_and_csum_dev` - `__skb_checksum_complete` - `__skb_checksum_complete_head` - `tls_sw_recvmsg` - `csum_partial_copy_to_xdr` Wait a minute, is there a particularly ubiquitous one in there? Hmm... I should check where `__skb_checksum_complete` is called, because if it's called on almost every packet receive, it's going to be a key point to focus on for fuzzing. |
| 40/2 | 2026/10/21 21:16 | tool | grepper |
0mArgs:{
"Expression": "__skb_checksum_complete\\(",
"PathPrefixes": [
"net/"
]
}Results: {
"Output": "net/core/datagram.c=890=int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,\n--\nnet/core/datagram.c-899-\tif (msg_data_left(msg) \u003c chunk) {\nnet/core/datagram.c:900:\t\tif (__skb_checksum_complete(skb))\nnet/core/datagram.c-901-\t\t\treturn -EINVAL;\n--\nnet/core/gro.c=794=__sum16 __skb_gro_checksum_complete(struct sk_buff *skb)\n--\nnet/core/gro.c-802-\tsum = csum_fold(csum_add(NAPI_GRO_CB(skb)-\u003ecsum, wsum));\nnet/core/gro.c:803:\t/* See comments in __skb_checksum_complete(). */\nnet/core/gro.c-804-\tif (likely(!sum)) {\n--\nnet/core/skbuff.c=3908=__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)\n--\nnet/core/skbuff.c-3920-\tsum = csum_fold(csum);\nnet/core/skbuff.c:3921:\t/* See comments in __skb_checksum_complete(). */\nnet/core/skbuff.c-3922-\tif (likely(!sum)) {\n--\nnet/core/skbuff.c=3931=EXPORT_SYMBOL(__skb_checksum_complete_head);\n--\nnet/core/skbuff.c-3941- */\nnet/core/skbuff.c:3942:__sum16 __skb_checksum_complete(struct sk_buff *skb)\nnet/core/skbuff.c-3943-{\n--\nnet/ipv4/udp.c=1584=static void udp_skb_csum_unnecessary_set(struct sk_buff *skb)\n--\nnet/ipv4/udp.c-1586-\t/* We come here after udp_lib_checksum_complete() returned 0.\nnet/ipv4/udp.c:1587:\t * This means that __skb_checksum_complete() might have\nnet/ipv4/udp.c-1588-\t * set skb-\u003ecsum_valid to 1.\n--\nnet/ipv6/raw.c=435=static int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,\n--\nnet/ipv6/raw.c-465-\t} else if (msg-\u003emsg_flags\u0026MSG_TRUNC) {\nnet/ipv6/raw.c:466:\t\tif (__skb_checksum_complete(skb))\nnet/ipv6/raw.c-467-\t\t\tgoto csum_copy_err;\n--\nnet/netfilter/utils.c=10=__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,\n--\nnet/netfilter/utils.c-35-\t\t\t\t\t\t protocol, 0);\nnet/netfilter/utils.c:36:\t\tcsum = __skb_checksum_complete(skb);\nnet/netfilter/utils.c-37-\t}\n--\nnet/netfilter/utils.c=64=__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,\n--\nnet/netfilter/utils.c-90-\t\t\t\t\t\t\t\t dataoff, 0))));\nnet/netfilter/utils.c:91:\t\tcsum = __skb_checksum_complete(skb);\nnet/netfilter/utils.c-92-\t}\n"
} |
| 41/2 | 2026/10/21 21:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 53175 output: 39 thoughts: 524 Thoughts: **Analyzing Packet Processing and Checksum Operations** Okay, so I'm looking at this code and immediately I see something interesting: `__skb_checksum_complete` isn't called on every packet. That makes sense, because NICs often offload checksum calculations or use `CHECKSUM_UNNECESSARY`, but it's still called for software verification. The puzzling thing is that `skb_checksum_full` *is* called by it regardless. I need to understand that relationship better. Let's dissect the new functions and refactored ones. Here's what's standing out: * `skb_segment`: This is about GSO segmentation. I'm seeing new checks specifically for nested fragment lists and handling copy failures, which is important. * `skb_checksum_full`: This is the new core function, so I need to check out what the checksum process is doing. * `skb_copy_and_csum_bits`: Refactoring here, and I spot new error returns and bounds checks, which I approve of. * `skb_crc32c_full`: Another new core function, so I'm going to have to dig into its details. * `skb_crc32c_csum_help`: It appears to use `skb_crc32c_full`, that makes sense. * `skb_zerocopy`: Reordered checks and a defensive bounds check. That's good defensive programming. * `skb_try_coalesce`: An assertion update – I'll need to see how the delta is being handled. * `skb_copy_and_csum_dev`: Bounds checks and failure handling, just what I want to see. * `csum_partial_copy_to_xdr`: Checksum calculation refactored, which I should give a good look. * `tls_sw_recvmsg`: I'm noticing this hits `__skb_nsg`, and a `BUG_ON` has been replaced with `DEBUG_NET_WARN_ON_ONCE`. Now, before I go any further, I need to make sure these symbols are accessible. I need to confirm if they're all non-static, or if any are static inline. Let me check the export symbols in `skbuff.c`: * `skb_segment` is `EXPORT_SYMBOL_GPL`. Okay. * `skb_checksum_full` is `EXPORT_SYMBOL`. * `skb_copy_and_csum_bits` is `EXPORT_SYMBOL`. * `skb_crc32c_full` is `EXPORT_SYMBOL`. * `skb_crc32c_csum_help` is `EXPORT_SYMBOL`. * `skb_zerocopy` is `EXPORT_SYMBOL_GPL`. Wait, I want to verify that `skb_zerocopy` export statement myself. |
| 42/2 | 2026/10/21 21:16 | tool | grepper |
0mArgs:{
"Expression": "EXPORT_SYMBOL.*skb_zerocopy",
"PathPrefixes": [
"net/core/skbuff.c"
]
}Results: {
"Output": "net/core/skbuff.c=1915=int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,\n--\nnet/core/skbuff.c-1952-}\nnet/core/skbuff.c:1953:EXPORT_SYMBOL_GPL(skb_zerocopy_iter_stream);\nnet/core/skbuff.c-1954-\n--\nnet/core/skbuff.c=3990=skb_zerocopy_headlen(const struct sk_buff *from)\n--\nnet/core/skbuff.c-4006-}\nnet/core/skbuff.c:4007:EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);\nnet/core/skbuff.c-4008-\n--\nnet/core/skbuff.c=4030=skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)\n--\nnet/core/skbuff.c-4101-}\nnet/core/skbuff.c:4102:EXPORT_SYMBOL_GPL(skb_zerocopy);\nnet/core/skbuff.c-4103-\n"
} |
| 43/2 | 2026/10/21 21:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 54718 output: 41 thoughts: 30 Thoughts: Here's my take on the thought process, from an expert's perspective: **Kernel Memory Management Deep Dive** Okay, so `skb_zerocopy` is definitely exposed. That's good to know, and it triggers something in my brain… wait a minute. Where does `skb_try_coalesce` stand? Is *that* also being exported? I need to quickly refresh my memory on that function. It's crucial for understanding how the kernel handles packet memory optimization, and whether or not it's available for user space access. I need to clarify that function and determine how it interacts with `skb_zerocopy`. It's important to grasp the whole picture. I really need to dig into the kernel source and make sure I fully understand it. |
| 44/2 | 2026/10/21 21:16 | tool | grepper |
0mArgs:{
"Expression": "EXPORT_SYMBOL.*skb_try_coalesce",
"PathPrefixes": [
"net/core/skbuff.c"
]
}Results: {
"Output": "net/core/skbuff.c=6422=bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,\n--\nnet/core/skbuff.c-6524-}\nnet/core/skbuff.c:6525:EXPORT_SYMBOL(skb_try_coalesce);\nnet/core/skbuff.c-6526-\n"
} |
| 45/2 | 2026/10/21 21:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 55068 output: 44 thoughts: 36 Thoughts: Here's the summary, assuming I'm an expert in network kernel programming: **Kernel SKB Coalescing and Checksumming: An Exporting Investigation** Okay, so I just noticed that `skb_try_coalesce` is actually exported. That's a good tidbit to have, and it opens up some possibilities. Now, I need to see what else might be out there. The real question is whether `skb_copy_and_csum_dev` is also exported, because that's a far more interesting function. Given the kernel's architecture, and the potential performance advantages I could gain, access to that would be golden. I'll need to check the symbol table directly and see what's what. |
| 46/2 | 2026/10/21 21:16 | tool | grepper |
0mArgs:{
"Expression": "EXPORT_SYMBOL.*skb_copy_and_csum_dev",
"PathPrefixes": [
"net/core/skbuff.c"
]
}Results: {
"Output": "net/core/skbuff.c=4104=void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)\n--\nnet/core/skbuff.c-4147-}\nnet/core/skbuff.c:4148:EXPORT_SYMBOL(skb_copy_and_csum_dev);\nnet/core/skbuff.c-4149-\n"
} |
| 47/2 | 2026/10/21 21:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 55425 output: 43 thoughts: 113 Thoughts: **Kernel IP Fragmentation Investigation** Okay, so I'm looking at IP fragmentation routines and I've just noticed something interesting: `skb_copy_and_csum_dev` is exported! That's a point of potential external use. Now, what about some of the internal helpers used *within* the core fragmentation logic? Things like `icmp_glue_bits` and `icmpv6_getfrag`? I recall they're marked as `static` and used specifically as callbacks within the `ip_append_data` and `ip6_append_data` functions, which is pretty standard practice for keeping things encapsulated. I need to be absolutely sure though. Right, what about the preprocessor macro, `__ip_append_data`? It appears `static` as well and is called by `ip_append_data`, so that's not a concern. Now, the crucial piece is whether the wrapping functions, `ip_append_data` and `ip6_append_data`, themselves are actually exported. That's the real test of whether someone can directly manipulate the data appended to packets. Time to check! |
| 48/2 | 2026/10/21 21:16 | tool | grepper |
0mError:no matches Args: {
"Expression": "EXPORT_SYMBOL.*ip_append_data",
"PathPrefixes": [
"net/ipv4/",
"net/ipv6/"
]
}Results: {
"error": "no matches"
} |
| 49/2 | 2026/10/21 21:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 55838 output: 36 thoughts: 24 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Diving into `ip_append_data`** Alright, let's get down to brass tacks. I need to refresh my memory on how this all works, so first things first, I'm heading directly into `net/ipv4/ip_output.c`. Specifically, I'm focusing in on `ip_append_data`. I know this is where the core logic resides for appending data to an IP datagram before it hits the network layer, and I'm guessing I need to clarify my understanding of its role. I need to grasp how the function handles things like fragmentation, checksum calculation, and any potential interaction with other subsystems like connection tracking or NAT. I know there are a lot of nuances in this area, especially regarding the interaction between the various layers in the stack, so I will need to clarify the specifics of this function. |
| 50/2 | 2026/10/21 21:16 | tool | grepper |
0mArgs:{
"Expression": "ip_append_data",
"PathPrefixes": [
"net/ipv4/ip_output.c"
]
}Results: {
"Output": "net/ipv4/ip_output.c=955=EXPORT_SYMBOL(ip_generic_getfrag);\nnet/ipv4/ip_output.c-956-\nnet/ipv4/ip_output.c:957:static int __ip_append_data(struct sock *sk,\nnet/ipv4/ip_output.c-958-\t\t\t struct flowi4 *fl4,\n--\nnet/ipv4/ip_output.c=1303=static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,\n--\nnet/ipv4/ip_output.c-1358-/*\nnet/ipv4/ip_output.c:1359: *\tip_append_data() can make one large IP datagram from many pieces of\nnet/ipv4/ip_output.c-1360- *\tdata. Each piece will be held on the socket until\n--\nnet/ipv4/ip_output.c-1368- */\nnet/ipv4/ip_output.c:1369:int ip_append_data(struct sock *sk, struct flowi4 *fl4,\nnet/ipv4/ip_output.c-1370-\t\t int getfrag(void *from, char *to, int offset, int len,\n--\nnet/ipv4/ip_output.c-1389-\nnet/ipv4/ip_output.c:1390:\treturn __ip_append_data(sk, fl4, \u0026sk-\u003esk_write_queue, \u0026inet-\u003ecork.base,\nnet/ipv4/ip_output.c-1391-\t\t\t\tsk_page_frag(sk), getfrag,\n--\nnet/ipv4/ip_output.c=1408=struct sk_buff *__ip_make_skb(struct sock *sk,\n--\nnet/ipv4/ip_output.c-1511-\nnet/ipv4/ip_output.c:1512:\t\t/* For such sockets, transhdrlen is zero when do ip_append_data(),\nnet/ipv4/ip_output.c-1513-\t\t * so icmphdr does not in skb linear region and can not get icmp_type\n--\nnet/ipv4/ip_output.c=1576=struct sk_buff *ip_make_skb(struct sock *sk,\n--\nnet/ipv4/ip_output.c-1598-\nnet/ipv4/ip_output.c:1599:\terr = __ip_append_data(sk, fl4, \u0026queue, cork,\nnet/ipv4/ip_output.c-1600-\t\t\t \u0026current-\u003etask_frag, getfrag,\n--\nnet/ipv4/ip_output.c=1627=void ip_send_unicast_reply(struct sock *sk, const struct sock *orig_sk,\n--\nnet/ipv4/ip_output.c-1680-\tipc.sockc.mark = fl4.flowi4_mark;\nnet/ipv4/ip_output.c:1681:\terr = ip_append_data(sk, \u0026fl4, ip_reply_glue_bits, arg-\u003eiov-\u003eiov_base,\nnet/ipv4/ip_output.c-1682-\t\t\t len, 0, \u0026ipc, \u0026rt, MSG_DONTWAIT);\n"
} |
| 51/2 | 2026/10/21 21:16 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 56937 output: 321 thoughts: 802 Thoughts: **Analysis of Network Core Patch for Fuzzing** Okay, so I've been taking a look at this patch, and here's the breakdown of my thinking. First, I noticed that the changes are centered around the core networking functions, specifically those related to the SKB (Socket Buffer) within `net/core/skbuff.c` and also `net/core/dev.c`. I immediately spot functions like `skb_segment`, `skb_checksum_full`, `skb_copy_and_csum_bits`, `skb_zerocopy`, and `skb_try_coalesce` as primary targets because these are where the modifications reside. We also have additions like checksum helper functions (`skb_crc32c_full`). This patch seems to touch checksum handling across IPv4, IPv6, and SunRPC, which is significant. I also see that there are new defensive checks and `DEBUG_NET_WARN_ON_ONCE` assertions included. I need to make sure I can exercise those code paths. I need to confirm the configuration requirements to ensure a clean build and effective fuzzing. Let's make sure `DEBUG_NET` is available. Yes, that's in `net/Kconfig.debug`. I see it depends on `DEBUG_KERNEL && NET`, which is standard for debug builds. I also see dependencies like `NET_CRC32C`, `IP_SCTP`, `TLS`, `INET`, `IPV6`, and `SUNRPC` which seem highly relevant. I need to enable those. I glanced at some other configs like `KUNIT`, `SUNVNET`, and `XEN_NETDEV_FRONTEND`, but they don't seem applicable here. They are either unrelated to our fuzzing goals or target different architectures or environments. So, to summarize what I'm confident in: * **WorthFuzzing:** True, because these are core networking functions, and the patch introduces modifications to checksum calculations and error handling, making it a good candidate. * **Reasoning:** The patch modifies core networking functions in `net/core/skbuff.c` and `net/core/dev.c` (including `skb_segment`, `skb_copy_and_csum_bits`, `skb_zerocopy`, `skb_try_coalesce`), adds new checksum helper functions (`skb_checksum_full`, `skb_crc32c_full`), updates checksum error handling across IPv4, IPv6, SunRPC, and adds defensive checks and `DEBUG_NET_WARN_ON_ONCE` assertions. * **EnableConfigs:** I need to enable the following configs, *without* the `CONFIG_` prefix: `DEBUG_NET`, `INET`, `IPV6`, `TLS`, `NET_CRC32C`, `IP_SCTP`, `SUNRPC`. * **FocusSymbols:** I want to focus my fuzzing efforts on these functions: `skb_segment`, `skb_checksum_full`, `skb_copy_and_csum_bits`, `skb_crc32c_full`, `skb_crc32c_csum_help`, `skb_zerocopy`, `skb_try_coalesce`, `skb_copy_and_csum_dev`, `tls_sw_recvmsg`, `csum_partial_copy_to_xdr`. Now, I am ready to call `set-results` using this information. |
| 52/2 | 2026/10/21 21:17 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"DEBUG_NET",
"INET",
"IPV6",
"TLS",
"NET_CRC32C",
"IP_SCTP",
"SUNRPC"
],
"FocusSymbols": [
"skb_segment",
"skb_checksum_full",
"skb_copy_and_csum_bits",
"skb_crc32c_full",
"skb_crc32c_csum_help",
"skb_zerocopy",
"skb_try_coalesce",
"skb_copy_and_csum_dev",
"tls_sw_recvmsg",
"csum_partial_copy_to_xdr"
],
"Reasoning": "The patch series refactors core socket buffer (skbuff) checksumming and copying routines in net/core/skbuff.c and net/core/dev.c. It introduces skb_checksum_full() and skb_crc32c_full() to propagate errors, refactors skb_copy_and_csum_bits() and its call sites across core networking (IPv4, IPv6, SunRPC), updates GSO segmentation validation in skb_segment(), and adds multiple runtime assertions via DEBUG_NET_WARN_ON_ONCE() and WARN_ON_ONCE(). These reachable paths in core networking warrant fuzzing.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"DEBUG_NET",
"INET",
"IPV6",
"TLS",
"NET_CRC32C",
"IP_SCTP",
"SUNRPC"
],
"FocusSymbols": [
"skb_segment",
"skb_checksum_full",
"skb_copy_and_csum_bits",
"skb_crc32c_full",
"skb_crc32c_csum_help",
"skb_zerocopy",
"skb_try_coalesce",
"skb_copy_and_csum_dev",
"tls_sw_recvmsg",
"csum_partial_copy_to_xdr"
],
"Reasoning": "The patch series refactors core socket buffer (skbuff) checksumming and copying routines in net/core/skbuff.c and net/core/dev.c. It introduces skb_checksum_full() and skb_crc32c_full() to propagate errors, refactors skb_copy_and_csum_bits() and its call sites across core networking (IPv4, IPv6, SunRPC), updates GSO segmentation validation in skb_segment(), and adds multiple runtime assertions via DEBUG_NET_WARN_ON_ONCE() and WARN_ON_ONCE(). These reachable paths in core networking warrant fuzzing.",
"WorthFuzzing": true
} |
| 53/1 | 2026/10/21 21:17 | action | If |
3mArgs:{
"WorthFuzzing": true
}Results: null |
| 54/2 | 2026/10/21 21:17 | agent | kmsan-evaluator |
3mModel:core Args: null Results: {
"KMSANReasoning": "The patch series refactors SKB checksum and CRC helpers (`skb_checksum_full`, `skb_copy_and_csum_bits`, `skb_crc32c_full`) to propagate error codes rather than silently returning 0 on unreadable frags or buffer overruns. It also replaces several `BUG_ON()` calls with error handling and adds checks against invalid nested frag_lists in `skb_segment()`.\n\nFrom a memory sanitization perspective:\n1. All out-pointer arguments (`csump`, `crcp`) are either initialized before calling or guarded by return value checks ensuring they are only read on success.\n2. `skb_copy_and_csum_bits()` explicitly zeroes out destination buffers with `memset()` on error paths to prevent callers from accessing stale/uninitialized memory.\n3. No kernel-to-userspace data leaks, uninitialized struct fields, or branching on uninitialized data are introduced.\n4. The bugs being addressed (buffer bounds, invalid frag geometry, BUG_ON conditions) are covered by KASAN and standard kernel debug assertions.\n\nTherefore, 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 9fec1e72dd0e9fa7934a768897145f6e40a2e828
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Oct 21 21:13:50 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/sun/sunvnet_common.c b/drivers/net/ethernet/sun/sunvnet_common.c
index 5cca958690521..4f229fcecc32f 100644
--- a/drivers/net/ethernet/sun/sunvnet_common.c
+++ b/drivers/net/ethernet/sun/sunvnet_common.c
@@ -1167,9 +1167,13 @@ static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies)
/* copy the rest, with csum calculation */
*(__sum16 *)(skb->data + offset) = 0;
- csum = skb_copy_and_csum_bits(skb, start,
- nskb->data + start,
- skb->len - start);
+ if (skb_copy_and_csum_bits(skb, start,
+ nskb->data + start,
+ skb->len - start, &csum)) {
+ dev_kfree_skb(nskb);
+ dev_kfree_skb(skb);
+ return NULL;
+ }
/* add in the header checksums */
if (skb->protocol == htons(ETH_P_IP)) {
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index fdcb91042f290..17811d81937c6 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -695,7 +695,12 @@ static struct sk_buff *bounce_skb(const struct sk_buff *skb)
/* Set the tail pointer and length */
skb_put(n, skb->len);
- BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len));
+ if (unlikely(skb_copy_bits(skb, -headerlen, n->head,
+ headerlen + skb->len))) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ kfree_skb(n);
+ return NULL;
+ }
skb_copy_header(n, skb);
return n;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index af1cbc2799b77..327a01a5d6d0b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -4277,8 +4277,10 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
-__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
- int len);
+int __must_check skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
+ u8 *to, int len, __wsum *csum);
+int __must_check skb_checksum_full(const struct sk_buff *skb, int offset,
+ int len, __wsum *csump);
int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int len,
unsigned int flags);
@@ -4327,6 +4329,8 @@ static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)
__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
__wsum csum);
+int __must_check skb_crc32c_full(const struct sk_buff *skb, int offset,
+ int len, u32 *crcp);
u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc);
static inline void * __must_check
diff --git a/net/core/dev.c b/net/core/dev.c
index 8eb9bf1ff9eb6..1d34fa4544a25 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3738,8 +3738,11 @@ int skb_crc32c_csum_help(struct sk_buff *skb)
if (ret)
goto out;
- crc = ~skb_crc32c(skb, start, skb->len - start, ~0);
- *(__le32 *)(skb->data + offset) = cpu_to_le32(crc);
+ crc = ~0;
+ ret = skb_crc32c_full(skb, start, skb->len - start, &crc);
+ if (ret)
+ goto out;
+ *(__le32 *)(skb->data + offset) = cpu_to_le32(~crc);
skb_reset_csum_not_inet(skb);
out:
return ret;
diff --git a/net/core/filter.c b/net/core/filter.c
index 3ee1a093337e3..f5bce0dc43fe0 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3696,9 +3696,9 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
shinfo->gso_segs = 0;
/* Due to header growth, MSS needs to be downgraded.
- * There is a BUG_ON() when segmenting the frag_list with
- * head_frag true, so linearize the skb after downgrading
- * the MSS.
+ * Segmenting a frag_list with head_frag true at the new MSS
+ * fails and the packet gets dropped, so linearize the skb
+ * after downgrading the MSS.
*/
if (!(flags & BPF_F_ADJ_ROOM_FIXED_GSO)) {
skb_decrease_gso_size(shinfo, len_diff);
diff --git a/net/core/net_test.c b/net/core/net_test.c
index bc2ef7612e7df..222d24793591c 100644
--- a/net/core/net_test.c
+++ b/net/core/net_test.c
@@ -39,6 +39,8 @@ enum gso_test_nr {
GSO_TEST_RESEGMENT_MULTI,
GSO_TEST_RESEGMENT_TAIL,
GSO_TEST_RESEGMENT_ONE_MSS,
+ GSO_TEST_FRAG_LIST_NON_UNIFORM_SG,
+ GSO_TEST_FRAG_LIST_NESTED,
};
struct gso_test_case {
@@ -57,6 +59,9 @@ struct gso_test_case {
unsigned int nr_segs;
const unsigned int *segs;
const unsigned int *gso_segs;
+
+ /* skb_segment() is expected to fail with this error */
+ int err;
};
static struct gso_test_case cases[] = {
@@ -204,6 +209,28 @@ static struct gso_test_case cases[] = {
},
.gso_segs = (const unsigned int[]) { 0, 0, 0, 0 },
},
+ {
+ /* frag_list members that don't end on gso_size boundaries
+ * can't be segmented with SG
+ */
+ .id = GSO_TEST_FRAG_LIST_NON_UNIFORM_SG,
+ .name = "frag_list_non_uniform_sg",
+ .linear_len = GSO_TEST_SIZE,
+ .nr_frag_skbs = 4,
+ .frag_skbs = (const unsigned int[]) { GSO_TEST_SIZE, 1, GSO_TEST_SIZE, 2 },
+ .err = -EINVAL,
+ },
+ {
+ /* the second frag_list member hangs off the first one's
+ * frag_list instead of off the head's
+ */
+ .id = GSO_TEST_FRAG_LIST_NESTED,
+ .name = "frag_list_nested",
+ .linear_len = GSO_TEST_SIZE,
+ .nr_frag_skbs = 2,
+ .frag_skbs = (const unsigned int[]) { GSO_TEST_SIZE, GSO_TEST_SIZE },
+ .err = -EINVAL,
+ },
};
static void gso_test_case_to_desc(struct gso_test_case *t, char *desc)
@@ -283,19 +310,41 @@ static void gso_test_func(struct kunit *test)
if (tcase->id == GSO_TEST_GSO_BY_FRAGS)
skb_shinfo(skb)->gso_size = GSO_BY_FRAGS;
+
+ if (tcase->id == GSO_TEST_FRAG_LIST_NESTED) {
+ struct sk_buff *first = skb_shinfo(skb)->frag_list;
+
+ skb_shinfo(first)->frag_list = first->next;
+ first->next = NULL;
+ first->len += tcase->frag_skbs[1];
+ first->data_len += tcase->frag_skbs[1];
+ }
}
features = NETIF_F_SG | NETIF_F_HW_CSUM;
if (tcase->id == GSO_TEST_GSO_PARTIAL)
features |= NETIF_F_GSO_PARTIAL;
- /* TODO: this should also work with SG,
- * rather than hit BUG_ON(i >= nfrags)
+ /* TODO: this should also work with SG, rather than fail the
+ * i >= nfrags check in skb_segment()
*/
if (tcase->id == GSO_TEST_FRAG_LIST_NON_UNIFORM)
features &= ~NETIF_F_SG;
SKB_GSO_CB(skb)->max_segs = tcase->max_segs;
+
+ if (tcase->err) {
+ /* the suppression block doesn't run if it can't be set up */
+ segs = NULL;
+ kunit_warning_suppress(test) {
+ segs = skb_segment(skb, features);
+ }
+ KUNIT_EXPECT_EQ(test, PTR_ERR_OR_ZERO(segs), tcase->err);
+ if (!IS_ERR_OR_NULL(segs))
+ kfree_skb_list(segs);
+ goto free_gso_skb;
+ }
+
segs = skb_segment(skb, features);
if (IS_ERR(segs)) {
KUNIT_FAIL(test, "segs error %pe", segs);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 93c2f440b9ece..e0c8f2f6bfac1 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2829,9 +2829,13 @@ static int pskb_trim_rcsum_complete(struct sk_buff *skb, unsigned int len)
int delta = skb->len - len;
if (skb_frags_readable(skb)) {
- skb->csum = csum_block_sub(skb->csum,
- skb_checksum(skb, len, delta, 0),
- len);
+ __wsum csum = 0;
+ int err;
+
+ err = skb_checksum_full(skb, len, delta, &csum);
+ if (err)
+ return err;
+ skb->csum = csum_block_sub(skb->csum, csum, len);
return 0;
}
@@ -3545,12 +3549,31 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
EXPORT_SYMBOL(skb_store_bits);
/* Checksum skb data. */
-__wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
+/**
+ * skb_checksum_full - checksum a range of an skb
+ * @skb: buffer to checksum
+ * @offset: offset in @skb to start at
+ * @len: number of bytes to checksum
+ * @csump: the sum to add to; on success the range's sum is added to it
+ *
+ * Return: 0 on success, -EINVAL if @len is negative, or -EFAULT if @skb
+ * has unreadable frags in the range or runs out before @len does. On
+ * failure *@csump is not changed.
+ */
+int skb_checksum_full(const struct sk_buff *skb, int offset, int len,
+ __wsum *csump)
{
int start = skb_headlen(skb);
int i, copy = start - offset;
struct sk_buff *frag_iter;
+ __wsum csum = *csump;
int pos = 0;
+ int err;
+
+ if (unlikely(len < 0)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
/* Checksum header. */
if (copy > 0) {
@@ -3558,13 +3581,13 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
copy = len;
csum = csum_partial(skb->data + offset, copy, csum);
if ((len -= copy) == 0)
- return csum;
+ goto out;
offset += copy;
pos = copy;
}
- if (WARN_ON_ONCE(!skb_frags_readable(skb)))
- return 0;
+ if (!skb_frags_readable(skb))
+ return -EFAULT;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
@@ -3593,7 +3616,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
}
if (!(len -= copy))
- return csum;
+ goto out;
offset += copy;
}
start = end;
@@ -3606,14 +3629,17 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
end = start + frag_iter->len;
if ((copy = end - offset) > 0) {
- __wsum csum2;
+ __wsum csum2 = 0;
+
if (copy > len)
copy = len;
- csum2 = skb_checksum(frag_iter, offset - start, copy,
- 0);
+ err = skb_checksum_full(frag_iter, offset - start, copy,
+ &csum2);
+ if (err)
+ return err;
csum = csum_block_add(csum, csum2, pos);
if ((len -= copy) == 0)
- return csum;
+ goto out;
offset += copy;
pos += copy;
}
@@ -3621,23 +3647,59 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
}
if (unlikely(len)) {
DEBUG_NET_WARN_ON_ONCE(1);
- return 0;
+ return -EFAULT;
}
+out:
+ *csump = csum;
+ return 0;
+}
+EXPORT_SYMBOL(skb_checksum_full);
+/* skb_checksum() has no way to report failure, so it returns 0, which is a
+ * valid checksum. Use skb_checksum_full() in new code.
+ */
+__wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
+{
+ if (unlikely(skb_checksum_full(skb, offset, len, &csum))) {
+ WARN_ON_ONCE(!skb_frags_readable(skb));
+ return 0;
+ }
return csum;
}
EXPORT_SYMBOL(skb_checksum);
/* Both of above in one bottle. */
-__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
- u8 *to, int len)
+/**
+ * skb_copy_and_csum_bits - copy data out of an skb and checksum it
+ * @skb: source buffer
+ * @offset: offset in @skb to start copying from
+ * @to: destination buffer
+ * @len: number of bytes to copy
+ * @csump: where to store the checksum of the copied bytes
+ *
+ * Return: 0 on success, -EINVAL if @len is negative, or -EFAULT if @skb
+ * has unreadable frags or runs out before @len does. On failure *@csump
+ * is not set, and on -EFAULT the part of @to that couldn't be filled is
+ * zeroed.
+ */
+int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
+ u8 *to, int len, __wsum *csump)
{
int start = skb_headlen(skb);
int i, copy = start - offset;
struct sk_buff *frag_iter;
int pos = 0;
__wsum csum = 0;
+ int err;
+
+ /* Everything below clamps copies to @len, so a negative one would
+ * turn into a huge copy.
+ */
+ if (unlikely(len < 0)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
/* Copy header. */
if (copy > 0) {
@@ -3646,7 +3708,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
csum = csum_partial_copy_nocheck(skb->data + offset, to,
copy);
if ((len -= copy) == 0)
- return csum;
+ goto out;
offset += copy;
to += copy;
pos = copy;
@@ -3656,7 +3718,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
/* Don't hand the caller a buffer with stale bytes in it. */
if (len > 0)
memset(to, 0, len);
- return 0;
+ return -EFAULT;
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
@@ -3688,7 +3750,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
}
if (!(len -= copy))
- return csum;
+ goto out;
offset += copy;
to += copy;
}
@@ -3705,12 +3767,16 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- csum2 = skb_copy_and_csum_bits(frag_iter,
- offset - start,
- to, copy);
+ err = skb_copy_and_csum_bits(frag_iter, offset - start,
+ to, copy, &csum2);
+ if (err) {
+ /* The child zeroed its part; zero the rest. */
+ memset(to + copy, 0, len - copy);
+ return err;
+ }
csum = csum_block_add(csum, csum2, pos);
if ((len -= copy) == 0)
- return csum;
+ goto out;
offset += copy;
to += copy;
pos += copy;
@@ -3720,32 +3786,51 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
if (unlikely(len)) {
DEBUG_NET_WARN_ON_ONCE(1);
/* Don't hand the caller a buffer with stale bytes in it. */
- if (len > 0)
- memset(to, 0, len);
- return 0;
+ memset(to, 0, len);
+ return -EFAULT;
}
- return csum;
+out:
+ *csump = csum;
+ return 0;
}
EXPORT_SYMBOL(skb_copy_and_csum_bits);
#ifdef CONFIG_NET_CRC32C
-u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
+/**
+ * skb_crc32c_full - CRC32C a range of an skb
+ * @skb: buffer to read
+ * @offset: offset in @skb to start at
+ * @len: number of bytes to include
+ * @crcp: the CRC to continue from; on success, updated with the range
+ *
+ * Return: 0 on success, -EINVAL if @len is negative, or -EFAULT if @skb
+ * has unreadable frags in the range or runs out before @len does. On
+ * failure *@crcp is not changed.
+ */
+int skb_crc32c_full(const struct sk_buff *skb, int offset, int len, u32 *crcp)
{
int start = skb_headlen(skb);
int i, copy = start - offset;
struct sk_buff *frag_iter;
+ u32 crc = *crcp;
+ int err;
+
+ if (unlikely(len < 0)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
if (copy > 0) {
copy = min(copy, len);
crc = crc32c(crc, skb->data + offset, copy);
len -= copy;
if (len == 0)
- return crc;
+ goto out;
offset += copy;
}
- if (WARN_ON_ONCE(!skb_frags_readable(skb)))
- return 0;
+ if (!skb_frags_readable(skb))
+ return -EFAULT;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
@@ -3770,7 +3855,7 @@ u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
}
len -= copy;
if (len == 0)
- return crc;
+ goto out;
offset += copy;
}
start = end;
@@ -3785,19 +3870,36 @@ u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
copy = end - offset;
if (copy > 0) {
copy = min(copy, len);
- crc = skb_crc32c(frag_iter, offset - start, copy, crc);
+ err = skb_crc32c_full(frag_iter, offset - start, copy,
+ &crc);
+ if (err)
+ return err;
len -= copy;
if (len == 0)
- return crc;
+ goto out;
offset += copy;
}
start = end;
}
if (unlikely(len)) {
DEBUG_NET_WARN_ON_ONCE(1);
- return 0;
+ return -EFAULT;
}
+out:
+ *crcp = crc;
+ return 0;
+}
+EXPORT_SYMBOL(skb_crc32c_full);
+/* skb_crc32c() has no way to report failure, so it returns 0, which is a
+ * valid CRC. Use skb_crc32c_full() in new code.
+ */
+u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
+{
+ if (unlikely(skb_crc32c_full(skb, offset, len, &crc))) {
+ WARN_ON_ONCE(!skb_frags_readable(skb));
+ return 0;
+ }
return crc;
}
EXPORT_SYMBOL(skb_crc32c);
@@ -3805,9 +3907,17 @@ EXPORT_SYMBOL(skb_crc32c);
__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
{
+ __wsum csum = skb->csum;
__sum16 sum;
- sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
+ /* If the data can't be checksummed it can't be valid either. */
+ if (skb_checksum_full(skb, 0, len, &csum)) {
+ if (!skb_shared(skb))
+ skb->csum_valid = 0;
+ return (__force __sum16)1;
+ }
+
+ sum = csum_fold(csum);
/* See comments in __skb_checksum_complete(). */
if (likely(!sum)) {
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
@@ -3831,10 +3941,17 @@ EXPORT_SYMBOL(__skb_checksum_complete_head);
*/
__sum16 __skb_checksum_complete(struct sk_buff *skb)
{
- __wsum csum;
+ __wsum csum = 0;
__sum16 sum;
- csum = skb_checksum(skb, 0, skb->len, 0);
+ /* If the data can't be checksummed it can't be valid either. Leave
+ * skb->csum alone, it's not a full packet checksum.
+ */
+ if (skb_checksum_full(skb, 0, skb->len, &csum)) {
+ if (!skb_shared(skb))
+ skb->csum_valid = 0;
+ return (__force __sum16)1;
+ }
sum = csum_fold(csum_add(skb->csum, csum));
/* This check is inverted, because we already knew the hardware
@@ -3905,8 +4022,9 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
* Return value:
* 0: everything is OK
* -ENOMEM: couldn't orphan frags of @from due to lack of memory
- * -EFAULT: skb_copy_bits() found some problem with skb geometry, or readable head
- * payload would be mixed with unreadable frags.
+ * -EFAULT: skb_copy_bits() found some problem with skb geometry, @from has
+ * no head_frag and @hlen is 0 while @len doesn't fit in @to's tailroom,
+ * or readable head payload would be mixed with unreadable frags.
*/
int
skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
@@ -3917,15 +4035,18 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
struct page *page;
unsigned int offset;
+ /* dont bother with small payloads */
+ if (len <= skb_tailroom(to))
+ return skb_copy_bits(from, 0, skb_put(to, len), len);
+
+ /* Without a head_frag the head can't be referenced as a page, so the
+ * caller has to ask for it to be copied.
+ */
if (unlikely(!from->head_frag && !hlen)) {
DEBUG_NET_WARN_ON_ONCE(1);
return -EFAULT;
}
- /* dont bother with small payloads */
- if (len <= skb_tailroom(to))
- return skb_copy_bits(from, 0, skb_put(to, len), len);
-
if (hlen) {
ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
if (unlikely(ret))
@@ -3990,7 +4111,11 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
else
csstart = skb_headlen(skb);
+ /* skb_headlen() underflows if data_len is bigger than len, so check
+ * csstart against len as well.
+ */
if (unlikely(csstart < 0 || csstart > skb_headlen(skb) ||
+ csstart > skb->len ||
(skb->ip_summed == CHECKSUM_PARTIAL &&
csstart + skb->csum_offset + sizeof(__sum16) >
skb->len))) {
@@ -4006,9 +4131,13 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
skb_copy_from_linear_data(skb, to, csstart);
csum = 0;
- if (csstart != skb->len)
- csum = skb_copy_and_csum_bits(skb, csstart, to + csstart,
- skb->len - csstart);
+ /* On failure the rest of @to is zeroed; leave the checksum alone so
+ * the frame goes out with a bad one.
+ */
+ if (csstart != skb->len &&
+ skb_copy_and_csum_bits(skb, csstart, to + csstart,
+ skb->len - csstart, &csum))
+ return;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
long csstuff = csstart + skb->csum_offset;
@@ -4958,6 +5087,15 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
int size;
if (unlikely(gso_by_frags)) {
+ /* The walk only goes one level deep: running out of
+ * members, or finding one with its own frag_list, means
+ * a nested frag_list that head_skb->len counts.
+ */
+ if (unlikely(!list_skb || skb_has_frag_list(list_skb))) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ err = -EINVAL;
+ goto err;
+ }
len = list_skb->len;
} else {
len = head_skb->len - offset;
@@ -4967,9 +5105,11 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
hsize = skb_headlen(head_skb) - offset;
- if (hsize <= 0 && i >= nfrags && skb_headlen(list_skb) &&
+ if (hsize <= 0 && i >= nfrags && list_skb &&
+ skb_headlen(list_skb) &&
(skb_headlen(list_skb) == len || sg)) {
- if (unlikely(skb_headlen(list_skb) > len)) {
+ if (unlikely(skb_headlen(list_skb) > len ||
+ skb_has_frag_list(list_skb))) {
DEBUG_NET_WARN_ON_ONCE(1);
err = -EINVAL;
goto err;
@@ -5057,11 +5197,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
if (!csum) {
if (!nskb->remcsum_offload)
nskb->ip_summed = CHECKSUM_NONE;
- SKB_GSO_CB(nskb)->csum =
- skb_copy_and_csum_bits(head_skb, offset,
- skb_put(nskb,
- len),
- len);
+ if (skb_copy_and_csum_bits(head_skb, offset,
+ skb_put(nskb, len),
+ len,
+ &SKB_GSO_CB(nskb)->csum)) {
+ err = -EFAULT;
+ goto err;
+ }
SKB_GSO_CB(nskb)->csum_start =
skb_headroom(nskb) + doffset;
} else {
@@ -5085,6 +5227,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
while (pos < offset + len) {
if (i >= nfrags) {
+ if (unlikely(!list_skb ||
+ skb_has_frag_list(list_skb))) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ err = -EINVAL;
+ goto err;
+ }
+
if (skb_orphan_frags(list_skb, GFP_ATOMIC) ||
skb_zerocopy_clone(nskb, list_skb,
GFP_ATOMIC))
@@ -5163,9 +5312,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
if (!nskb->remcsum_offload)
nskb->ip_summed = CHECKSUM_NONE;
- SKB_GSO_CB(nskb)->csum =
- skb_checksum(nskb, doffset,
- nskb->len - doffset, 0);
+ SKB_GSO_CB(nskb)->csum = 0;
+ if (skb_checksum_full(nskb, doffset,
+ nskb->len - doffset,
+ &SKB_GSO_CB(nskb)->csum)) {
+ err = -EFAULT;
+ goto err;
+ }
SKB_GSO_CB(nskb)->csum_start =
skb_headroom(nskb) + doffset;
}
@@ -5398,8 +5551,9 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len,
*
* Fill the specified scatter-gather list with mappings/pointers into a
* region of the buffer space attached to a socket buffer. Returns either
- * the number of scatterlist items used, or -EMSGSIZE if the contents
- * could not fit.
+ * the number of scatterlist items used, -EMSGSIZE if the contents
+ * could not fit, or -EINVAL if @offset and @len run past the end of
+ * the skb.
*/
int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
{
@@ -6269,7 +6423,8 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
bool *fragstolen, int *delta_truesize)
{
struct skb_shared_info *to_shinfo, *from_shinfo;
- int i, delta, len = from->len;
+ unsigned int len = from->len;
+ int i, delta;
*fragstolen = false;
@@ -6340,7 +6495,7 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
delta = from->truesize - SKB_TRUESIZE(skb_end_offset(from));
}
- WARN_ON_ONCE(delta < len);
+ WARN_ON_ONCE(delta < 0 || delta < len);
memcpy(to_shinfo->frags + to_shinfo->nr_frags,
from_shinfo->frags,
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 90c0e22c29bea..35008785e3d22 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -364,12 +364,15 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
DEFINE_RAW_FLEX(struct icmp_bxm, icmp_param, replyopts.opt.__data,
IP_OPTIONS_DATA_FIXED_SIZE);
__wsum csum;
+ int err;
icmp_param = from;
- csum = skb_copy_and_csum_bits(icmp_param->skb,
- icmp_param->offset + offset,
- to, len);
+ err = skb_copy_and_csum_bits(icmp_param->skb,
+ icmp_param->offset + offset,
+ to, len, &csum);
+ if (err)
+ return err;
skb->csum = csum_block_add(skb->csum, csum, odd);
if (icmp_param->data.icmph.type <= NR_ICMP_TYPES &&
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 3396f177a18d0..f7da4538d05b5 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1162,9 +1162,14 @@ static int __ip_append_data(struct sock *sk,
data += fragheaderlen + exthdrlen;
if (fraggap) {
- skb->csum = skb_copy_and_csum_bits(
- skb_prev, maxfraglen,
- data + transhdrlen, fraggap);
+ if (skb_copy_and_csum_bits(skb_prev, maxfraglen,
+ data + transhdrlen,
+ fraggap,
+ &skb->csum)) {
+ err = -EFAULT;
+ kfree_skb(skb);
+ goto error;
+ }
skb_prev->csum = csum_sub(skb_prev->csum,
skb->csum);
data += fraggap;
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index a95b0351824f3..31ca3da80b1f1 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -322,9 +322,12 @@ static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, st
struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
struct sk_buff *org_skb = msg->skb;
__wsum csum;
+ int err;
- csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
- to, len);
+ err = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
+ to, len, &csum);
+ if (err)
+ return err;
skb->csum = csum_block_add(skb->csum, csum, odd);
if (!(msg->type & ICMPV6_INFOMSG_MASK))
nf_ct_attach(skb, org_skb);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 25fe0ba98b1a6..d259e7dca8ba2 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1724,9 +1724,14 @@ static int __ip6_append_data(struct sock *sk,
skb->transport_header = (skb->network_header +
fragheaderlen);
if (fraggap) {
- skb->csum = skb_copy_and_csum_bits(
- skb_prev, maxfraglen,
- data + transhdrlen, fraggap);
+ if (skb_copy_and_csum_bits(skb_prev, maxfraglen,
+ data + transhdrlen,
+ fraggap,
+ &skb->csum)) {
+ err = -EFAULT;
+ kfree_skb(skb);
+ goto error;
+ }
skb_prev->csum = csum_sub(skb_prev->csum,
skb->csum);
data += fraggap;
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
index d8d8842c7de5c..5d780ad4ae3a0 100644
--- a/net/sunrpc/socklib.c
+++ b/net/sunrpc/socklib.c
@@ -49,7 +49,9 @@ xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len)
if (desc->need_checksum) {
__wsum csum;
- csum = skb_copy_and_csum_bits(desc->skb, desc->offset, to, len);
+ if (unlikely(skb_copy_and_csum_bits(desc->skb, desc->offset,
+ to, len, &csum)))
+ return 0;
desc->csum = csum_block_add(desc->csum, csum, desc->offset);
} else {
if (unlikely(skb_copy_bits(desc->skb, desc->offset, to, len)))
@@ -142,11 +144,6 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
desc.csum = csum_partial(skb->data, desc.offset, skb->csum);
if (xdr_partial_copy_from_skb(xdr, &desc) < 0)
return -1;
- if (desc.offset != skb->len) {
- __wsum csum2;
- csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0);
- desc.csum = csum_block_add(desc.csum, csum2, desc.offset);
- }
if (desc.count)
return -1;
if (csum_fold(desc.csum))
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 312e51270f293..1c578ea47a1b3 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -142,7 +142,10 @@ static int __skb_nsg(struct sk_buff *skb, int offset, int len,
start = end;
}
}
- BUG_ON(len);
+ if (unlikely(len)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
return elt;
}
|
| 55/3 | 2026/10/21 21:17 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 14271 output: 45 thoughts: 1320 Thoughts: **KMSAN Fuzzing Session Assessment**
Okay, let's analyze this patch series and decide if we need a dedicated KMSAN fuzzing session (i.e., set `NeedsKMSAN=true`). The guidelines are clear: standard KASAN builds cover a lot, including OOB, UAF, double frees, and memory corruption. KMSAN is specifically for uninitialized memory reads – stack, heap, and page allocations – and kernel-to-user info leaks. The rule is simple: if KASAN or other standard detectors can catch it, we don't need KMSAN. We only need KMSAN if the changes introduce *or expose* uninitialized memory risks that *only* KMSAN can detect.
Alright, let's get into this patch series. It touches a bunch of network-related code: `drivers/net/ethernet/sun/sunvnet_common.c`, `drivers/net/xen-netfront.c`, some include files like `include/linux/skbuff.h`, and various core network files (`net/core/dev.c`, `net/core/filter.c`, `net/core/net_test.c`, `net/core/skbuff.c`). Also, some IPv4 and IPv6 stuff, and even some sunrpc and tls code.
The core change revolves around `skb_copy_and_csum_bits`. Specifically, the function signature changed. It now returns an `int` and takes an extra `__wsum *csum` argument. Previously it was: `__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len);`
Now it is: `int __must_check skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, __wsum *csum);`
So, it now returns an error code, and the csum is returned via a pointer. The critical thing here is *what happens when an error occurs.* The updated return type, and the fact that an error code is returned, is a big red flag. Let's delve into the function's implementation.
Looking at the code, if `len` is negative, it returns `-EINVAL`. If the SKB has unreadable frags, it returns `-EFAULT`. Critically, on error (`-EINVAL` or `-EFAULT`), the part of `to` that couldn't be filled is zeroed (to avoid stale bytes!), and crucially, *`csump` is not set*!
Now, let's trace where this function is called and see how the return value is handled. The first caller is in `drivers/net/ethernet/sun/sunvnet_common.c`. The code is doing the following:
```c
if (skb_copy_and_csum_bits(skb, start,
nskb->data + start,
skb->len - start, &csum)) {
dev_kfree_skb(nskb);
dev_kfree_skb(skb);
return NULL;
}
```
If `skb_copy_and_csum_bits` returns an error (anything non-zero), it frees the SKBs and returns `NULL`. It looks like the caller ignores the csum value if the function fails. Good! Wait, what if `skb_copy_and_csum_bits` succeeds? *`*csump = csum;` is executed before `return 0;`*. It seems that, in the case of a success, the checksum that is used by the calling code, `sunvnet_common.c`, will be initialized. Wait! Is `csum` initialized before calling `skb_copy_and_csum_bits`?
Let's check `drivers/net/ethernet/sun/sunvnet_common.c` lines around 1167, and see what is going on...
|
| 56/3 | 2026/10/21 21:17 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/sun/sunvnet_common.c",
"FirstLine": 1155,
"LineCount": 40
}Results: {
"Contents": "1155:\t\n1156:\t\t\tif (skb-\u003eip_summed == CHECKSUM_PARTIAL)\n1157:\t\t\t\tstart = skb_checksum_start_offset(skb);\n1158:\t\t\tif (start) {\n1159:\t\t\t\tint offset = start + nskb-\u003ecsum_offset;\n1160:\t\n1161:\t\t\t\t/* copy the headers, no csum here */\n1162:\t\t\t\tif (skb_copy_bits(skb, 0, nskb-\u003edata, start)) {\n1163:\t\t\t\t\tdev_kfree_skb(nskb);\n1164:\t\t\t\t\tdev_kfree_skb(skb);\n1165:\t\t\t\t\treturn NULL;\n1166:\t\t\t\t}\n1167:\t\n1168:\t\t\t\t/* copy the rest, with csum calculation */\n1169:\t\t\t\t*(__sum16 *)(skb-\u003edata + offset) = 0;\n1170:\t\t\t\tif (skb_copy_and_csum_bits(skb, start,\n1171:\t\t\t\t\t\t\t nskb-\u003edata + start,\n1172:\t\t\t\t\t\t\t skb-\u003elen - start, \u0026csum)) {\n1173:\t\t\t\t\tdev_kfree_skb(nskb);\n1174:\t\t\t\t\tdev_kfree_skb(skb);\n1175:\t\t\t\t\treturn NULL;\n1176:\t\t\t\t}\n1177:\t\n1178:\t\t\t\t/* add in the header checksums */\n1179:\t\t\t\tif (skb-\u003eprotocol == htons(ETH_P_IP)) {\n1180:\t\t\t\t\tstruct iphdr *iph = ip_hdr(nskb);\n1181:\t\n1182:\t\t\t\t\tif (iph-\u003eprotocol == IPPROTO_TCP ||\n1183:\t\t\t\t\t iph-\u003eprotocol == IPPROTO_UDP) {\n1184:\t\t\t\t\t\tcsum = csum_tcpudp_magic(iph-\u003esaddr,\n1185:\t\t\t\t\t\t\t\t\t iph-\u003edaddr,\n1186:\t\t\t\t\t\t\t\t\t skb-\u003elen - start,\n1187:\t\t\t\t\t\t\t\t\t iph-\u003eprotocol,\n1188:\t\t\t\t\t\t\t\t\t csum);\n1189:\t\t\t\t\t}\n1190:\t\t\t\t} else if (skb-\u003eprotocol == htons(ETH_P_IPV6)) {\n1191:\t\t\t\t\tstruct ipv6hdr *ip6h = ipv6_hdr(nskb);\n1192:\t\n1193:\t\t\t\t\tif (ip6h-\u003enexthdr == IPPROTO_TCP ||\n1194:\t\t\t\t\t ip6h-\u003enexthdr == IPPROTO_UDP) {\n"
} |
| 57/3 | 2026/10/21 21:17 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 17189 output: 25 thoughts: 99 Thoughts: Okay, here's my summary, considering my expertise: **Checking `skb_copy_and_csum_bits` Usage After a Potential Vulnerability** Alright, so the code shows that `csum` is only used *after* a call to `skb_copy_and_csum_bits`, specifically *after* it returns non-NULL (implying success). This seems logical at first glance. However, my immediate concern is: has *every* usage of `skb_copy_and_csum_bits` in the kernel been audited to reflect this logic? To be absolutely sure, I need a comprehensive view. Simply looking at this isolated instance isn't enough. Therefore, the next step is to perform a full kernel-wide grep for `skb_copy_and_csum_bits`. I need to ensure that *all* call sites are either correctly updated to use `csum` after a successful return, or, if a caller *doesn't* use the return value this immediately flags a potential issue. A full audit is required to be sure all uses are safe. I can't leave any stone unturned on this one. |
| 58/3 | 2026/10/21 21:17 | tool | grepper |
0mArgs:{
"Expression": "skb_copy_and_csum_bits"
}Results: {
"Output": "drivers/net/ethernet/sun/sunvnet_common.c=1109=static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies)\n--\ndrivers/net/ethernet/sun/sunvnet_common.c-1169-\t\t\t*(__sum16 *)(skb-\u003edata + offset) = 0;\ndrivers/net/ethernet/sun/sunvnet_common.c:1170:\t\t\tif (skb_copy_and_csum_bits(skb, start,\ndrivers/net/ethernet/sun/sunvnet_common.c-1171-\t\t\t\t\t\t nskb-\u003edata + start,\n--\ninclude/linux/skbuff.h=4279=int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);\ninclude/linux/skbuff.h:4280:int __must_check skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\ninclude/linux/skbuff.h-4281-\t\t\t\t\tu8 *to, int len, __wsum *csum);\n--\nnet/core/skbuff.c=3669=EXPORT_SYMBOL(skb_checksum);\n--\nnet/core/skbuff.c-3673-/**\nnet/core/skbuff.c:3674: *\tskb_copy_and_csum_bits - copy data out of an skb and checksum it\nnet/core/skbuff.c-3675- *\t@skb: source buffer\n--\nnet/core/skbuff.c-3685- */\nnet/core/skbuff.c:3686:int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,\nnet/core/skbuff.c-3687-\t\t\t u8 *to, int len, __wsum *csump)\n--\nnet/core/skbuff.c-3769-\t\t\t\tcopy = len;\nnet/core/skbuff.c:3770:\t\t\terr = skb_copy_and_csum_bits(frag_iter, offset - start,\nnet/core/skbuff.c-3771-\t\t\t\t\t\t to, copy, \u0026csum2);\n--\nnet/core/skbuff.c-3795-}\nnet/core/skbuff.c:3796:EXPORT_SYMBOL(skb_copy_and_csum_bits);\nnet/core/skbuff.c-3797-\n--\nnet/core/skbuff.c=4104=void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)\n--\nnet/core/skbuff.c-4137-\tif (csstart != skb-\u003elen \u0026\u0026\nnet/core/skbuff.c:4138:\t skb_copy_and_csum_bits(skb, csstart, to + csstart,\nnet/core/skbuff.c-4139-\t\t\t\t skb-\u003elen - csstart, \u0026csum))\n--\nnet/core/skbuff.c=4974=struct sk_buff *skb_segment(struct sk_buff *head_skb,\n--\nnet/core/skbuff.c-5199-\t\t\t\t\tnskb-\u003eip_summed = CHECKSUM_NONE;\nnet/core/skbuff.c:5200:\t\t\t\tif (skb_copy_and_csum_bits(head_skb, offset,\nnet/core/skbuff.c-5201-\t\t\t\t\t\t\t skb_put(nskb, len),\n--\nnet/ipv4/icmp.c=361=static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,\n--\nnet/ipv4/icmp.c-370-\nnet/ipv4/icmp.c:371:\terr = skb_copy_and_csum_bits(icmp_param-\u003eskb,\nnet/ipv4/icmp.c-372-\t\t\t\t icmp_param-\u003eoffset + offset,\n--\nnet/ipv4/ip_output.c=957=static int __ip_append_data(struct sock *sk,\n--\nnet/ipv4/ip_output.c-1164-\t\t\tif (fraggap) {\nnet/ipv4/ip_output.c:1165:\t\t\t\tif (skb_copy_and_csum_bits(skb_prev, maxfraglen,\nnet/ipv4/ip_output.c-1166-\t\t\t\t\t\t\t data + transhdrlen,\n--\nnet/ipv6/icmp.c=320=static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)\n--\nnet/ipv6/icmp.c-326-\nnet/ipv6/icmp.c:327:\terr = skb_copy_and_csum_bits(org_skb, msg-\u003eoffset + offset,\nnet/ipv6/icmp.c-328-\t\t\t\t to, len, \u0026csum);\n--\nnet/ipv6/ip6_output.c=1453=static int __ip6_append_data(struct sock *sk,\n--\nnet/ipv6/ip6_output.c-1726-\t\t\tif (fraggap) {\nnet/ipv6/ip6_output.c:1727:\t\t\t\tif (skb_copy_and_csum_bits(skb_prev, maxfraglen,\nnet/ipv6/ip6_output.c-1728-\t\t\t\t\t\t\t data + transhdrlen,\n--\nnet/sunrpc/socklib.c=45=xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len)\n--\nnet/sunrpc/socklib.c-51-\nnet/sunrpc/socklib.c:52:\t\tif (unlikely(skb_copy_and_csum_bits(desc-\u003eskb, desc-\u003eoffset,\nnet/sunrpc/socklib.c-53-\t\t\t\t\t\t to, len, \u0026csum)))\n"
} |
| 59/3 | 2026/10/21 21:17 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 19116 output: 37 thoughts: 1489 Thoughts: **Checksum and CRC Analysis** Okay, so I've updated all the callers of `skb_copy_and_csum_bits`, that's a good start. Now I need to check the other related checksum functions. Let's look at `skb_checksum_full` and its callers. Ah, here's its definition, looks straightforward. Now, the places it's used... I see it in `pskb_trim_rcsum_complete` where it looks like it calculates the checksum for a partial fragment, then updates `skb->csum`. Also, `skb_checksum` uses it, seems like a wrapper with a potential `WARN_ON_ONCE` if it fails, which suggests something is wrong if checksums can't be calculated on fragments. There's a recursive call within `skb_checksum_full` itself, used when fragmenting, and a few instances of it being called for the head data: `__skb_checksum_complete_head` and `__skb_checksum_complete`. They appear to be using it to validate the checksum, and mark the `skb` as invalid if a full checksum is required and not present. Finally, `skb_segment` uses it in GSO processing, calculating checksums for the new segments. So it's used in fragment handling, checksum validation/completion, and GSO offload. All fairly critical network functions. Next, I need to check `skb_crc32c_full`. Looks like it's used in `skb_crc32c_csum_help` within `net/core/dev.c`. It appears to be used in calculating checksums for the skb data and writing it to the skb header. `skb_crc32c` uses it, similarly to `skb_checksum`, with the same fragment readable check, and again, a recursive call within the function itself, so the fragment handling logic looks consistent here. Okay, now let's go back and examine `net/sunrpc/socklib.c`. This is interesting. I see a block of code related to checksum calculations using `skb_checksum` that was deleted. I've got to figure out *why* that was removed from `csum_partial_copy_to_xdr`. It looks like it was there to calculate a checksum over the remaining data after an initial partial copy. I need to understand the logic of why the checksum of the remaining data wasn't copied to the xdr. The check that the offset is equal to the skb length is important. I'll need to check the calling function `csum_partial_copy_to_xdr` and `xdr_skb_read_bits` to see what is going on. |
| 60/3 | 2026/10/21 21:17 | tool | read-file |
0mArgs:{
"File": "net/sunrpc/socklib.c",
"FirstLine": 115,
"LineCount": 45
}Results: {
"Contents": " 115:\t\t}\n 116:\t\n 117:\t\treturn copied;\n 118:\t}\n 119:\t\n 120:\t/**\n 121:\t * csum_partial_copy_to_xdr - checksum and copy data\n 122:\t * @xdr: target XDR buffer\n 123:\t * @skb: source skb\n 124:\t *\n 125:\t * We have set things up such that we perform the checksum of the UDP\n 126:\t * packet in parallel with the copies into the RPC client iovec. -DaveM\n 127:\t */\n 128:\tint csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)\n 129:\t{\n 130:\t\tstruct xdr_skb_reader desc = {\n 131:\t\t\t.skb\t\t= skb,\n 132:\t\t\t.count\t\t= skb-\u003elen - desc.offset,\n 133:\t\t};\n 134:\t\n 135:\t\tif (skb_csum_unnecessary(skb)) {\n 136:\t\t\tif (xdr_partial_copy_from_skb(xdr, \u0026desc) \u003c 0)\n 137:\t\t\t\treturn -1;\n 138:\t\t\tif (desc.count)\n 139:\t\t\t\treturn -1;\n 140:\t\t\treturn 0;\n 141:\t\t}\n 142:\t\n 143:\t\tdesc.need_checksum = true;\n 144:\t\tdesc.csum = csum_partial(skb-\u003edata, desc.offset, skb-\u003ecsum);\n 145:\t\tif (xdr_partial_copy_from_skb(xdr, \u0026desc) \u003c 0)\n 146:\t\t\treturn -1;\n 147:\t\tif (desc.count)\n 148:\t\t\treturn -1;\n 149:\t\tif (csum_fold(desc.csum))\n 150:\t\t\treturn -1;\n 151:\t\tif (unlikely(skb-\u003eip_summed == CHECKSUM_COMPLETE) \u0026\u0026\n 152:\t\t !skb-\u003ecsum_complete_sw)\n 153:\t\t\tnetdev_rx_csum_fault(skb-\u003edev, skb);\n 154:\t\treturn 0;\n 155:\t}\n 156:\t\n 157:\tstatic inline int xprt_sendmsg(struct socket *sock, struct msghdr *msg,\n 158:\t\t\t\t size_t seek)\n 159:\t{\n"
} |
| 61/3 | 2026/10/21 21:17 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 21937 output: 35 thoughts: 7156 Thoughts: **Analysis of Network Buffer Error Handling and Memory Safety** Okay, so I've been diving into this patch series, and it's clear that the primary focus is to improve error handling related to network buffer operations, specifically aiming for memory safety and preventing the potential for uninitialized memory exposure. It seems like the core change revolves around how functions like `skb_copy_and_csum_bits`, `skb_checksum_full`, and related functions manage their return values and side effects in the event of failures. I noticed that `desc.offset` is set to 0 initially, and then the function `xdr_partial_copy_from_skb` copies the whole payload. If `desc.count`, then it failed. So, `desc.offset != skb->len` was redundant, and essentially dead code that was correctly removed. The major pattern here is that, when functions like `skb_copy_and_csum_bits` encounter an issue (unreadable fragments, out-of-bounds reads, etc.), they now return an error code (-EFAULT or -EINVAL). Crucially, before returning, they explicitly zero out the destination buffer (`to`) using `memset`. This prevents the caller from potentially accessing stale or uninitialized data. Before this patch, there were checksums being returned that were unhelpful in telling the caller about the error state. I spent some time confirming that the checksums passed into functions are always initialized (e.g. they are set to 0), and I checked all call sites. I checked `skb_zerocopy` to find that the order of `len <= skb_tailroom(to)` and `!from->head_frag && !hlen` has been swapped: meaning that now, if the payload is small enough, the kernel can copy it without needing a head fragment, which avoids the need for copies. The change in `xen-netfront.c` replaces a `BUG_ON` with proper error handling (returning NULL and freeing the SKB). I've been meaning to check if the caller properly handles this change, but the focus is clearly on preventing kernel panics in the event of copy errors, which is a good thing. I confirmed that there are no introduced uninitialized memory or user-space copies that could expose kernel memory. Any potential failures from network copy calls return the error to the caller. All these changes seem geared towards making the code more robust and, most importantly, safer by eliminating implicit assumptions about data initialization and return value semantics. |
| 62/3 | 2026/10/21 21:18 | tool | grepper |
0mArgs:{
"Expression": "bounce_skb",
"PathPrefixes": [
"drivers/net/xen-netfront.c"
]
}Results: {
"Output": "drivers/net/xen-netfront.c=644=static int xennet_xdp_xmit(struct net_device *dev, int n,\n--\ndrivers/net/xen-netfront.c-675-\ndrivers/net/xen-netfront.c:676:static struct sk_buff *bounce_skb(const struct sk_buff *skb)\ndrivers/net/xen-netfront.c-677-{\n--\ndrivers/net/xen-netfront.c=711=static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)\n--\ndrivers/net/xen-netfront.c-766-\tif (np-\u003ebounce || unlikely(PAGE_SIZE - offset \u003c ETH_HLEN)) {\ndrivers/net/xen-netfront.c:767:\t\tnskb = bounce_skb(skb);\ndrivers/net/xen-netfront.c-768-\t\tif (!nskb)\n"
} |
| 63/3 | 2026/10/21 21:18 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 29920 output: 37 thoughts: 139 Thoughts: **Analyzing a Kernel Bug**
Okay, so I'm digging into this kernel code and something's bugging me. Specifically, lines 767-768 of this particular section. It looks like `nskb = bounce_skb(skb); if (!nskb)` is called, but the caller already checked `if (!nskb)`. That's a red flag – a potential double-check situation, which usually suggests a misunderstanding or a subtle race condition lurking somewhere. My immediate thought is, "Why the redundant check?" It smells a bit off.
Now, I need to understand what's happening *inside* that `__skb_nsg` function that's being called, so I'll go check that function out. Let's see...Ah, here we are in `net/tls/tls_sw.c`. I see a suspicious `BUG_ON(len);` being changed to `if (unlikely(len)) { ... return -EINVAL; }`. The comment says it's being changed. So, there's a reason for that change. Okay, that's interesting. The `DEBUG_NET_WARN_ON_ONCE(1)` suggests that it's hitting this condition, but only occasionally, which makes this bug much harder to track down.
Therefore, let's now investigate the callers of `__skb_nsg` and `skb_nsg` to understand the context and where this potentially erroneous `len` value is coming from. Need to see where the data is actually coming from to understand the data's validity.
|
| 64/3 | 2026/10/21 21:18 | tool | grepper |
0mArgs:{
"Expression": "__skb_nsg|skb_nsg",
"PathPrefixes": [
"net/tls/"
]
}Results: {
"Output": "net/tls/tls_sw.c=71=noinline void tls_err_abort(struct sock *sk, int err)\n--\nnet/tls/tls_sw.c-80-\nnet/tls/tls_sw.c:81:static int __skb_nsg(struct sk_buff *skb, int offset, int len,\nnet/tls/tls_sw.c-82- unsigned int recursion_level)\n--\nnet/tls/tls_sw.c-131- chunk = len;\nnet/tls/tls_sw.c:132: ret = __skb_nsg(frag_iter, offset - start, chunk,\nnet/tls/tls_sw.c-133- recursion_level + 1);\n--\nnet/tls/tls_sw.c-154- */\nnet/tls/tls_sw.c:155:static int skb_nsg(struct sk_buff *skb, int offset, int len)\nnet/tls/tls_sw.c-156-{\nnet/tls/tls_sw.c:157: return __skb_nsg(skb, offset, len, 0);\nnet/tls/tls_sw.c-158-}\n--\nnet/tls/tls_sw.c=1268=static int tls_decrypt_sg(struct sock *sk, struct iov_iter *out_iov,\n--\nnet/tls/tls_sw.c-1288-\nnet/tls/tls_sw.c:1289:\tn_sgin = skb_nsg(skb, rxm-\u003eoffset + prot-\u003eprepend_size,\nnet/tls/tls_sw.c-1290-\t\t\t rxm-\u003efull_len - prot-\u003eprepend_size);\n"
} |
| 65/3 | 2026/10/21 21:18 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 30889 output: 38 thoughts: 21 Thoughts: Here's my take on those thoughts, tailored for an expert audience: **Analyzing the `n_sgin` Handling in `tls_decrypt_sg`** Okay, so I'm diving into `tls_decrypt_sg` to see exactly how it's managing `n_sgin`. This is a critical area, as any mishandling here could have significant security implications, especially in how we're dealing with the secure gcm nonce. I want to understand if there are any subtle flaws in the nonce generation or validation within this function, potential issues that might lead to nonce reuse or predictability. I need to quickly assess if `n_sgin` is being properly initialized, if there's any potential for it to be influenced by untrusted data, and if the overall process adheres to best practices. Are we using a cryptographically secure PRNG for generating or manipulating it? Does it account for a counter increment to the nonce? Any nonces stored in context? This warrants close scrutiny since it's at the core of ensuring the confidentiality and integrity of our TLS sessions. I have to assess whether there might be any timing-based side-channel vulnerabilities linked to the handling of `n_sgin` that an attacker could exploit. |
| 66/3 | 2026/10/21 21:18 | tool | read-file |
0mArgs:{
"File": "net/tls/tls_sw.c",
"FirstLine": 1288,
"LineCount": 25
}Results: {
"Contents": "1288:\t\n1289:\t\tn_sgin = skb_nsg(skb, rxm-\u003eoffset + prot-\u003eprepend_size,\n1290:\t\t\t\t rxm-\u003efull_len - prot-\u003eprepend_size);\n1291:\t\tif (n_sgin \u003c 1)\n1292:\t\t\treturn n_sgin ?: -EBADMSG;\n1293:\t\n1294:\t\tif (darg-\u003ezc \u0026\u0026 (out_iov || out_sg)) {\n1295:\t\t\tclear_skb = NULL;\n1296:\t\n1297:\t\t\tif (out_iov)\n1298:\t\t\t\tn_sgout = 1 + tail_pages +\n1299:\t\t\t\t\tiov_iter_npages_cap(out_iov, INT_MAX, data_len);\n1300:\t\t\telse\n1301:\t\t\t\tn_sgout = sg_nents(out_sg);\n1302:\t\t} else {\n1303:\t\t\tdarg-\u003ezc = false;\n1304:\t\n1305:\t\t\tclear_skb = tls_alloc_clrtxt_skb(sk, skb, rxm-\u003efull_len);\n1306:\t\t\tif (!clear_skb)\n1307:\t\t\t\treturn -ENOMEM;\n1308:\t\n1309:\t\t\tn_sgout = 1 + skb_shinfo(clear_skb)-\u003enr_frags;\n1310:\t\t}\n1311:\t\n1312:\t\t/* Increment to accommodate AAD */\n"
} |
| 67/3 | 2026/10/21 21:18 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 31617 output: 37 thoughts: 3637 Thoughts: **Analyzing Checksum and Copy Operations in skbuff.c** Okay, so I've been tracing through these error handling paths in `skbuff.c`, specifically focusing on checksum calculations and data copies within the context of GSO (Generic Segmentation Offload). I started by looking at how negative return codes are handled, which seems straightforward enough - a check for `< 1` handles the negative return code directly, which is good. I then dug into `skb_segment`, and it became clear there was some careful handling of errors in `skb_copy_and_csum_bits` and `skb_checksum_full`. The key point here is that if either of these functions fail, they return an error code, and the allocated skb/segs are freed via goto err. The code carefully avoids using potentially incorrect values from failed checksum operations. I took a detour to thoroughly review `skb_checksum_full`. I noticed that if `skb_checksum_full` returns an error, the pointed-to checksum value (`*csump`) is NOT touched. The callers are all designed in a way that handles the error appropriately. For instance, in `skb_checksum` and `__skb_checksum_complete_head`, a non-zero return value indicates failure, but no invalid data is used. I've confirmed that this pattern is consistently maintained across all the call sites of `skb_checksum_full`. In all the call paths, the `csump` is only set when the function returns 0. I shifted my focus to `skb_copy_and_csum_bits`. I realized that `len < 0` is handled correctly, returning `-EINVAL`, but the critical thing to note here is that the function doesn't write to `*csump` or `to` if the length is negative, avoiding undefined behavior. It also seemed important to note that when `skb_copy_and_csum_bits` returns -EFAULT, the buffer `to` is zeroed via `memset`, preventing the caller from receiving stale data. Again, this points to a robust approach of error handling and data integrity. All paths that return -EFAULT zero out `to`. Finally, I checked `skb_crc32c_full` and its caller. Similar to the checksum functions, if `skb_crc32c_full` returns an error, the CRC value isn't modified. `skb->data + offset` is NOT modified. This confirms the trend of maintaining data integrity on error paths. The return value is used to propagate an error, without touching the data. |
| 68/3 | 2026/10/21 21:19 | tool | read-file |
0mArgs:{
"File": "net/core/skbuff.c",
"FirstLine": 4025,
"LineCount": 50
}Results: {
"Contents": "4025:\t *\t-EFAULT: skb_copy_bits() found some problem with skb geometry, @from has\n4026:\t *\tno head_frag and @hlen is 0 while @len doesn't fit in @to's tailroom,\n4027:\t *\tor readable head payload would be mixed with unreadable frags.\n4028:\t */\n4029:\tint\n4030:\tskb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)\n4031:\t{\n4032:\t\tint i, j = 0;\n4033:\t\tint plen = 0; /* length of skb-\u003ehead fragment */\n4034:\t\tint ret;\n4035:\t\tstruct page *page;\n4036:\t\tunsigned int offset;\n4037:\t\n4038:\t\t/* dont bother with small payloads */\n4039:\t\tif (len \u003c= skb_tailroom(to))\n4040:\t\t\treturn skb_copy_bits(from, 0, skb_put(to, len), len);\n4041:\t\n4042:\t\t/* Without a head_frag the head can't be referenced as a page, so the\n4043:\t\t * caller has to ask for it to be copied.\n4044:\t\t */\n4045:\t\tif (unlikely(!from-\u003ehead_frag \u0026\u0026 !hlen)) {\n4046:\t\t\tDEBUG_NET_WARN_ON_ONCE(1);\n4047:\t\t\treturn -EFAULT;\n4048:\t\t}\n4049:\t\n4050:\t\tif (hlen) {\n4051:\t\t\tret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);\n4052:\t\t\tif (unlikely(ret))\n4053:\t\t\t\treturn ret;\n4054:\t\t\tlen -= hlen;\n4055:\t\t} else {\n4056:\t\t\tplen = min_t(int, skb_headlen(from), len);\n4057:\t\t\tif (plen) {\n4058:\t\t\t\tpage = virt_to_head_page(from-\u003ehead);\n4059:\t\t\t\toffset = from-\u003edata - (unsigned char *)page_address(page);\n4060:\t\t\t\t__skb_fill_netmem_desc(to, 0, page_to_netmem(page),\n4061:\t\t\t\t\t\t offset, plen);\n4062:\t\t\t\tget_page(page);\n4063:\t\t\t\tj = 1;\n4064:\t\t\t\tlen -= plen;\n4065:\t\t\t}\n4066:\t\t}\n4067:\t\n4068:\t\tif (!skb_frags_readable(from) \u0026\u0026 j \u003e 0 \u0026\u0026 len) {\n4069:\t\t\tput_page(page);\n4070:\t\t\treturn -EFAULT;\n4071:\t\t}\n4072:\t\n4073:\t\tskb_len_add(to, len + plen);\n4074:\t\n"
} |
| 69/3 | 2026/10/21 21:19 | llm | kmsan-evaluator |
1mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 36654 output: 275 thoughts: 2264 Thoughts: **KMSAN Assessment: SKB Improvements** Okay, let's break this down. My initial thought process is to meticulously analyze the code changes against the KMSAN criteria. First, I'm thinking about the original code: it seems like there are changes to how we handle checksum calculations, GSO segmentation, and some skb coalescing. My main focus is on whether any of these changes introduce a risk of uninitialized memory reads or information leaks. I recall some past issues. The initial code in `skb_zerocopy` that was refactored was just to avoid an unnecessary -EFAULT when a copy was actually small and fitting the tailroom. `skb_segment` had bugs related to nested `frag_lists` that could lead to crashes or out-of-bounds access. The `skb_try_coalesce` issue was due to a signed/unsigned comparison issue, which isn't directly related to uninitialized memory, but bounds checking. Now I'm diving into the KMSAN criteria. 1. **Kernel structures to user space:** I need to make sure that no new kernel structures or fields are being sent to userspace. After checking, I realize the modified functions are mainly checksum calculations, GSO segmentation, coalescing, and some error handling in network drivers. So, I need to check to see if any of these functions touch user space. My quick scan reveals no direct user-space exposure. However, I want to be 100% sure. I need to make sure any `skb` attributes being copied to user space aren't affected. I confirm they aren't, so no risk. The most important thing here is that `skb_copy_and_csum_bits`, when returning an error, explicitly zero-fills the destination buffer (`to`) to prevent using stale or uninitialized data. 2. **Conditional logic based on uninitialized data:** Next, I'm carefully reviewing all the conditional branches, making sure they don't depend on potentially uninitialized variables. This means going function by function: `vnet_skb_shape`, `skb_checksum_full`, `skb_checksum`, `skb_crc32c_full`, and so on. In each function that I'm looking at, the checksum values (`csum`, `crc`) are always properly initialized either directly or passed in by reference in a controlled way. If an error is returned, the checksum values are not considered, so no uninitialized reads. In `skb_segment`, it's the same pattern for `SKB_GSO_CB(nskb)->csum`: it's handled, never read uninitialized. 3. **Allocation/Initialization of Complex Data Structures:** There aren't any new complex data structures being allocated or initialized here. This criterion is straightforward to eliminate. 4. **Bounds checks and logic risking uninitialized data access:** Now, this is crucial. This is where I'm examining how the changes affect bounds checks, and if the logic could lead to reading uninitialized data. I confirm that on the contrary, the changes tighten the bounds checks. Error handling is improved, and the bugs around nested `frag_lists` in `skb_segment` have been fixed. I have to confirm that these fixes don't expose any uninitialized data access. Also, `skb_copy_and_csum_bits`, `skb_checksum_full`, etc., all have stricter bounds checking and error propagation. If there's an error, `memset` is called to zero-out the buffer to prevent reads of uninitialized memory. This reinforces that KASAN (Kernel Address Sanitizer) is more relevant here, since KASAN specifically addresses memory access violations, buffer overflows, and NULL pointer dereferences. So, after careful consideration, all of the changes here are primarily improving memory safety in areas that KASAN already addresses. KMSAN is not required here. I confirm that all the issues addressed are OOB, NULL-deref, bounds checks. All the output variables are initialized. No risk of infoleak. Therefore, I conclude `NeedsKMSAN=false`. I want to be super clear, and I re-read the original patch description and my analysis, comparing KASAN to KMSAN. The improvements are about checksumming, replacing `BUG_ON`s with error returns, and fixing frag_list issues. KASAN is there for memory safety. KMSAN isn't needed here. `NeedsKMSAN=false` is correct. |
| 70/3 | 2026/10/21 21:20 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch series refactors SKB checksum and CRC helpers (`skb_checksum_full`, `skb_copy_and_csum_bits`, `skb_crc32c_full`) to propagate error codes rather than silently returning 0 on unreadable frags or buffer overruns. It also replaces several `BUG_ON()` calls with error handling and adds checks against invalid nested frag_lists in `skb_segment()`.\n\nFrom a memory sanitization perspective:\n1. All out-pointer arguments (`csump`, `crcp`) are either initialized before calling or guarded by return value checks ensuring they are only read on success.\n2. `skb_copy_and_csum_bits()` explicitly zeroes out destination buffers with `memset()` on error paths to prevent callers from accessing stale/uninitialized memory.\n3. No kernel-to-userspace data leaks, uninitialized struct fields, or branching on uninitialized data are introduced.\n4. The bugs being addressed (buffer bounds, invalid frag geometry, BUG_ON conditions) are covered by KASAN and standard kernel debug assertions.\n\nTherefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch series refactors SKB checksum and CRC helpers (`skb_checksum_full`, `skb_copy_and_csum_bits`, `skb_crc32c_full`) to propagate error codes rather than silently returning 0 on unreadable frags or buffer overruns. It also replaces several `BUG_ON()` calls with error handling and adds checks against invalid nested frag_lists in `skb_segment()`.\n\nFrom a memory sanitization perspective:\n1. All out-pointer arguments (`csump`, `crcp`) are either initialized before calling or guarded by return value checks ensuring they are only read on success.\n2. `skb_copy_and_csum_bits()` explicitly zeroes out destination buffers with `memset()` on error paths to prevent callers from accessing stale/uninitialized memory.\n3. No kernel-to-userspace data leaks, uninitialized struct fields, or branching on uninitialized data are introduced.\n4. The bugs being addressed (buffer bounds, invalid frag geometry, BUG_ON conditions) are covered by KASAN and standard kernel debug assertions.\n\nTherefore, 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) |
|---|