Commit 58ab57d4 authored by Lu Wei's avatar Lu Wei Committed by Zheng Zengkai
Browse files

tcp_comp: Fix receives err when server receives a large packet

hulk inclusion
category: bugfix
bugzilla: 186745, https://gitee.com/openeuler/kernel/issues/I60M9A


CVE: NA

----------------------------------------

When tcp compression is uses, if server receives a large packet,
which is larger than PAGE_SIZES * MAX_SKB_FRAGS bytes, it needs
more than one skb to store the data since one skb can only store
PAGE_SIZES * MAX_SKB_FRAGS bytes data.
    In function tcp_comp_decompress(), it breaks the while-loop
which copy decompressed data to new skb when more than MAX_SKB_FRAGS
pages is needed, causing part of data is copied into the new skb and
received by user but the compressed_len is not added. In this case,
the data will be decompressed infinitely.
    The patch limits the decompressed length so it can be copied
into one skb. Moreover, once a skb is full, quit decompress process
directly.

Fixes: c31c696f ("tcp_comp: Del compressed_data and remaining_data from tcp_comp_context_rx")
Signed-off-by: default avatarLu Wei <luwei32@huawei.com>
Reviewed-by: default avatarYue Haibing <yuehaibing@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent d38abaf8
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -9,9 +9,10 @@
#include <linux/zstd.h>

#define TCP_COMP_MAX_PADDING	64
#define TCP_COMP_SCRATCH_SIZE	65535
#define TCP_COMP_DATA_SIZE	65536
#define TCP_COMP_SCRATCH_SIZE	(TCP_COMP_DATA_SIZE - 1)
#define TCP_COMP_MAX_CSIZE	(TCP_COMP_SCRATCH_SIZE + TCP_COMP_MAX_PADDING)
#define TCP_COMP_ALLOC_ORDER   get_order(65536)
#define TCP_COMP_ALLOC_ORDER   get_order(TCP_COMP_DATA_SIZE)
#define TCP_COMP_MAX_WINDOWLOG 17
#define TCP_COMP_MAX_INPUT (1 << TCP_COMP_MAX_WINDOWLOG)

@@ -589,6 +590,9 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb, int flags)
		return -ENOMEM;

	while (compressed_len < (skb->len - rxm->offset)) {
		if (skb_shinfo(nskb)->nr_frags >= MAX_SKB_FRAGS)
			break;

		len = 0;
		plen = skb->len - rxm->offset - compressed_len;
		if (plen > TCP_COMP_MAX_CSIZE)
@@ -600,7 +604,8 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb, int flags)

		outbuf.dst = ctx->rx.plaintext_data;
		outbuf.pos = 0;
		outbuf.size = TCP_COMP_MAX_CSIZE * 32;
		outbuf.size = MAX_SKB_FRAGS * TCP_COMP_DATA_SIZE;
		outbuf.size -= skb_shinfo(nskb)->nr_frags * TCP_COMP_DATA_SIZE;

		ret = ZSTD_decompressStream(ctx->rx.dstream, &outbuf, &inbuf);
		if (ZSTD_isError(ret)) {