Commit c31c696f authored by Wang Yufen's avatar Wang Yufen Committed by Zheng Zengkai
Browse files

tcp_comp: Del compressed_data and remaining_data from tcp_comp_context_rx

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I48H9Z?from=project-issue


CVE: NA

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

The compressed data and decompressed data is separated. There is no need to save
the uncompressed data to remaining_data buffer, can directly read data from the
uncompressed skb.

Signed-off-by: default avatarWang Yufen <wangyufen@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: default avatarLu Wei <luwei32@huawei.com>
Reviewed-by: default avatarWei Yongjun <weiyongjun1@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent c5f3ee69
Loading
Loading
Loading
Loading
+30 −68
Original line number Diff line number Diff line
@@ -38,10 +38,7 @@ struct tcp_comp_context_rx {
	ZSTD_DStream *dstream;
	void *dworkspace;
	void *plaintext_data;
	void *compressed_data;
	void *remaining_data;

	size_t data_offset;
	struct strparser strp;
	void (*saved_data_ready)(struct sock *sk);
	struct sk_buff *pkt;
@@ -549,24 +546,8 @@ static int tcp_comp_rx_context_init(struct tcp_comp_context *ctx)
	if (!ctx->rx.plaintext_data)
		goto err_dstream;

	ctx->rx.compressed_data = kvmalloc(TCP_COMP_MAX_CSIZE, GFP_KERNEL);
	if (!ctx->rx.compressed_data)
		goto err_compressed;

	ctx->rx.remaining_data = kvmalloc(TCP_COMP_MAX_CSIZE, GFP_KERNEL);
	if (!ctx->rx.remaining_data)
		goto err_remaining;

	ctx->rx.data_offset = 0;

	return 0;

err_remaining:
	kvfree(ctx->rx.compressed_data);
	ctx->rx.compressed_data = NULL;
err_compressed:
	kvfree(ctx->rx.plaintext_data);
	ctx->rx.plaintext_data = NULL;
err_dstream:
	kfree(ctx->rx.dworkspace);
	ctx->rx.dworkspace = NULL;
@@ -588,11 +569,12 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb, int flags)
{
	struct tcp_comp_context *ctx = comp_get_ctx(sk);
	struct strp_msg *rxm = strp_msg(skb);
	const int plen = skb->len;
	size_t ret, compressed_len = 0;
	int nr_frags_over = 0;
	ZSTD_outBuffer outbuf;
	ZSTD_inBuffer inbuf;
	struct sk_buff *nskb;
	int len;
	int len, plen;
	void *to;

	to = tcp_comp_get_rx_stream(sk);
@@ -602,62 +584,54 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb, int flags)
	if (skb_linearize_cow(skb))
		return -ENOMEM;

	if (plen + ctx->rx.data_offset > TCP_COMP_MAX_CSIZE)
		return -ENOMEM;

	nskb = skb_copy(skb, GFP_KERNEL);
	if (!nskb)
		return -ENOMEM;

	if (ctx->rx.data_offset)
		memcpy(ctx->rx.compressed_data, ctx->rx.remaining_data,
		       ctx->rx.data_offset);
	while (compressed_len < (skb->len - rxm->offset)) {
		len = 0;
		plen = skb->len - rxm->offset - compressed_len;
		if (plen > TCP_COMP_MAX_CSIZE)
			plen = TCP_COMP_MAX_CSIZE;

	memcpy((char *)ctx->rx.compressed_data + ctx->rx.data_offset,
	       (char *)skb->data + rxm->offset, plen - rxm->offset);

	inbuf.src = ctx->rx.compressed_data;
		inbuf.src = (char *)skb->data + rxm->offset + compressed_len;
		inbuf.pos = 0;
	inbuf.size = plen - rxm->offset + ctx->rx.data_offset;
	ctx->rx.data_offset = 0;
		inbuf.size = plen;

		outbuf.dst = ctx->rx.plaintext_data;
		outbuf.pos = 0;
		outbuf.size = TCP_COMP_MAX_CSIZE * 32;

	while (1) {
		size_t ret;

		to = outbuf.dst;
		ret = ZSTD_decompressStream(ctx->rx.dstream, &outbuf, &inbuf);
		if (ZSTD_isError(ret)) {
			kfree_skb(nskb);
			return -EIO;
		}

		len = outbuf.pos - plen;
		if (!compressed_len) {
			len = outbuf.pos - skb->len;
			if (len > skb_tailroom(nskb))
				len = skb_tailroom(nskb);

			__skb_put(nskb, len);

		len += plen;
			len += skb->len;
			skb_copy_to_linear_data(nskb, to, len);
		}

		while ((to += len, outbuf.pos -= len) > 0) {
			struct page *pages;
			skb_frag_t *frag;

			if (WARN_ON(skb_shinfo(nskb)->nr_frags >= MAX_SKB_FRAGS)) {
				kfree_skb(nskb);
				return -EMSGSIZE;
			if (skb_shinfo(nskb)->nr_frags >= MAX_SKB_FRAGS) {
				nr_frags_over = 1;
				break;
			}

			frag = skb_shinfo(nskb)->frags +
			       skb_shinfo(nskb)->nr_frags;
			pages = alloc_pages(__GFP_NOWARN | GFP_KERNEL | __GFP_COMP,
					    TCP_COMP_ALLOC_ORDER);

			if (!pages) {
				kfree_skb(nskb);
				return -ENOMEM;
@@ -678,25 +652,17 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb, int flags)
			skb_shinfo(nskb)->nr_frags++;
		}

		if (ret == 0)
		if (nr_frags_over)
			break;

		if (inbuf.pos >= plen || !inbuf.pos) {
			if (inbuf.pos < inbuf.size) {
				memcpy((char *)ctx->rx.remaining_data,
				       (char *)inbuf.src + inbuf.pos,
				       inbuf.size - inbuf.pos);
				ctx->rx.data_offset = inbuf.size - inbuf.pos;
			}
			break;
		}
		compressed_len += inbuf.pos;
	}

	ctx->rx.dpkt = nskb;
	rxm = strp_msg(nskb);
	rxm->full_len = nskb->len;
	rxm->offset = 0;
	comp_advance_skb(sk, skb, plen - rxm->offset);
	comp_advance_skb(sk, skb, compressed_len);

	return 0;
}
@@ -734,6 +700,7 @@ static int tcp_comp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
				goto recv_end;
			}
		}

		skb = ctx->rx.dpkt;
		rxm = strp_msg(skb);
		chunk = min_t(unsigned int, rxm->full_len, len);
@@ -885,12 +852,6 @@ static void tcp_comp_context_rx_free(struct tcp_comp_context *ctx)

	kvfree(ctx->rx.plaintext_data);
	ctx->rx.plaintext_data = NULL;

	kvfree(ctx->rx.compressed_data);
	ctx->rx.compressed_data = NULL;

	kvfree(ctx->rx.remaining_data);
	ctx->rx.remaining_data = NULL;
}

static void tcp_comp_context_free(struct rcu_head *head)
@@ -917,6 +878,7 @@ void tcp_cleanup_compression(struct sock *sk)
		kfree_skb(ctx->rx.pkt);
		ctx->rx.pkt = NULL;
	}

	if (ctx->rx.dpkt) {
		kfree_skb(ctx->rx.dpkt);
		ctx->rx.dpkt = NULL;