Skip to content

Commit

Permalink
esp4: add length check for UDP encapsulation
Browse files Browse the repository at this point in the history
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: Sabrina Dubroca <[email protected]>
Signed-off-by: Steffen Klassert <[email protected]>
  • Loading branch information
qsn authored and klassert committed Mar 26, 2019
1 parent dbb2483 commit 8dfb4eb
Showing 1 changed file with 15 additions and 5 deletions.
20 changes: 15 additions & 5 deletions net/ipv4/esp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,26 +226,30 @@ static void esp_output_fill_trailer(u8 *tail, int tfclen, int plen, __u8 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;
struct udphdr *uh;
__be32 *udpdata32;
__be16 sport, dport;
struct xfrm_encap_tmpl *encap = x->encap;
struct ip_esp_hdr *esph = esp->esph;
unsigned int len;

spin_lock_bh(&x->lock);
sport = encap->encap_sport;
dport = encap->encap_dport;
encap_type = encap->encap_type;
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->source = sport;
uh->dest = dport;
uh->len = htons(skb->len + esp->tailen
- skb_transport_offset(skb));
uh->len = htons(len);
uh->check = 0;

switch (encap_type) {
Expand All @@ -262,6 +266,8 @@ static void esp_output_udp_encap(struct xfrm_state *x, struct sk_buff *skb, stru

*skb_mac_header(skb) = IPPROTO_UDP;
esp->esph = esph;

return 0;
}

int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
Expand All @@ -275,8 +281,12 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
int tailen = esp->tailen;

/* this is non-NULL only with UDP Encapsulation */
if (x->encap)
esp_output_udp_encap(x, skb, esp);
if (x->encap) {
int err = esp_output_udp_encap(x, skb, esp);

if (err < 0)
return err;
}

if (!skb_cloned(skb)) {
if (tailen <= skb_tailroom(skb)) {
Expand Down

0 comments on commit 8dfb4eb

Please sign in to comment.