Skip to content

Commit 5121197

Browse files
Cong WangPaolo Abeni
authored andcommitted
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. Fixes: ab7ac4e ("kcm: Kernel Connection Multiplexor module") Reported-by: syzbot+278279efdd2730dd14bf@syzkaller.appspotmail.com Reported-by: shaozhengchao <shaozhengchao@huawei.com> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Tom Herbert <tom@herbertland.com> Signed-off-by: Cong Wang <cong.wang@bytedance.com> Link: https://lore.kernel.org/r/20221114005119.597905-1-xiyou.wangcong@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 280c0f7 commit 5121197

File tree

1 file changed

+6
-52
lines changed

1 file changed

+6
-52
lines changed

net/kcm/kcmsock.c

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ static void requeue_rx_msgs(struct kcm_mux *mux, struct sk_buff_head *head)
222222
struct sk_buff *skb;
223223
struct kcm_sock *kcm;
224224

225-
while ((skb = __skb_dequeue(head))) {
225+
while ((skb = skb_dequeue(head))) {
226226
/* Reset destructor to avoid calling kcm_rcv_ready */
227227
skb->destructor = sock_rfree;
228228
skb_orphan(skb);
@@ -1085,53 +1085,17 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
10851085
return err;
10861086
}
10871087

1088-
static struct sk_buff *kcm_wait_data(struct sock *sk, int flags,
1089-
long timeo, int *err)
1090-
{
1091-
struct sk_buff *skb;
1092-
1093-
while (!(skb = skb_peek(&sk->sk_receive_queue))) {
1094-
if (sk->sk_err) {
1095-
*err = sock_error(sk);
1096-
return NULL;
1097-
}
1098-
1099-
if (sock_flag(sk, SOCK_DONE))
1100-
return NULL;
1101-
1102-
if ((flags & MSG_DONTWAIT) || !timeo) {
1103-
*err = -EAGAIN;
1104-
return NULL;
1105-
}
1106-
1107-
sk_wait_data(sk, &timeo, NULL);
1108-
1109-
/* Handle signals */
1110-
if (signal_pending(current)) {
1111-
*err = sock_intr_errno(timeo);
1112-
return NULL;
1113-
}
1114-
}
1115-
1116-
return skb;
1117-
}
1118-
11191088
static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
11201089
size_t len, int flags)
11211090
{
11221091
struct sock *sk = sock->sk;
11231092
struct kcm_sock *kcm = kcm_sk(sk);
11241093
int err = 0;
1125-
long timeo;
11261094
struct strp_msg *stm;
11271095
int copied = 0;
11281096
struct sk_buff *skb;
11291097

1130-
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
1131-
1132-
lock_sock(sk);
1133-
1134-
skb = kcm_wait_data(sk, flags, timeo, &err);
1098+
skb = skb_recv_datagram(sk, flags, &err);
11351099
if (!skb)
11361100
goto out;
11371101

@@ -1162,14 +1126,11 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
11621126
/* Finished with message */
11631127
msg->msg_flags |= MSG_EOR;
11641128
KCM_STATS_INCR(kcm->stats.rx_msgs);
1165-
skb_unlink(skb, &sk->sk_receive_queue);
1166-
kfree_skb(skb);
11671129
}
11681130
}
11691131

11701132
out:
1171-
release_sock(sk);
1172-
1133+
skb_free_datagram(sk, skb);
11731134
return copied ? : err;
11741135
}
11751136

@@ -1179,19 +1140,14 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
11791140
{
11801141
struct sock *sk = sock->sk;
11811142
struct kcm_sock *kcm = kcm_sk(sk);
1182-
long timeo;
11831143
struct strp_msg *stm;
11841144
int err = 0;
11851145
ssize_t copied;
11861146
struct sk_buff *skb;
11871147

11881148
/* Only support splice for SOCKSEQPACKET */
11891149

1190-
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
1191-
1192-
lock_sock(sk);
1193-
1194-
skb = kcm_wait_data(sk, flags, timeo, &err);
1150+
skb = skb_recv_datagram(sk, flags, &err);
11951151
if (!skb)
11961152
goto err_out;
11971153

@@ -1219,13 +1175,11 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
12191175
* finish reading the message.
12201176
*/
12211177

1222-
release_sock(sk);
1223-
1178+
skb_free_datagram(sk, skb);
12241179
return copied;
12251180

12261181
err_out:
1227-
release_sock(sk);
1228-
1182+
skb_free_datagram(sk, skb);
12291183
return err;
12301184
}
12311185

0 commit comments

Comments
 (0)