Skip to content

Commit

Permalink
net: Fix skb->csum update in inet_proto_csum_replace16().
Browse files Browse the repository at this point in the history
skb->csum is updated incorrectly, when manipulation for
NF_NAT_MANIP_SRC\DST is done on IPV6 packet.

Fix:
There is no need to update skb->csum in inet_proto_csum_replace16(),
because update in two fields a.) IPv6 src/dst address and b.) L4 header
checksum cancels each other for skb->csum calculation. Whereas
inet_proto_csum_replace4 function needs to update skb->csum, because
update in 3 fields a.) IPv4 src/dst address, b.) IPv4 Header checksum
and c.) L4 header checksum results in same diff as L4 Header checksum
for skb->csum calculation.

[ [email protected]: a few comestic documentation edits ]
Signed-off-by: Praveen Chaudhary <[email protected]>
Signed-off-by: Zhenggen Xu <[email protected]>
Signed-off-by: Andy Stracner <[email protected]>
Reviewed-by: Florian Westphal <[email protected]>
Signed-off-by: Pablo Neira Ayuso <[email protected]>
  • Loading branch information
praveen-li authored and ummakynes committed Jan 24, 2020
1 parent eb014de commit 189c9b1
Showing 1 changed file with 17 additions and 3 deletions.
20 changes: 17 additions & 3 deletions net/core/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,23 @@ void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
}
EXPORT_SYMBOL(inet_proto_csum_replace4);

/**
* inet_proto_csum_replace16 - update layer 4 header checksum field
* @sum: Layer 4 header checksum field
* @skb: sk_buff for the packet
* @from: old IPv6 address
* @to: new IPv6 address
* @pseudohdr: True if layer 4 header checksum includes pseudoheader
*
* Update layer 4 header as per the update in IPv6 src/dst address.
*
* There is no need to update skb->csum in this function, because update in two
* fields a.) IPv6 src/dst address and b.) L4 header checksum cancels each other
* for skb->csum calculation. Whereas inet_proto_csum_replace4 function needs to
* update skb->csum, because update in 3 fields a.) IPv4 src/dst address,
* b.) IPv4 Header checksum and c.) L4 header checksum results in same diff as
* L4 Header checksum for skb->csum calculation.
*/
void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
const __be32 *from, const __be32 *to,
bool pseudohdr)
Expand All @@ -449,9 +466,6 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
if (skb->ip_summed != CHECKSUM_PARTIAL) {
*sum = csum_fold(csum_partial(diff, sizeof(diff),
~csum_unfold(*sum)));
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
skb->csum = ~csum_partial(diff, sizeof(diff),
~skb->csum);
} else if (pseudohdr)
*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
csum_unfold(*sum)));
Expand Down

0 comments on commit 189c9b1

Please sign in to comment.