提交 3716c262 编写于 作者: S Sabrina Dubroca 提交者: Greg Kroah-Hartman

esp4: add length check for UDP encapsulation

[ Upstream commit 8dfb4eba4100e7cdd161a8baef2d8d61b7a7e62e ]

esp_output_udp_encap can produce a length that doesn't fit in the 16
bits of a UDP header's length field. In that case, we'll send a
fragmented packet whose length is larger than IP_MAX_MTU (resulting in
"Oversized IP packet" warnings on receive) and with a bogus UDP
length.

To prevent this, add a length check to esp_output_udp_encap and return
 -EMSGSIZE on failure.

This seems to be older than git history.
Signed-off-by: NSabrina Dubroca <sd@queasysnail.net>
Signed-off-by: NSteffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: NSasha Levin <sashal@kernel.org>
上级 d410ef75
...@@ -223,7 +223,7 @@ static void esp_output_fill_trailer(u8 *tail, int tfclen, int plen, __u8 proto) ...@@ -223,7 +223,7 @@ static void esp_output_fill_trailer(u8 *tail, int tfclen, int plen, __u8 proto)
tail[plen - 1] = proto; tail[plen - 1] = proto;
} }
static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) static int esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
{ {
int encap_type; int encap_type;
struct udphdr *uh; struct udphdr *uh;
...@@ -231,6 +231,7 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru ...@@ -231,6 +231,7 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru
__be16 sport, dport; __be16 sport, dport;
struct xfrm_encap_tmpl *encap = x->encap; struct xfrm_encap_tmpl *encap = x->encap;
struct ip_esp_hdr *esph = esp->esph; struct ip_esp_hdr *esph = esp->esph;
unsigned int len;
spin_lock_bh(&x->lock); spin_lock_bh(&x->lock);
sport = encap->encap_sport; sport = encap->encap_sport;
...@@ -238,11 +239,14 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru ...@@ -238,11 +239,14 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru
encap_type = encap->encap_type; encap_type = encap->encap_type;
spin_unlock_bh(&x->lock); spin_unlock_bh(&x->lock);
len = skb->len + esp->tailen - skb_transport_offset(skb);
if (len + sizeof(struct iphdr) >= IP_MAX_MTU)
return -EMSGSIZE;
uh = (struct udphdr *)esph; uh = (struct udphdr *)esph;
uh->source = sport; uh->source = sport;
uh->dest = dport; uh->dest = dport;
uh->len = htons(skb->len + esp->tailen uh->len = htons(len);
- skb_transport_offset(skb));
uh->check = 0; uh->check = 0;
switch (encap_type) { switch (encap_type) {
...@@ -259,6 +263,8 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru ...@@ -259,6 +263,8 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru
*skb_mac_header(skb) = IPPROTO_UDP; *skb_mac_header(skb) = IPPROTO_UDP;
esp->esph = esph; esp->esph = esph;
return 0;
} }
int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
...@@ -272,8 +278,12 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * ...@@ -272,8 +278,12 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
int tailen = esp->tailen; int tailen = esp->tailen;
/* this is non-NULL only with UDP Encapsulation */ /* this is non-NULL only with UDP Encapsulation */
if (x->encap) if (x->encap) {
esp_output_udp_encap(x, skb, esp); int err = esp_output_udp_encap(x, skb, esp);
if (err < 0)
return err;
}
if (!skb_cloned(skb)) { if (!skb_cloned(skb)) {
if (tailen <= skb_tailroom(skb)) { if (tailen <= skb_tailroom(skb)) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册