Lu Wei (1): tcp_comp: Fix receives err when server receives a large packet
Wang Yufen (5): tcp_comp: Avoiding the null pointer problem of ctx in comp_stream_read tcp_comp: Fix comp_read_size return value tcp_comp: Fix ZSTD_decompressStream failed tcp_comp: Add dpkt to save decompressed skb tcp_comp: Del compressed_data and remaining_data from tcp_comp_context_rx
net/ipv4/tcp_comp.c | 193 ++++++++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 95 deletions(-)
From: Wang Yufen wangyufen@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I45UYC?from=project-issue CVE: NA
-------------------------------------------------
In comp_stream_read ctx might be null, add null check to avoid oops. And delete unnecessary tcp_comp_err_abort.
Signed-off-by: Wang Yufen wangyufen@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com --- net/ipv4/tcp_comp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/tcp_comp.c b/net/ipv4/tcp_comp.c index 1e5e00369f88..739e59036e25 100644 --- a/net/ipv4/tcp_comp.c +++ b/net/ipv4/tcp_comp.c @@ -697,8 +697,6 @@ static int tcp_comp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, if (!ctx->rx.decompressed) { err = tcp_comp_decompress(sk, skb); if (err < 0) { - if (err != -ENOSPC) - tcp_comp_err_abort(sk, EBADMSG); goto recv_end; } ctx->rx.decompressed = true; @@ -732,6 +730,9 @@ bool comp_stream_read(struct sock *sk) { struct tcp_comp_context *ctx = comp_get_ctx(sk);
+ if (!ctx) + return false; + if (ctx->rx.pkt) return true;
From: Wang Yufen wangyufen@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I47SV5?from=project-issue CVE: NA
-------------------------------------------------
In comp_read_size rxm->offset should be subtracted from skb->len. And use strp_done to release resoureces when destroy sock.
Signed-off-by: Wang Yufen wangyufen@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com --- net/ipv4/tcp_comp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/tcp_comp.c b/net/ipv4/tcp_comp.c index 739e59036e25..bbb635284af4 100644 --- a/net/ipv4/tcp_comp.c +++ b/net/ipv4/tcp_comp.c @@ -763,7 +763,7 @@ static int comp_read_size(struct strparser *strp, struct sk_buff *skb) if (rxm->offset > skb->len) return 0;
- return skb->len; + return skb->len - rxm->offset; }
void comp_setup_strp(struct sock *sk, struct tcp_comp_context *ctx) @@ -870,6 +870,7 @@ static void tcp_comp_context_free(struct rcu_head *head)
tcp_comp_context_tx_free(ctx); tcp_comp_context_rx_free(ctx); + strp_done(&ctx->rx.strp); kfree(ctx); }
@@ -885,6 +886,7 @@ void tcp_cleanup_compression(struct sock *sk) kfree_skb(ctx->rx.pkt); ctx->rx.pkt = NULL; } + strp_stop(&ctx->rx.strp);
rcu_assign_pointer(icsk->icsk_ulp_data, NULL); call_rcu(&ctx->rcu, tcp_comp_context_free);
From: Wang Yufen wangyufen@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I48H9Z?from=project-issue CVE: NA
-------------------------------------------------
This patch fixes possible ZSTD_decompressStream failures. When decompressing skb->data, should skip the previous rxm->offset data.
Signed-off-by: Wang Yufen wangyufen@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com --- net/ipv4/tcp_comp.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/net/ipv4/tcp_comp.c b/net/ipv4/tcp_comp.c index bbb635284af4..fe9451984fdb 100644 --- a/net/ipv4/tcp_comp.c +++ b/net/ipv4/tcp_comp.c @@ -569,8 +569,8 @@ static void *tcp_comp_get_rx_stream(struct sock *sk) static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb) { struct tcp_comp_context *ctx = comp_get_ctx(sk); + struct strp_msg *rxm = strp_msg(skb); const int plen = skb->len; - struct strp_msg *rxm; ZSTD_outBuffer outbuf; ZSTD_inBuffer inbuf; int len; @@ -591,11 +591,11 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb) ctx->rx.data_offset);
memcpy((char *)ctx->rx.compressed_data + ctx->rx.data_offset, - skb->data, plen); + (char *)skb->data + rxm->offset, plen - rxm->offset);
inbuf.src = ctx->rx.compressed_data; inbuf.pos = 0; - inbuf.size = plen + ctx->rx.data_offset; + inbuf.size = plen - rxm->offset + ctx->rx.data_offset; ctx->rx.data_offset = 0;
outbuf.dst = ctx->rx.plaintext_data; @@ -606,7 +606,6 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb) size_t ret;
to = outbuf.dst; - ret = ZSTD_decompressStream(ctx->rx.dstream, &outbuf, &inbuf); if (ZSTD_isError(ret)) return -EIO; @@ -616,8 +615,8 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb) len = skb_tailroom(skb);
__skb_put(skb, len); - rxm = strp_msg(skb); - rxm->full_len += len; + rxm->full_len += (len + rxm->offset); + rxm->offset = 0;
len += plen; skb_copy_to_linear_data(skb, to, len);
From: Wang Yufen wangyufen@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I48H9Z?from=project-issue CVE: NA
-------------------------------------------------
In order to separate the compressed data and decompressed data, this patch adds dpkt to tcp_comp_context_rx, dpkt is used to save decompressed skb.
Signed-off-by: Wang Yufen wangyufen@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com --- net/ipv4/tcp_comp.c | 94 ++++++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 30 deletions(-)
diff --git a/net/ipv4/tcp_comp.c b/net/ipv4/tcp_comp.c index fe9451984fdb..531c90210493 100644 --- a/net/ipv4/tcp_comp.c +++ b/net/ipv4/tcp_comp.c @@ -45,7 +45,7 @@ struct tcp_comp_context_rx { struct strparser strp; void (*saved_data_ready)(struct sock *sk); struct sk_buff *pkt; - bool decompressed; + struct sk_buff *dpkt; };
struct tcp_comp_context { @@ -510,6 +510,24 @@ static bool comp_advance_skb(struct sock *sk, struct sk_buff *skb, return true; }
+static bool comp_advance_dskb(struct sock *sk, struct sk_buff *skb, + unsigned int len) +{ + struct tcp_comp_context *ctx = comp_get_ctx(sk); + struct strp_msg *rxm = strp_msg(skb); + + if (len < rxm->full_len) { + rxm->offset += len; + rxm->full_len -= len; + return false; + } + + /* Finished with message */ + ctx->rx.dpkt = NULL; + kfree_skb(skb); + return true; +} + static int tcp_comp_rx_context_init(struct tcp_comp_context *ctx) { int dsize; @@ -566,13 +584,14 @@ static void *tcp_comp_get_rx_stream(struct sock *sk) return ctx->rx.plaintext_data; }
-static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb) +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; ZSTD_outBuffer outbuf; ZSTD_inBuffer inbuf; + struct sk_buff *nskb; int len; void *to;
@@ -586,6 +605,10 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb) 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); @@ -607,34 +630,38 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb)
to = outbuf.dst; ret = ZSTD_decompressStream(ctx->rx.dstream, &outbuf, &inbuf); - if (ZSTD_isError(ret)) + if (ZSTD_isError(ret)) { + kfree_skb(nskb); return -EIO; + }
len = outbuf.pos - plen; - if (len > skb_tailroom(skb)) - len = skb_tailroom(skb); + if (len > skb_tailroom(nskb)) + len = skb_tailroom(nskb);
- __skb_put(skb, len); - rxm->full_len += (len + rxm->offset); - rxm->offset = 0; + __skb_put(nskb, len);
len += plen; - skb_copy_to_linear_data(skb, to, 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(skb)->nr_frags >= MAX_SKB_FRAGS)) + if (WARN_ON(skb_shinfo(nskb)->nr_frags >= MAX_SKB_FRAGS)) { + kfree_skb(nskb); return -EMSGSIZE; + }
- frag = skb_shinfo(skb)->frags + - skb_shinfo(skb)->nr_frags; + 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) + if (!pages) { + kfree_skb(nskb); return -ENOMEM; + }
__skb_frag_set_page(frag, pages); len = PAGE_SIZE << TCP_COMP_ALLOC_ORDER; @@ -645,11 +672,10 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb) skb_frag_size_set(frag, len); memcpy(skb_frag_address(frag), to, len);
- skb->truesize += len; - skb->data_len += len; - skb->len += len; - rxm->full_len += len; - skb_shinfo(skb)->nr_frags++; + nskb->truesize += len; + nskb->data_len += len; + nskb->len += len; + skb_shinfo(nskb)->nr_frags++; }
if (ret == 0) @@ -665,6 +691,13 @@ static int tcp_comp_decompress(struct sock *sk, struct sk_buff *skb) break; } } + + ctx->rx.dpkt = nskb; + rxm = strp_msg(nskb); + rxm->full_len = nskb->len; + rxm->offset = 0; + comp_advance_skb(sk, skb, plen - rxm->offset); + return 0; }
@@ -689,21 +722,19 @@ static int tcp_comp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, do { int chunk = 0;
- skb = comp_wait_data(sk, flags, timeo, &err); - if (!skb) - goto recv_end; + if (!ctx->rx.dpkt) { + skb = comp_wait_data(sk, flags, timeo, &err); + if (!skb) + goto recv_end;
- if (!ctx->rx.decompressed) { - err = tcp_comp_decompress(sk, skb); + err = tcp_comp_decompress(sk, skb, flags); if (err < 0) { goto recv_end; } - ctx->rx.decompressed = true; } + skb = ctx->rx.dpkt; rxm = strp_msg(skb); - chunk = min_t(unsigned int, rxm->full_len, len); - err = skb_copy_datagram_msg(skb, rxm->offset, msg, chunk); if (err < 0) @@ -712,11 +743,11 @@ static int tcp_comp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, copied += chunk; len -= chunk; if (likely(!(flags & MSG_PEEK))) - comp_advance_skb(sk, skb, chunk); + comp_advance_dskb(sk, skb, chunk); else break;
- if (copied >= target && !ctx->rx.pkt) + if (copied >= target && !ctx->rx.dpkt) break; } while (len > 0);
@@ -732,7 +763,7 @@ bool comp_stream_read(struct sock *sk) if (!ctx) return false;
- if (ctx->rx.pkt) + if (ctx->rx.pkt || ctx->rx.dpkt) return true;
return false; @@ -749,7 +780,6 @@ static void comp_queue(struct strparser *strp, struct sk_buff *skb) { struct tcp_comp_context *ctx = comp_get_ctx(strp->sk);
- ctx->rx.decompressed = false; ctx->rx.pkt = skb; strp_pause(strp); ctx->rx.saved_data_ready(strp->sk); @@ -885,6 +915,10 @@ 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; + } strp_stop(&ctx->rx.strp);
rcu_assign_pointer(icsk->icsk_ulp_data, NULL);
From: Wang Yufen wangyufen@huawei.com
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: Wang Yufen wangyufen@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com --- net/ipv4/tcp_comp.c | 98 ++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 68 deletions(-)
diff --git a/net/ipv4/tcp_comp.c b/net/ipv4/tcp_comp.c index 531c90210493..1c757a132a60 100644 --- a/net/ipv4/tcp_comp.c +++ b/net/ipv4/tcp_comp.c @@ -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); - - 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.pos = 0; - inbuf.size = plen - rxm->offset + ctx->rx.data_offset; - ctx->rx.data_offset = 0; + 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;
- outbuf.dst = ctx->rx.plaintext_data; - outbuf.pos = 0; - outbuf.size = TCP_COMP_MAX_CSIZE * 32; + inbuf.src = (char *)skb->data + rxm->offset + compressed_len; + inbuf.pos = 0; + inbuf.size = plen;
- while (1) { - size_t ret; + outbuf.dst = ctx->rx.plaintext_data; + outbuf.pos = 0; + outbuf.size = TCP_COMP_MAX_CSIZE * 32;
- 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 (len > skb_tailroom(nskb)) - len = skb_tailroom(nskb); + if (!compressed_len) { + len = outbuf.pos - skb->len; + if (len > skb_tailroom(nskb)) + len = skb_tailroom(nskb);
- __skb_put(nskb, len); + __skb_put(nskb, len);
- len += plen; - skb_copy_to_linear_data(nskb, to, len); + 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; } @@ -732,6 +698,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); @@ -883,12 +850,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) @@ -915,6 +876,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;
Offering: HULK hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I60M9A
----------------------------------------
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: c31c696f9300 ("tcp_comp: Del compressed_data and remaining_data from tcp_comp_context_rx") Signed-off-by: Lu Wei luwei32@huawei.com Signed-off-by: Lu Wei luwei32@huawei.com --- net/ipv4/tcp_comp.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/tcp_comp.c b/net/ipv4/tcp_comp.c index 1c757a132a60..dec62ef5c0ef 100644 --- a/net/ipv4/tcp_comp.c +++ b/net/ipv4/tcp_comp.c @@ -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)) {