mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
mptcp: fix MSG_PEEK stream corruption
[ Upstream commit8e04ce45a8] If a MSG_PEEK | MSG_WAITALL read operation consumes all the bytes in the receive queue and recvmsg() need to waits for more data - i.e. it's a blocking one - upon arrival of the next packet the MPTCP protocol will start again copying the oldest data present in the receive queue, corrupting the data stream. Address the issue explicitly tracking the peeked sequence number, restarting from the last peeked byte. Fixes:ca4fb89257("mptcp: add MSG_PEEK support") Cc: stable@vger.kernel.org Signed-off-by: Paolo Abeni <pabeni@redhat.com> Reviewed-by: Geliang Tang <geliang@kernel.org> Tested-by: Geliang Tang <geliang@kernel.org> Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> Link: https://patch.msgid.link/20251028-net-mptcp-send-timeout-v1-2-38ffff5a9ec8@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org> [ Adjust context ] Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
ab9d10109a
commit
0206a9341e
@@ -1977,19 +1977,35 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied);
|
||||
|
||||
static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk,
|
||||
struct msghdr *msg,
|
||||
size_t len, int flags,
|
||||
size_t len, int flags, int copied_total,
|
||||
struct scm_timestamping_internal *tss,
|
||||
int *cmsg_flags)
|
||||
{
|
||||
struct sk_buff *skb, *tmp;
|
||||
int total_data_len = 0;
|
||||
int copied = 0;
|
||||
|
||||
skb_queue_walk_safe(&msk->receive_queue, skb, tmp) {
|
||||
u32 offset = MPTCP_SKB_CB(skb)->offset;
|
||||
u32 delta, offset = MPTCP_SKB_CB(skb)->offset;
|
||||
u32 data_len = skb->len - offset;
|
||||
u32 count = min_t(size_t, len - copied, data_len);
|
||||
u32 count;
|
||||
int err;
|
||||
|
||||
if (flags & MSG_PEEK) {
|
||||
/* skip already peeked skbs */
|
||||
if (total_data_len + data_len <= copied_total) {
|
||||
total_data_len += data_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip the already peeked data in the current skb */
|
||||
delta = copied_total - total_data_len;
|
||||
offset += delta;
|
||||
data_len -= delta;
|
||||
}
|
||||
|
||||
count = min_t(size_t, len - copied, data_len);
|
||||
|
||||
if (!(flags & MSG_TRUNC)) {
|
||||
err = skb_copy_datagram_msg(skb, offset, msg, count);
|
||||
if (unlikely(err < 0)) {
|
||||
@@ -2006,22 +2022,19 @@ static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk,
|
||||
|
||||
copied += count;
|
||||
|
||||
if (count < data_len) {
|
||||
if (!(flags & MSG_PEEK)) {
|
||||
if (!(flags & MSG_PEEK)) {
|
||||
msk->bytes_consumed += count;
|
||||
if (count < data_len) {
|
||||
MPTCP_SKB_CB(skb)->offset += count;
|
||||
MPTCP_SKB_CB(skb)->map_seq += count;
|
||||
msk->bytes_consumed += count;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(flags & MSG_PEEK)) {
|
||||
/* we will bulk release the skb memory later */
|
||||
skb->destructor = NULL;
|
||||
WRITE_ONCE(msk->rmem_released, msk->rmem_released + skb->truesize);
|
||||
__skb_unlink(skb, &msk->receive_queue);
|
||||
__kfree_skb(skb);
|
||||
msk->bytes_consumed += count;
|
||||
}
|
||||
|
||||
if (copied >= len)
|
||||
@@ -2245,7 +2258,8 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||
while (copied < len) {
|
||||
int err, bytes_read;
|
||||
|
||||
bytes_read = __mptcp_recvmsg_mskq(msk, msg, len - copied, flags, &tss, &cmsg_flags);
|
||||
bytes_read = __mptcp_recvmsg_mskq(msk, msg, len - copied, flags,
|
||||
copied, &tss, &cmsg_flags);
|
||||
if (unlikely(bytes_read < 0)) {
|
||||
if (!copied)
|
||||
copied = bytes_read;
|
||||
|
||||
Reference in New Issue
Block a user