]>
Commit | Line | Data |
---|---|---|
e6832405 SL |
1 | From 60da21ec12c68ca002b06d936fb35ce1b2c4e3be Mon Sep 17 00:00:00 2001 |
2 | From: Sabrina Dubroca <sd@queasysnail.net> | |
3 | Date: Mon, 25 Mar 2019 14:30:00 +0100 | |
4 | Subject: esp4: add length check for UDP encapsulation | |
5 | ||
6 | [ Upstream commit 8dfb4eba4100e7cdd161a8baef2d8d61b7a7e62e ] | |
7 | ||
8 | esp_output_udp_encap can produce a length that doesn't fit in the 16 | |
9 | bits of a UDP header's length field. In that case, we'll send a | |
10 | fragmented packet whose length is larger than IP_MAX_MTU (resulting in | |
11 | "Oversized IP packet" warnings on receive) and with a bogus UDP | |
12 | length. | |
13 | ||
14 | To prevent this, add a length check to esp_output_udp_encap and return | |
15 | -EMSGSIZE on failure. | |
16 | ||
17 | This seems to be older than git history. | |
18 | ||
19 | Signed-off-by: Sabrina Dubroca <sd@queasysnail.net> | |
20 | Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> | |
21 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
22 | --- | |
23 | net/ipv4/esp4.c | 20 +++++++++++++++----- | |
24 | 1 file changed, 15 insertions(+), 5 deletions(-) | |
25 | ||
26 | diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c | |
27 | index 10e809b296ec8..fb065a8937ea2 100644 | |
28 | --- a/net/ipv4/esp4.c | |
29 | +++ b/net/ipv4/esp4.c | |
30 | @@ -226,7 +226,7 @@ static void esp_output_fill_trailer(u8 *tail, int tfclen, int plen, __u8 proto) | |
31 | tail[plen - 1] = proto; | |
32 | } | |
33 | ||
34 | -static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) | |
35 | +static int esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) | |
36 | { | |
37 | int encap_type; | |
38 | struct udphdr *uh; | |
39 | @@ -234,6 +234,7 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru | |
40 | __be16 sport, dport; | |
41 | struct xfrm_encap_tmpl *encap = x->encap; | |
42 | struct ip_esp_hdr *esph = esp->esph; | |
43 | + unsigned int len; | |
44 | ||
45 | spin_lock_bh(&x->lock); | |
46 | sport = encap->encap_sport; | |
47 | @@ -241,11 +242,14 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru | |
48 | encap_type = encap->encap_type; | |
49 | spin_unlock_bh(&x->lock); | |
50 | ||
51 | + len = skb->len + esp->tailen - skb_transport_offset(skb); | |
52 | + if (len + sizeof(struct iphdr) >= IP_MAX_MTU) | |
53 | + return -EMSGSIZE; | |
54 | + | |
55 | uh = (struct udphdr *)esph; | |
56 | uh->source = sport; | |
57 | uh->dest = dport; | |
58 | - uh->len = htons(skb->len + esp->tailen | |
59 | - - skb_transport_offset(skb)); | |
60 | + uh->len = htons(len); | |
61 | uh->check = 0; | |
62 | ||
63 | switch (encap_type) { | |
64 | @@ -262,6 +266,8 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru | |
65 | ||
66 | *skb_mac_header(skb) = IPPROTO_UDP; | |
67 | esp->esph = esph; | |
68 | + | |
69 | + return 0; | |
70 | } | |
71 | ||
72 | int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) | |
73 | @@ -275,8 +281,12 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * | |
74 | int tailen = esp->tailen; | |
75 | ||
76 | /* this is non-NULL only with UDP Encapsulation */ | |
77 | - if (x->encap) | |
78 | - esp_output_udp_encap(x, skb, esp); | |
79 | + if (x->encap) { | |
80 | + int err = esp_output_udp_encap(x, skb, esp); | |
81 | + | |
82 | + if (err < 0) | |
83 | + return err; | |
84 | + } | |
85 | ||
86 | if (!skb_cloned(skb)) { | |
87 | if (tailen <= skb_tailroom(skb)) { | |
88 | -- | |
89 | 2.20.1 | |
90 |