Commit ccb49100 authored by Steffen Klassert's avatar Steffen Klassert Committed by Zheng Zengkai
Browse files

esp: Fix possible buffer overflow in ESP transformation

mainline inclusion
from mainline
commit ebe48d36
category: bugfix
bugzilla: 186409, https://gitee.com/openeuler/kernel/issues/I4YXSX


CVE: CVE-2022-0886

--------------------------------

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: cac2661c ("esp4: Avoid skb_cow_data whenever possible")
Fixes: 03e2a30f ("esp6: Avoid skb_cow_data whenever possible")
Reported-by: default avatarvalis <sec@valis.email>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: default avatarXu Jia <xujia39@huawei.com>
Reviewed-by: default avatarWei Yongjun <weiyongjun1@huawei.com>
Reviewed-by: default avatarXiu Jianfeng <xiujianfeng@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 87b23cd4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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)
+5 −0
Original line number Diff line number Diff line
@@ -448,6 +448,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 TCP/UDP Encapsulation */
	if (x->encap) {
@@ -457,6 +458,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;
+5 −0
Original line number Diff line number Diff line
@@ -483,6 +483,7 @@ 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);
@@ -491,6 +492,10 @@ 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)
		goto cow;

	if (!skb_cloned(skb)) {
		if (tailen <= skb_tailroom(skb)) {
			nfrags = 1;