Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b709dae authored by Alexey Kodanev's avatar Alexey Kodanev Committed by Greg Kroah-Hartman
Browse files

udplite: fix partial checksum initialization




[ Upstream commit 15f35d49c93f4fa9875235e7bf3e3783d2dd7a1b ]

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: ed70fcfc ("net: Call skb_checksum_init in IPv4")
Fixes: e4f45b7f ("net: Call skb_checksum_init in IPv6")
Signed-off-by: default avatarAlexey Kodanev <alexey.kodanev@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 794953c9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -61,6 +61,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;
+5 −0
Original line number Diff line number Diff line
@@ -1718,6 +1718,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;
		}
	}

	return skb_checksum_init_zero_check(skb, proto, uh->check,
+5 −0
Original line number Diff line number Diff line
@@ -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)