Commit 5bd8baab authored by Sabrina Dubroca's avatar Sabrina Dubroca Committed by Steffen Klassert

esp: limit skb_page_frag_refill use to a single page

Commit ebe48d36 ("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: cac2661c ("esp4: Avoid skb_cow_data whenever possible")
Fixes: 03e2a30f ("esp6: Avoid skb_cow_data whenever possible")
Signed-off-by: default avatarSabrina Dubroca <sd@queasysnail.net>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 748b82c2
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#define ESP_SKB_FRAG_MAXSIZE (PAGE_SIZE << SKB_FRAG_PAGE_ORDER)
struct ip_esp_hdr; struct ip_esp_hdr;
static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb) static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb)
......
...@@ -446,7 +446,6 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * ...@@ -446,7 +446,6 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
struct page *page; struct page *page;
struct sk_buff *trailer; struct sk_buff *trailer;
int tailen = esp->tailen; int tailen = esp->tailen;
unsigned int allocsz;
/* this is non-NULL only with TCP/UDP Encapsulation */ /* this is non-NULL only with TCP/UDP Encapsulation */
if (x->encap) { if (x->encap) {
...@@ -456,8 +455,8 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * ...@@ -456,8 +455,8 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
return err; return err;
} }
allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE ||
if (allocsz > ESP_SKB_FRAG_MAXSIZE) ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE)
goto cow; goto cow;
if (!skb_cloned(skb)) { if (!skb_cloned(skb)) {
......
...@@ -482,7 +482,6 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info ...@@ -482,7 +482,6 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
struct page *page; struct page *page;
struct sk_buff *trailer; struct sk_buff *trailer;
int tailen = esp->tailen; int tailen = esp->tailen;
unsigned int allocsz;
if (x->encap) { if (x->encap) {
int err = esp6_output_encap(x, skb, esp); int err = esp6_output_encap(x, skb, esp);
...@@ -491,8 +490,8 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info ...@@ -491,8 +490,8 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
return err; return err;
} }
allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE ||
if (allocsz > ESP_SKB_FRAG_MAXSIZE) ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE)
goto cow; goto cow;
if (!skb_cloned(skb)) { if (!skb_cloned(skb)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment