summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSabrina Dubroca <sd@queasysnail.net>2022-04-13 10:10:50 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-07-12 16:29:00 +0200
commitef6f83df1209a7d9bd1c605a62457d4c00f9179e (patch)
tree3bc7f974b56f15d8b0bb3db48325b53b6080078d /net
parent2283d8a4ecbe13573fad833f4ed6805f72446b2f (diff)
downloadlinux-stable-ef6f83df1209a7d9bd1c605a62457d4c00f9179e.tar.gz
linux-stable-ef6f83df1209a7d9bd1c605a62457d4c00f9179e.tar.bz2
linux-stable-ef6f83df1209a7d9bd1c605a62457d4c00f9179e.zip
esp: limit skb_page_frag_refill use to a single page
commit 5bd8baab087dff657e05387aee802e70304cc813 upstream. Commit ebe48d368e97 ("esp: Fix possible buffer overflow in ESP transformation") tried to fix skb_page_frag_refill usage in ESP by capping allocsize to 32k, but that doesn't completely solve the issue, as skb_page_frag_refill may return a single page. If that happens, we will write out of bounds, despite the check introduced in the previous patch. This patch forces COW in cases where we would end up calling skb_page_frag_refill with a size larger than a page (first in esp_output_head with tailen, then in esp_output_tail with skb->data_len). Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible") Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible") Signed-off-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/esp4.c5
-rw-r--r--net/ipv6/esp6.c5
2 files changed, 4 insertions, 6 deletions
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 45bb5b60b994..203569500b91 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -275,7 +275,6 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
struct page *page;
struct sk_buff *trailer;
int tailen = esp->tailen;
- unsigned int allocsz;
/* this is non-NULL only with UDP Encapsulation */
if (x->encap) {
@@ -285,8 +284,8 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
return err;
}
- allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES);
- if (allocsz > ESP_SKB_FRAG_MAXSIZE)
+ if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE ||
+ ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE)
goto cow;
if (!skb_cloned(skb)) {
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index e3abfc97fde7..d847ffbe9745 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -241,10 +241,9 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
struct page *page;
struct sk_buff *trailer;
int tailen = esp->tailen;
- unsigned int allocsz;
- allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES);
- if (allocsz > ESP_SKB_FRAG_MAXSIZE)
+ if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE ||
+ ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE)
goto cow;
if (!skb_cloned(skb)) {