FAILED: patch "[PATCH] kcm: close race conditions on sk_receive_queue" failed to apply to 4.9-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.9-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Possible dependencies:
5121197ecc5d ("kcm: close race conditions on sk_receive_queue") bbb03029a899 ("strparser: Generalize strparser")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 5121197ecc5db58c07da95eb1ff82b98b121a221 Mon Sep 17 00:00:00 2001
From: Cong Wang <[email protected]>
Date: Sun, 13 Nov 2022 16:51:19 -0800
Subject: [PATCH] kcm: close race conditions on sk_receive_queue
sk->sk_receive_queue is protected by skb queue lock, but for KCM sockets its RX path takes mux->rx_lock to protect more than just skb queue. However, kcm_recvmsg() still only grabs the skb queue lock, so race conditions still exist.
We can teach kcm_recvmsg() to grab mux->rx_lock too but this would introduce a potential performance regression as struct kcm_mux can be shared by multiple KCM sockets.
So we have to enforce skb queue lock in requeue_rx_msgs() and handle skb peek case carefully in kcm_wait_data(). Fortunately, skb_recv_datagram() already handles it nicely and is widely used by other sockets, we can just switch to skb_recv_datagram() after getting rid of the unnecessary sock lock in kcm_recvmsg() and kcm_splice_read(). Side note: SOCK_DONE is not used by KCM sockets, so it is safe to get rid of this check too.
I ran the original syzbot reproducer for 30 min without seeing any issue.
net/kcm/kcmsock.c +6 -52
@@ -222,7 +222,7 @@ static void requeue_rx_msgs(struct kcm_mux *mux, struct sk_buff_head *head)struct sk_buff *skb;struct kcm_sock *kcm; -while ((skb =__skb_dequeue (head))) { +while ((skb =skb_dequeue (head))) {/* Reset destructor to avoid calling kcm_rcv_ready */ skb->destructor = sock_rfree;skb_orphan (skb);
@@ -1085,53 +1085,17 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)return err; } -static struct sk_buff *kcm_wait_data (struct sock *sk,int flags, -long timeo,int *err) -{ -struct sk_buff *skb; - -while (!(skb =skb_peek (&sk->sk_receive_queue))) { -if (sk->sk_err) { - *err =sock_error (sk); -return NULL ; - } - -if (sock_flag (sk,SOCK_DONE )) -return NULL ; - -if ((flags &MSG_DONTWAIT ) || !timeo) { - *err = -EAGAIN ; -return NULL ; - } - -sk_wait_data (sk, &timeo,NULL ); - -/* Handle signals */ -if (signal_pending (current)) { - *err =sock_intr_errno (timeo); -return NULL ; - } - } - -return skb; -} -static int kcm_recvmsg (struct socket *sock,struct msghdr *msg,size_t len,int flags) {struct sock *sk = sock->sk;struct kcm_sock *kcm =kcm_sk (sk);int err =0 ; -long timeo;struct strp_msg *stm;int copied =0 ;struct sk_buff *skb; - timeo =sock_rcvtimeo (sk, flags &MSG_DONTWAIT ); - -lock_sock (sk); - - skb =kcm_wait_data (sk, flags, timeo, &err); + skb =skb_recv_datagram (sk, flags, &err);if (!skb) goto out;
@@ -1162,14 +1126,11 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,/* Finished with message */ msg->msg_flags |=MSG_EOR ;KCM_STATS_INCR (kcm->stats.rx_msgs); -skb_unlink (skb, &sk->sk_receive_queue); -kfree_skb (skb); } } out: -release_sock (sk); - +skb_free_datagram (sk, skb);return copied ? : err; }
@@ -1179,7 +1140,6 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos, {struct sock *sk = sock->sk;struct kcm_sock *kcm =kcm_sk (sk); -long timeo;struct strp_msg *stm;int err =0 ;ssize_t copied;
@@ -1187,11 +1147,7 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,/* Only support splice for SOCKSEQPACKET */ - timeo =sock_rcvtimeo (sk, flags &MSG_DONTWAIT ); - -lock_sock (sk); - - skb =kcm_wait_data (sk, flags, timeo, &err); + skb =skb_recv_datagram (sk, flags, &err);if (!skb) goto err_out;
@@ -1219,13 +1175,11 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,* finish reading the message. */ -release_sock (sk); - +skb_free_datagram (sk, skb);return copied; err_out: -release_sock (sk); - +skb_free_datagram (sk, skb);return err; }