Message ID | 20220324111455.389344-2-cascardo@canonical.com |
---|---|
State | New |
Headers | show |
Series | [SRU,Bionic] esp: Fix possible buffer overflow in ESP transformation | expand |
Applied to bionic:linux/master-next. Thanks, - Luke On Thu, Mar 24, 2022 at 4:16 AM Thadeu Lima de Souza Cascardo < cascardo@canonical.com> wrote: > From: Steffen Klassert <steffen.klassert@secunet.com> > > The maximum message size that can be send is bigger than > the maximum site that skb_page_frag_refill can allocate. > So it is possible to write beyond the allocated buffer. > > Fix this by doing a fallback to COW in that case. > > v2: > > Avoid get get_order() costs as suggested by Linus Torvalds. > > Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible") > Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible") > Reported-by: valis <sec@valis.email> > Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> > (backported from commit ebe48d368e97d007bfeb76fcb065d6cfc4c96645) > [cascardo: there was not x->encap test on esp6_output_head because of > missing commit > 0146dca70b877b73c5fd9c67912b8a0ca8a7bac7] > [cascardo: add SKB_FRAG_PAGE_ORDER to include/net/sock.h] > CVE-2022-27666 > Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> > --- > include/net/esp.h | 2 ++ > include/net/sock.h | 2 ++ > net/ipv4/esp4.c | 5 +++++ > net/ipv6/esp6.c | 5 +++++ > 4 files changed, 14 insertions(+) > > diff --git a/include/net/esp.h b/include/net/esp.h > index 117652eb6ea3..465e38890ee9 100644 > --- a/include/net/esp.h > +++ b/include/net/esp.h > @@ -4,6 +4,8 @@ > > #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) > diff --git a/include/net/sock.h b/include/net/sock.h > index 79f9b7ee4e45..8dc208d54232 100644 > --- a/include/net/sock.h > +++ b/include/net/sock.h > @@ -2452,6 +2452,8 @@ extern int sysctl_optmem_max; > extern __u32 sysctl_wmem_default; > extern __u32 sysctl_rmem_default; > > +#define SKB_FRAG_PAGE_ORDER get_order(32768) > + > static inline int sk_get_wmem0(const struct sock *sk, const struct proto > *proto) > { > /* Does this proto have per netns sysctl_wmem ? */ > diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c > index d8151c72205f..2dc2887a0e84 100644 > --- a/net/ipv4/esp4.c > +++ b/net/ipv4/esp4.c > @@ -257,6 +257,7 @@ 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) { > @@ -266,6 +267,10 @@ 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) > + goto cow; > + > if (!skb_cloned(skb)) { > if (tailen <= skb_tailroom(skb)) { > nfrags = 1; > diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c > index 3eb167ad1ce6..cbc663756841 100644 > --- a/net/ipv6/esp6.c > +++ b/net/ipv6/esp6.c > @@ -223,6 +223,11 @@ 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) > + goto cow; > > if (!skb_cloned(skb)) { > if (tailen <= skb_tailroom(skb)) { > -- > 2.32.0 > > > -- > kernel-team mailing list > kernel-team@lists.ubuntu.com > https://lists.ubuntu.com/mailman/listinfo/kernel-team >
diff --git a/include/net/esp.h b/include/net/esp.h index 117652eb6ea3..465e38890ee9 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -4,6 +4,8 @@ #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) diff --git a/include/net/sock.h b/include/net/sock.h index 79f9b7ee4e45..8dc208d54232 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2452,6 +2452,8 @@ extern int sysctl_optmem_max; extern __u32 sysctl_wmem_default; extern __u32 sysctl_rmem_default; +#define SKB_FRAG_PAGE_ORDER get_order(32768) + static inline int sk_get_wmem0(const struct sock *sk, const struct proto *proto) { /* Does this proto have per netns sysctl_wmem ? */ diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index d8151c72205f..2dc2887a0e84 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -257,6 +257,7 @@ 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) { @@ -266,6 +267,10 @@ 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) + goto cow; + if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { nfrags = 1; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 3eb167ad1ce6..cbc663756841 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -223,6 +223,11 @@ 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) + goto cow; if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) {