Skip to content

Commit

Permalink
esp: limit skb_page_frag_refill use to a single page
Browse files Browse the repository at this point in the history
[ Upstream commit 5bd8baa ]

Commit ebe48d3 ("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: cac2661 ("esp4: Avoid skb_cow_data whenever possible")
Fixes: 03e2a30 ("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: Sasha Levin <sashal@kernel.org>
  • Loading branch information
qsn authored and gregkh committed Apr 27, 2022
1 parent 3f7914d commit c075c3e
Show file tree
Hide file tree
Showing 3 changed files with 4 additions and 8 deletions.
2 changes: 0 additions & 2 deletions include/net/esp.h
Expand Up @@ -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)
Expand Down
5 changes: 2 additions & 3 deletions net/ipv4/esp4.c
Expand Up @@ -448,7 +448,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 TCP/UDP Encapsulation */
if (x->encap) {
Expand All @@ -458,8 +457,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)) {
Expand Down
5 changes: 2 additions & 3 deletions net/ipv6/esp6.c
Expand Up @@ -483,7 +483,6 @@ 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;

if (x->encap) {
int err = esp6_output_encap(x, skb, esp);
Expand All @@ -492,8 +491,8 @@ int esp6_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)) {
Expand Down

0 comments on commit c075c3e

Please sign in to comment.