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

Commit fb509b7d authored by Praveen Chaudhary's avatar Praveen Chaudhary Committed by Greg Kroah-Hartman
Browse files

net: Fix skb->csum update in inet_proto_csum_replace16().



[ Upstream commit 189c9b1e94539b11c80636bc13e9cf47529e7bba ]

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.

[ pablo@netfilter.org: a few comestic documentation edits ]
Signed-off-by: default avatarPraveen Chaudhary <pchaudhary@linkedin.com>
Signed-off-by: default avatarZhenggen Xu <zxu@linkedin.com>
Signed-off-by: default avatarAndy Stracner <astracner@linkedin.com>
Reviewed-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 9d139683
Loading
Loading
Loading
Loading
+17 −3
Original line number Diff line number Diff line
@@ -316,6 +316,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)
@@ -327,9 +344,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)));