]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
esp: limit skb_page_frag_refill use to a single page
authorSabrina Dubroca <sd@queasysnail.net>
Wed, 13 Apr 2022 08:10:50 +0000 (10:10 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Jul 2022 14:27:27 +0000 (16:27 +0200)
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>
include/net/esp.h
net/ipv4/esp4.c
net/ipv6/esp6.c

index 465e38890ee986023fd7502d0abeb80bca3182a5..117652eb6ea32a836cd269f01e70f0e3c990fbc7 100644 (file)
@@ -4,8 +4,6 @@
 
 #include <linux/skbuff.h>
 
-#define ESP_SKB_FRAG_MAXSIZE (PAGE_SIZE << SKB_FRAG_PAGE_ORDER)
-
 struct ip_esp_hdr;
 
 static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb)
index 38e2aa2b2a31c8fd05c45b7b5a4bb25808c8e622..d5e860573ecd409e7e75072caa7aa7cae6909e20 100644 (file)
@@ -257,7 +257,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) {
@@ -267,8 +266,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)) {
index a9baf562bb9b92a5597591c8d592108cb8e5d842..e19624245e16755b87a4b86aff45fbfdeac1c3db 100644 (file)
@@ -223,10 +223,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)) {