* [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.