All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net v1] kcm: fix zero-frag skb in frag_list on partial sendmsg error
@ 2026-02-13  6:12 Jiayuan Chen
  2026-02-17 11:52 ` Paolo Abeni
  0 siblings, 1 reply; 4+ messages in thread
From: Jiayuan Chen @ 2026-02-13  6:12 UTC (permalink / raw)
  To: netdev
  Cc: jiayuan.chen, Jiayuan Chen, syzbot+52624bdfbf2746d37d70,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Michal Luczaj, Sven Stegemann, Christian Brauner,
	Tom Herbert, linux-kernel

From: Jiayuan Chen <jiayuan.chen@shopee.com>

Syzkaller reported a warning in kcm_write_msgs() when processing a
message with a zero-fragment skb in the frag_list.

When kcm_sendmsg() fills MAX_SKB_FRAGS fragments in the current skb,
it allocates a new skb (tskb) and links it into the frag_list before
copying data. If the copy subsequently fails (e.g. -EFAULT from
user memory), tskb remains in the frag_list with zero fragments:

  head skb (msg being assembled, NOT yet in sk_write_queue)
  +-----------+
  | frags[17] |  (MAX_SKB_FRAGS, all filled with data)
  | frag_list-+--> tskb
  +-----------+    +----------+
                   | frags[0] |  (empty! copy failed before filling)
                   +----------+

For SOCK_SEQPACKET with partial data already copied, the error path
saves this message via partial_message for later completion. A
subsequent zero-length write(fd, NULL, 0) implies MSG_EOR, which
queues the message to sk_write_queue. kcm_write_msgs() then walks
the frag_list and hits:

  WARN_ON(!skb_shinfo(skb)->nr_frags)

TCP has a similar pattern where skbs are enqueued before data copy
and cleaned up on failure via tcp_remove_empty_skb(). KCM was
missing the equivalent cleanup.

Fix this by tracking the predecessor skb (frag_prev) when allocating
a new frag_list entry. On error, if the tail skb has zero frags,
use frag_prev to unlink and free it in O(1) without walking the
singly-linked frag_list. frag_prev is safe to dereference because
the entire message chain is only held locally (or in kcm->seq_skb)
and is not added to sk_write_queue until MSG_EOR, so the send path
cannot free it underneath us.

Also change the WARN_ON to WARN_ON_ONCE to avoid flooding the log
if the condition is somehow hit repeatedly.

There are currently no KCM selftests in the kernel tree; a simple
reproducer is available at [1].

[1] https://gist.github.com/mrpre/a94d431c757e8d6f168f4dd1a3749daa

Reported-by: syzbot+52624bdfbf2746d37d70@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/000000000000269a1405a12fdc77@google.com/T/
Fixes: ab7ac4eb9832 ("kcm: Kernel Connection Multiplexor module")
Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
---
 net/kcm/kcmsock.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index 5dd7e0509a48..3912e75079f5 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -628,7 +628,7 @@ static int kcm_write_msgs(struct kcm_sock *kcm)
 			skb = txm->frag_skb;
 		}
 
-		if (WARN_ON(!skb_shinfo(skb)->nr_frags) ||
+		if (WARN_ON_ONCE(!skb_shinfo(skb)->nr_frags) ||
 		    WARN_ON_ONCE(!skb_frag_page(&skb_shinfo(skb)->frags[0]))) {
 			ret = -EINVAL;
 			goto out;
@@ -749,7 +749,7 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 {
 	struct sock *sk = sock->sk;
 	struct kcm_sock *kcm = kcm_sk(sk);
-	struct sk_buff *skb = NULL, *head = NULL;
+	struct sk_buff *skb = NULL, *head = NULL, *frag_prev = NULL;
 	size_t copy, copied = 0;
 	long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 	int eor = (sock->type == SOCK_DGRAM) ?
@@ -824,6 +824,7 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 				else
 					skb->next = tskb;
 
+				frag_prev = skb;
 				skb = tskb;
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
 				continue;
@@ -933,6 +934,22 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 out_error:
 	kcm_push(kcm);
 
+	/* When MAX_SKB_FRAGS was reached, a new skb was allocated and
+	 * linked into the frag_list before data copy. If the copy
+	 * subsequently failed, this skb has zero frags. Remove it from
+	 * the frag_list to prevent kcm_write_msgs from later hitting
+	 * WARN_ON(!skb_shinfo(skb)->nr_frags).
+	 */
+	if (frag_prev && !skb_shinfo(skb)->nr_frags) {
+		if (head == frag_prev)
+			skb_shinfo(head)->frag_list = NULL;
+		else
+			frag_prev->next = NULL;
+		kfree_skb(skb);
+		/* Update skb as it may be saved in partial_message via goto */
+		skb = frag_prev;
+	}
+
 	if (sock->type == SOCK_SEQPACKET) {
 		/* Wrote some bytes before encountering an
 		 * error, return partial success.
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH net v1] kcm: fix zero-frag skb in frag_list on partial sendmsg error
@ 2026-02-13 13:39 kernel test robot
  0 siblings, 0 replies; 4+ messages in thread
From: kernel test robot @ 2026-02-13 13:39 UTC (permalink / raw)
  To: oe-kbuild; +Cc: lkp, Dan Carpenter

BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20260213061232.338244-1-jiayuan.chen@linux.dev>
References: <20260213061232.338244-1-jiayuan.chen@linux.dev>
TO: Jiayuan Chen <jiayuan.chen@linux.dev>
TO: netdev@vger.kernel.org
CC: jiayuan.chen@linux.dev
CC: Jiayuan Chen <jiayuan.chen@shopee.com>
CC: syzbot+52624bdfbf2746d37d70@syzkaller.appspotmail.com
CC: Eric Dumazet <edumazet@google.com>
CC: Jakub Kicinski <kuba@kernel.org>
CC: Paolo Abeni <pabeni@redhat.com>
CC: Simon Horman <horms@kernel.org>
CC: Michal Luczaj <mhal@rbox.co>
CC: Sven Stegemann <sven@stegemann.de>
CC: Christian Brauner <brauner@kernel.org>
CC: Tom Herbert <tom@herbertland.com>
CC: linux-kernel@vger.kernel.org

Hi Jiayuan,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Jiayuan-Chen/kcm-fix-zero-frag-skb-in-frag_list-on-partial-sendmsg-error/20260213-141421
base:   net/main
patch link:    https://lore.kernel.org/r/20260213061232.338244-1-jiayuan.chen%40linux.dev
patch subject: [PATCH net v1] kcm: fix zero-frag skb in frag_list on partial sendmsg error
:::::: branch date: 7 hours ago
:::::: commit date: 7 hours ago
config: sparc-randconfig-r073-20260213 (https://download.01.org/0day-ci/archive/20260213/202602132158.nPDgggYY-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 11.5.0
smatch version: v0.5.0-8994-gd50c5a4c

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <error27@gmail.com>
| Closes: https://lore.kernel.org/r/202602132158.nPDgggYY-lkp@intel.com/

smatch warnings:
net/kcm/kcmsock.c:945 kcm_sendmsg() error: we previously assumed 'head' could be null (see line 787)

vim +/head +945 net/kcm/kcmsock.c

ab7ac4eb9832e3 Tom Herbert       2016-03-07  747  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  748  static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  749  {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  750  	struct sock *sk = sock->sk;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  751  	struct kcm_sock *kcm = kcm_sk(sk);
3d264f513af54f Jiayuan Chen      2026-02-13  752  	struct sk_buff *skb = NULL, *head = NULL, *frag_prev = NULL;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  753  	size_t copy, copied = 0;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  754  	long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  755  	int eor = (sock->type == SOCK_DGRAM) ?
ab7ac4eb9832e3 Tom Herbert       2016-03-07  756  		  !(msg->msg_flags & MSG_MORE) : !!(msg->msg_flags & MSG_EOR);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  757  	int err = -EPIPE;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  758  
807067bf014d4a Kuniyuki Iwashima 2024-08-15  759  	mutex_lock(&kcm->tx_mutex);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  760  	lock_sock(sk);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  761  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  762  	/* Per tcp_sendmsg this should be in poll */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  763  	sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  764  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  765  	if (sk->sk_err)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  766  		goto out_error;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  767  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  768  	if (kcm->seq_skb) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  769  		/* Previously opened message */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  770  		head = kcm->seq_skb;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  771  		skb = kcm_tx_msg(head)->last_skb;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  772  		goto start;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  773  	}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  774  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  775  	/* Call the sk_stream functions to manage the sndbuf mem. */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  776  	if (!sk_stream_memory_free(sk)) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  777  		kcm_push(kcm);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  778  		set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  779  		err = sk_stream_wait_memory(sk, &timeo);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  780  		if (err)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  781  			goto out_error;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  782  	}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  783  
98e3862ca2b1ae WANG Cong         2017-02-07  784  	if (msg_data_left(msg)) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  785  		/* New message, alloc head skb */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  786  		head = alloc_skb(0, sk->sk_allocation);
ab7ac4eb9832e3 Tom Herbert       2016-03-07 @787  		while (!head) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  788  			kcm_push(kcm);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  789  			err = sk_stream_wait_memory(sk, &timeo);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  790  			if (err)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  791  				goto out_error;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  792  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  793  			head = alloc_skb(0, sk->sk_allocation);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  794  		}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  795  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  796  		skb = head;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  797  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  798  		/* Set ip_summed to CHECKSUM_UNNECESSARY to avoid calling
ab7ac4eb9832e3 Tom Herbert       2016-03-07  799  		 * csum_and_copy_from_iter from skb_do_copy_data_nocache.
ab7ac4eb9832e3 Tom Herbert       2016-03-07  800  		 */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  801  		skb->ip_summed = CHECKSUM_UNNECESSARY;
98e3862ca2b1ae WANG Cong         2017-02-07  802  	}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  803  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  804  start:
ab7ac4eb9832e3 Tom Herbert       2016-03-07  805  	while (msg_data_left(msg)) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  806  		bool merge = true;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  807  		int i = skb_shinfo(skb)->nr_frags;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  808  		struct page_frag *pfrag = sk_page_frag(sk);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  809  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  810  		if (!sk_page_frag_refill(sk, pfrag))
ab7ac4eb9832e3 Tom Herbert       2016-03-07  811  			goto wait_for_memory;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  812  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  813  		if (!skb_can_coalesce(skb, i, pfrag->page,
ab7ac4eb9832e3 Tom Herbert       2016-03-07  814  				      pfrag->offset)) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  815  			if (i == MAX_SKB_FRAGS) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  816  				struct sk_buff *tskb;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  817  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  818  				tskb = alloc_skb(0, sk->sk_allocation);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  819  				if (!tskb)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  820  					goto wait_for_memory;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  821  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  822  				if (head == skb)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  823  					skb_shinfo(head)->frag_list = tskb;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  824  				else
ab7ac4eb9832e3 Tom Herbert       2016-03-07  825  					skb->next = tskb;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  826  
3d264f513af54f Jiayuan Chen      2026-02-13  827  				frag_prev = skb;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  828  				skb = tskb;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  829  				skb->ip_summed = CHECKSUM_UNNECESSARY;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  830  				continue;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  831  			}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  832  			merge = false;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  833  		}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  834  
2b03bcae66c7b2 David Howells     2023-05-31  835  		if (msg->msg_flags & MSG_SPLICE_PAGES) {
2b03bcae66c7b2 David Howells     2023-05-31  836  			copy = msg_data_left(msg);
2b03bcae66c7b2 David Howells     2023-05-31  837  			if (!sk_wmem_schedule(sk, copy))
2b03bcae66c7b2 David Howells     2023-05-31  838  				goto wait_for_memory;
2b03bcae66c7b2 David Howells     2023-05-31  839  
25489a4f556414 Michal Luczaj     2025-07-02  840  			err = skb_splice_from_iter(skb, &msg->msg_iter, copy);
2b03bcae66c7b2 David Howells     2023-05-31  841  			if (err < 0) {
2b03bcae66c7b2 David Howells     2023-05-31  842  				if (err == -EMSGSIZE)
2b03bcae66c7b2 David Howells     2023-05-31  843  					goto wait_for_memory;
2b03bcae66c7b2 David Howells     2023-05-31  844  				goto out_error;
2b03bcae66c7b2 David Howells     2023-05-31  845  			}
2b03bcae66c7b2 David Howells     2023-05-31  846  
2b03bcae66c7b2 David Howells     2023-05-31  847  			copy = err;
2b03bcae66c7b2 David Howells     2023-05-31  848  			skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG;
2b03bcae66c7b2 David Howells     2023-05-31  849  			sk_wmem_queued_add(sk, copy);
2b03bcae66c7b2 David Howells     2023-05-31  850  			sk_mem_charge(sk, copy);
2b03bcae66c7b2 David Howells     2023-05-31  851  
2b03bcae66c7b2 David Howells     2023-05-31  852  			if (head != skb)
2b03bcae66c7b2 David Howells     2023-05-31  853  				head->truesize += copy;
2b03bcae66c7b2 David Howells     2023-05-31  854  		} else {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  855  			copy = min_t(int, msg_data_left(msg),
ab7ac4eb9832e3 Tom Herbert       2016-03-07  856  				     pfrag->size - pfrag->offset);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  857  			if (!sk_wmem_schedule(sk, copy))
ab7ac4eb9832e3 Tom Herbert       2016-03-07  858  				goto wait_for_memory;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  859  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  860  			err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
ab7ac4eb9832e3 Tom Herbert       2016-03-07  861  						       pfrag->page,
ab7ac4eb9832e3 Tom Herbert       2016-03-07  862  						       pfrag->offset,
ab7ac4eb9832e3 Tom Herbert       2016-03-07  863  						       copy);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  864  			if (err)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  865  				goto out_error;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  866  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  867  			/* Update the skb. */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  868  			if (merge) {
2b03bcae66c7b2 David Howells     2023-05-31  869  				skb_frag_size_add(
2b03bcae66c7b2 David Howells     2023-05-31  870  					&skb_shinfo(skb)->frags[i - 1], copy);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  871  			} else {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  872  				skb_fill_page_desc(skb, i, pfrag->page,
ab7ac4eb9832e3 Tom Herbert       2016-03-07  873  						   pfrag->offset, copy);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  874  				get_page(pfrag->page);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  875  			}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  876  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  877  			pfrag->offset += copy;
2b03bcae66c7b2 David Howells     2023-05-31  878  		}
2b03bcae66c7b2 David Howells     2023-05-31  879  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  880  		copied += copy;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  881  		if (head != skb) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  882  			head->len += copy;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  883  			head->data_len += copy;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  884  		}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  885  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  886  		continue;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  887  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  888  wait_for_memory:
ab7ac4eb9832e3 Tom Herbert       2016-03-07  889  		kcm_push(kcm);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  890  		err = sk_stream_wait_memory(sk, &timeo);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  891  		if (err)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  892  			goto out_error;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  893  	}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  894  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  895  	if (eor) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  896  		bool not_busy = skb_queue_empty(&sk->sk_write_queue);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  897  
98e3862ca2b1ae WANG Cong         2017-02-07  898  		if (head) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  899  			/* Message complete, queue it on send buffer */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  900  			__skb_queue_tail(&sk->sk_write_queue, head);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  901  			kcm->seq_skb = NULL;
cd6e111bf5be5c Tom Herbert       2016-03-07  902  			KCM_STATS_INCR(kcm->stats.tx_msgs);
98e3862ca2b1ae WANG Cong         2017-02-07  903  		}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  904  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  905  		if (msg->msg_flags & MSG_BATCH) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  906  			kcm->tx_wait_more = true;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  907  		} else if (kcm->tx_wait_more || not_busy) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  908  			err = kcm_write_msgs(kcm);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  909  			if (err < 0) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  910  				/* We got a hard error in write_msgs but have
ab7ac4eb9832e3 Tom Herbert       2016-03-07  911  				 * already queued this message. Report an error
ab7ac4eb9832e3 Tom Herbert       2016-03-07  912  				 * in the socket, but don't affect return value
ab7ac4eb9832e3 Tom Herbert       2016-03-07  913  				 * from sendmsg
ab7ac4eb9832e3 Tom Herbert       2016-03-07  914  				 */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  915  				pr_warn("KCM: Hard failure on kcm_write_msgs\n");
ab7ac4eb9832e3 Tom Herbert       2016-03-07  916  				report_csk_error(&kcm->sk, -err);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  917  			}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  918  		}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  919  	} else {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  920  		/* Message not complete, save state */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  921  partial_message:
cd27b96bc13841 WANG Cong         2017-02-13  922  		if (head) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  923  			kcm->seq_skb = head;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  924  			kcm_tx_msg(head)->last_skb = skb;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  925  		}
cd27b96bc13841 WANG Cong         2017-02-13  926  	}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  927  
cd6e111bf5be5c Tom Herbert       2016-03-07  928  	KCM_STATS_ADD(kcm->stats.tx_bytes, copied);
cd6e111bf5be5c Tom Herbert       2016-03-07  929  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  930  	release_sock(sk);
807067bf014d4a Kuniyuki Iwashima 2024-08-15  931  	mutex_unlock(&kcm->tx_mutex);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  932  	return copied;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  933  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  934  out_error:
ab7ac4eb9832e3 Tom Herbert       2016-03-07  935  	kcm_push(kcm);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  936  
3d264f513af54f Jiayuan Chen      2026-02-13  937  	/* When MAX_SKB_FRAGS was reached, a new skb was allocated and
3d264f513af54f Jiayuan Chen      2026-02-13  938  	 * linked into the frag_list before data copy. If the copy
3d264f513af54f Jiayuan Chen      2026-02-13  939  	 * subsequently failed, this skb has zero frags. Remove it from
3d264f513af54f Jiayuan Chen      2026-02-13  940  	 * the frag_list to prevent kcm_write_msgs from later hitting
3d264f513af54f Jiayuan Chen      2026-02-13  941  	 * WARN_ON(!skb_shinfo(skb)->nr_frags).
3d264f513af54f Jiayuan Chen      2026-02-13  942  	 */
3d264f513af54f Jiayuan Chen      2026-02-13  943  	if (frag_prev && !skb_shinfo(skb)->nr_frags) {
3d264f513af54f Jiayuan Chen      2026-02-13  944  		if (head == frag_prev)
3d264f513af54f Jiayuan Chen      2026-02-13 @945  			skb_shinfo(head)->frag_list = NULL;
3d264f513af54f Jiayuan Chen      2026-02-13  946  		else
3d264f513af54f Jiayuan Chen      2026-02-13  947  			frag_prev->next = NULL;
3d264f513af54f Jiayuan Chen      2026-02-13  948  		kfree_skb(skb);
3d264f513af54f Jiayuan Chen      2026-02-13  949  		/* Update skb as it may be saved in partial_message via goto */
3d264f513af54f Jiayuan Chen      2026-02-13  950  		skb = frag_prev;
3d264f513af54f Jiayuan Chen      2026-02-13  951  	}
3d264f513af54f Jiayuan Chen      2026-02-13  952  
a22730b1b4bf43 Kuniyuki Iwashima 2023-09-11  953  	if (sock->type == SOCK_SEQPACKET) {
ab7ac4eb9832e3 Tom Herbert       2016-03-07  954  		/* Wrote some bytes before encountering an
ab7ac4eb9832e3 Tom Herbert       2016-03-07  955  		 * error, return partial success.
ab7ac4eb9832e3 Tom Herbert       2016-03-07  956  		 */
a22730b1b4bf43 Kuniyuki Iwashima 2023-09-11  957  		if (copied)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  958  			goto partial_message;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  959  		if (head != kcm->seq_skb)
ab7ac4eb9832e3 Tom Herbert       2016-03-07  960  			kfree_skb(head);
a22730b1b4bf43 Kuniyuki Iwashima 2023-09-11  961  	} else {
a22730b1b4bf43 Kuniyuki Iwashima 2023-09-11  962  		kfree_skb(head);
a22730b1b4bf43 Kuniyuki Iwashima 2023-09-11  963  		kcm->seq_skb = NULL;
a22730b1b4bf43 Kuniyuki Iwashima 2023-09-11  964  	}
ab7ac4eb9832e3 Tom Herbert       2016-03-07  965  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  966  	err = sk_stream_error(sk, msg->msg_flags, err);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  967  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  968  	/* make sure we wake any epoll edge trigger waiter */
ab7ac4eb9832e3 Tom Herbert       2016-03-07  969  	if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
ab7ac4eb9832e3 Tom Herbert       2016-03-07  970  		sk->sk_write_space(sk);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  971  
ab7ac4eb9832e3 Tom Herbert       2016-03-07  972  	release_sock(sk);
807067bf014d4a Kuniyuki Iwashima 2024-08-15  973  	mutex_unlock(&kcm->tx_mutex);
ab7ac4eb9832e3 Tom Herbert       2016-03-07  974  	return err;
ab7ac4eb9832e3 Tom Herbert       2016-03-07  975  }
ab7ac4eb9832e3 Tom Herbert       2016-03-07  976  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net v1] kcm: fix zero-frag skb in frag_list on partial sendmsg error
  2026-02-13  6:12 [PATCH net v1] kcm: fix zero-frag skb in frag_list on partial sendmsg error Jiayuan Chen
@ 2026-02-17 11:52 ` Paolo Abeni
  2026-02-19  1:40   ` Jiayuan Chen
  0 siblings, 1 reply; 4+ messages in thread
From: Paolo Abeni @ 2026-02-17 11:52 UTC (permalink / raw)
  To: Jiayuan Chen, netdev
  Cc: Jiayuan Chen, syzbot+52624bdfbf2746d37d70, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Simon Horman, Michal Luczaj,
	Sven Stegemann, Christian Brauner, Tom Herbert, linux-kernel

On 2/13/26 7:12 AM, Jiayuan Chen wrote:
> From: Jiayuan Chen <jiayuan.chen@shopee.com>
> 
> Syzkaller reported a warning in kcm_write_msgs() when processing a
> message with a zero-fragment skb in the frag_list.
> 
> When kcm_sendmsg() fills MAX_SKB_FRAGS fragments in the current skb,
> it allocates a new skb (tskb) and links it into the frag_list before
> copying data. If the copy subsequently fails (e.g. -EFAULT from
> user memory), tskb remains in the frag_list with zero fragments:
> 
>   head skb (msg being assembled, NOT yet in sk_write_queue)
>   +-----------+
>   | frags[17] |  (MAX_SKB_FRAGS, all filled with data)
>   | frag_list-+--> tskb
>   +-----------+    +----------+
>                    | frags[0] |  (empty! copy failed before filling)
>                    +----------+
> 
> For SOCK_SEQPACKET with partial data already copied, the error path
> saves this message via partial_message for later completion. A
> subsequent zero-length write(fd, NULL, 0) implies MSG_EOR, which
> queues the message to sk_write_queue.

AI review noted that the above statement is dubious. Specifically,
looking it looks like that write(fd, NULL, 0) implies EOR for SOCK_DGRAM
packets:

	int eor = (sock->type == SOCK_DGRAM) ?
		  !(msg->msg_flags & MSG_MORE) : !!(msg->msg_flags & MSG_EOR);

I guess the changelog needs some clarification.

Thanks,

Paolo


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net v1] kcm: fix zero-frag skb in frag_list on partial sendmsg error
  2026-02-17 11:52 ` Paolo Abeni
@ 2026-02-19  1:40   ` Jiayuan Chen
  0 siblings, 0 replies; 4+ messages in thread
From: Jiayuan Chen @ 2026-02-19  1:40 UTC (permalink / raw)
  To: Paolo Abeni, netdev
  Cc: Jiayuan Chen, syzbot+52624bdfbf2746d37d70, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Simon Horman, Michal Luczaj,
	Sven Stegemann, Christian Brauner, Tom Herbert, linux-kernel

2026/2/17 19:52, "Paolo Abeni" <pabeni@redhat.com mailto:pabeni@redhat.com?to=%22Paolo%20Abeni%22%20%3Cpabeni%40redhat.com%3E > wrote:


> 
> On 2/13/26 7:12 AM, Jiayuan Chen wrote:
> 
> > 
> > From: Jiayuan Chen <jiayuan.chen@shopee.com>
> >  
> >  Syzkaller reported a warning in kcm_write_msgs() when processing a
> >  message with a zero-fragment skb in the frag_list.
> >  
> >  When kcm_sendmsg() fills MAX_SKB_FRAGS fragments in the current skb,
> >  it allocates a new skb (tskb) and links it into the frag_list before
> >  copying data. If the copy subsequently fails (e.g. -EFAULT from
> >  user memory), tskb remains in the frag_list with zero fragments:
> >  
> >  head skb (msg being assembled, NOT yet in sk_write_queue)
> >  +-----------+
> >  | frags[17] | (MAX_SKB_FRAGS, all filled with data)
> >  | frag_list-+--> tskb
> >  +-----------+ +----------+
> >  | frags[0] | (empty! copy failed before filling)
> >  +----------+
> >  
> >  For SOCK_SEQPACKET with partial data already copied, the error path
> >  saves this message via partial_message for later completion. A
> >  subsequent zero-length write(fd, NULL, 0) implies MSG_EOR, which
> >  queues the message to sk_write_queue.
> > 
> AI review noted that the above statement is dubious. Specifically,
> looking it looks like that write(fd, NULL, 0) implies EOR for SOCK_DGRAM
> packets:
> 
>  int eor = (sock->type == SOCK_DGRAM) ?
>  !(msg->msg_flags & MSG_MORE) : !!(msg->msg_flags & MSG_EOR);
> 
> I guess the changelog needs some clarification.
> 
> Thanks,
> 
> Paolo
>

Thanks for pointing this out. I'll update the changelog to clarify that
for SOCK_SEQPACKET, sock_write_iter() automatically sets MSG_EOR
(net/socket.c:1189), which is what makes the subsequent write()
complete the message.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-02-19  1:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-13  6:12 [PATCH net v1] kcm: fix zero-frag skb in frag_list on partial sendmsg error Jiayuan Chen
2026-02-17 11:52 ` Paolo Abeni
2026-02-19  1:40   ` Jiayuan Chen
  -- strict thread matches above, loose matches on Subject: below --
2026-02-13 13:39 kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.