Skip to content

Commit

Permalink
udplite: fix partial checksum initialization
Browse files Browse the repository at this point in the history
Since UDP-Lite is always using checksum, the following path is
triggered when calculating pseudo header for it:

  udp4_csum_init() or udp6_csum_init()
    skb_checksum_init_zero_check()
      __skb_checksum_validate_complete()

The problem can appear if skb->len is less than CHECKSUM_BREAK. In
this particular case __skb_checksum_validate_complete() also invokes
__skb_checksum_complete(skb). If UDP-Lite is using partial checksum
that covers only part of a packet, the function will return bad
checksum and the packet will be dropped.

It can be fixed if we skip skb_checksum_init_zero_check() and only
set the required pseudo header checksum for UDP-Lite with partial
checksum before udp4_csum_init()/udp6_csum_init() functions return.

Fixes: ed70fcf ("net: Call skb_checksum_init in IPv4")
Fixes: e4f45b7 ("net: Call skb_checksum_init in IPv6")
Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
akodanev authored and davem330 committed Feb 16, 2018
1 parent da27988 commit 15f35d4
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/net/udplite.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh)
UDP_SKB_CB(skb)->cscov = cscov;
if (skb->ip_summed == CHECKSUM_COMPLETE)
skb->ip_summed = CHECKSUM_NONE;
skb->csum_valid = 0;
}

return 0;
Expand Down
5 changes: 5 additions & 0 deletions net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2024,6 +2024,11 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
err = udplite_checksum_init(skb, uh);
if (err)
return err;

if (UDP_SKB_CB(skb)->partial_cov) {
skb->csum = inet_compute_pseudo(skb, proto);
return 0;
}
}

/* Note, we are only interested in != 0 or == 0, thus the
Expand Down
5 changes: 5 additions & 0 deletions net/ipv6/ip6_checksum.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
err = udplite_checksum_init(skb, uh);
if (err)
return err;

if (UDP_SKB_CB(skb)->partial_cov) {
skb->csum = ip6_compute_pseudo(skb, proto);
return 0;
}
}

/* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels)
Expand Down

0 comments on commit 15f35d4

Please sign in to comment.