diff options
-rw-r--r-- | queue-5.4/net-fix-checksum-update-for-ila-adj-transport.patch | 158 | ||||
-rw-r--r-- | queue-5.4/series | 2 | ||||
-rw-r--r-- | queue-5.4/xprtrdma-fix-pointer-derefs-in-error-cases-of-rpcrdma_ep_create.patch | 42 |
3 files changed, 202 insertions, 0 deletions
diff --git a/queue-5.4/net-fix-checksum-update-for-ila-adj-transport.patch b/queue-5.4/net-fix-checksum-update-for-ila-adj-transport.patch new file mode 100644 index 0000000000..36c5fcb7ab --- /dev/null +++ b/queue-5.4/net-fix-checksum-update-for-ila-adj-transport.patch @@ -0,0 +1,158 @@ +From 6043b794c7668c19dabc4a93c75b924a19474d59 Mon Sep 17 00:00:00 2001 +From: Paul Chaignon <paul.chaignon@gmail.com> +Date: Thu, 29 May 2025 12:28:05 +0200 +Subject: net: Fix checksum update for ILA adj-transport + +From: Paul Chaignon <paul.chaignon@gmail.com> + +commit 6043b794c7668c19dabc4a93c75b924a19474d59 upstream. + +During ILA address translations, the L4 checksums can be handled in +different ways. One of them, adj-transport, consist in parsing the +transport layer and updating any found checksum. This logic relies on +inet_proto_csum_replace_by_diff and produces an incorrect skb->csum when +in state CHECKSUM_COMPLETE. + +This bug can be reproduced with a simple ILA to SIR mapping, assuming +packets are received with CHECKSUM_COMPLETE: + + $ ip a show dev eth0 + 14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 62:ae:35:9e:0f:8d brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 3333:0:0:1::c078/64 scope global + valid_lft forever preferred_lft forever + inet6 fd00:10:244:1::c078/128 scope global nodad + valid_lft forever preferred_lft forever + inet6 fe80::60ae:35ff:fe9e:f8d/64 scope link proto kernel_ll + valid_lft forever preferred_lft forever + $ ip ila add loc_match fd00:10:244:1 loc 3333:0:0:1 \ + csum-mode adj-transport ident-type luid dev eth0 + +Then I hit [fd00:10:244:1::c078]:8000 with a server listening only on +[3333:0:0:1::c078]:8000. With the bug, the SYN packet is dropped with +SKB_DROP_REASON_TCP_CSUM after inet_proto_csum_replace_by_diff changed +skb->csum. The translation and drop are visible on pwru [1] traces: + + IFACE TUPLE FUNC + eth0:9 [fd00:10:244:3::3d8]:51420->[fd00:10:244:1::c078]:8000(tcp) ipv6_rcv + eth0:9 [fd00:10:244:3::3d8]:51420->[fd00:10:244:1::c078]:8000(tcp) ip6_rcv_core + eth0:9 [fd00:10:244:3::3d8]:51420->[fd00:10:244:1::c078]:8000(tcp) nf_hook_slow + eth0:9 [fd00:10:244:3::3d8]:51420->[fd00:10:244:1::c078]:8000(tcp) inet_proto_csum_replace_by_diff + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) tcp_v6_early_demux + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) ip6_route_input + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) ip6_input + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) ip6_input_finish + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) ip6_protocol_deliver_rcu + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) raw6_local_deliver + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) ipv6_raw_deliver + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) tcp_v6_rcv + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) __skb_checksum_complete + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) kfree_skb_reason(SKB_DROP_REASON_TCP_CSUM) + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) skb_release_head_state + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) skb_release_data + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) skb_free_head + eth0:9 [fd00:10:244:3::3d8]:51420->[3333:0:0:1::c078]:8000(tcp) kfree_skbmem + +This is happening because inet_proto_csum_replace_by_diff is updating +skb->csum when it shouldn't. The L4 checksum is updated such that it +"cancels" the IPv6 address change in terms of checksum computation, so +the impact on skb->csum is null. + +Note this would be different for an IPv4 packet since three fields +would be updated: the IPv4 address, the IP checksum, and the L4 +checksum. Two would cancel each other and skb->csum would still need +to be updated to take the L4 checksum change into account. + +This patch fixes it by passing an ipv6 flag to +inet_proto_csum_replace_by_diff, to skip the skb->csum update if we're +in the IPv6 case. Note the behavior of the only other user of +inet_proto_csum_replace_by_diff, the BPF subsystem, is left as is in +this patch and fixed in the subsequent patch. + +With the fix, using the reproduction from above, I can confirm +skb->csum is not touched by inet_proto_csum_replace_by_diff and the TCP +SYN proceeds to the application after the ILA translation. + +Link: https://github.com/cilium/pwru [1] +Fixes: 65d7ab8de582 ("net: Identifier Locator Addressing module") +Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com> +Acked-by: Daniel Borkmann <daniel@iogearbox.net> +Link: https://patch.msgid.link/b5539869e3550d46068504feb02d37653d939c0b.1748509484.git.paul.chaignon@gmail.com +Signed-off-by: Jakub Kicinski <kuba@kernel.org> +[ Fixed conflict due to unrelated change in inet_proto_csum_replace_by_diff. ] +Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + include/net/checksum.h | 2 +- + net/core/filter.c | 2 +- + net/core/utils.c | 4 ++-- + net/ipv6/ila/ila_common.c | 6 +++--- + 4 files changed, 7 insertions(+), 7 deletions(-) + +--- a/include/net/checksum.h ++++ b/include/net/checksum.h +@@ -152,7 +152,7 @@ void inet_proto_csum_replace16(__sum16 * + const __be32 *from, const __be32 *to, + bool pseudohdr); + void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb, +- __wsum diff, bool pseudohdr); ++ __wsum diff, bool pseudohdr, bool ipv6); + + static __always_inline + void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb, +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -1949,7 +1949,7 @@ BPF_CALL_5(bpf_l4_csum_replace, struct s + if (unlikely(from != 0)) + return -EINVAL; + +- inet_proto_csum_replace_by_diff(ptr, skb, to, is_pseudo); ++ inet_proto_csum_replace_by_diff(ptr, skb, to, is_pseudo, false); + break; + case 2: + inet_proto_csum_replace2(ptr, skb, from, to, is_pseudo); +--- a/net/core/utils.c ++++ b/net/core/utils.c +@@ -473,11 +473,11 @@ void inet_proto_csum_replace16(__sum16 * + EXPORT_SYMBOL(inet_proto_csum_replace16); + + void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb, +- __wsum diff, bool pseudohdr) ++ __wsum diff, bool pseudohdr, bool ipv6) + { + if (skb->ip_summed != CHECKSUM_PARTIAL) { + *sum = csum_fold(csum_add(diff, ~csum_unfold(*sum))); +- if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) ++ if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr && !ipv6) + skb->csum = ~csum_add(diff, ~skb->csum); + } else if (pseudohdr) { + *sum = ~csum_fold(csum_add(diff, csum_unfold(*sum))); +--- a/net/ipv6/ila/ila_common.c ++++ b/net/ipv6/ila/ila_common.c +@@ -86,7 +86,7 @@ static void ila_csum_adjust_transport(st + + diff = get_csum_diff(ip6h, p); + inet_proto_csum_replace_by_diff(&th->check, skb, +- diff, true); ++ diff, true, true); + } + break; + case NEXTHDR_UDP: +@@ -97,7 +97,7 @@ static void ila_csum_adjust_transport(st + if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { + diff = get_csum_diff(ip6h, p); + inet_proto_csum_replace_by_diff(&uh->check, skb, +- diff, true); ++ diff, true, true); + if (!uh->check) + uh->check = CSUM_MANGLED_0; + } +@@ -111,7 +111,7 @@ static void ila_csum_adjust_transport(st + + diff = get_csum_diff(ip6h, p); + inet_proto_csum_replace_by_diff(&ih->icmp6_cksum, skb, +- diff, true); ++ diff, true, true); + } + break; + } diff --git a/queue-5.4/series b/queue-5.4/series index 21efd68f2e..a818571711 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -213,3 +213,5 @@ arm-dts-am335x-bone-common-add-gpio-phy-reset-on-revision-c3-board.patch arm-dts-am335x-bone-common-increase-mdio-reset-deassert-time.patch arm-dts-am335x-bone-common-increase-mdio-reset-deassert-delay-to-50ms.patch posix-cpu-timers-fix-race-between-handle_posix_cpu_timers-and-posix_cpu_timer_del.patch +xprtrdma-fix-pointer-derefs-in-error-cases-of-rpcrdma_ep_create.patch +net-fix-checksum-update-for-ila-adj-transport.patch diff --git a/queue-5.4/xprtrdma-fix-pointer-derefs-in-error-cases-of-rpcrdma_ep_create.patch b/queue-5.4/xprtrdma-fix-pointer-derefs-in-error-cases-of-rpcrdma_ep_create.patch new file mode 100644 index 0000000000..84d613f497 --- /dev/null +++ b/queue-5.4/xprtrdma-fix-pointer-derefs-in-error-cases-of-rpcrdma_ep_create.patch @@ -0,0 +1,42 @@ +From a9c10b5b3b67b3750a10c8b089b2e05f5e176e33 Mon Sep 17 00:00:00 2001 +From: Dan Aloni <dan.aloni@vastdata.com> +Date: Tue, 25 Jan 2022 22:06:46 +0200 +Subject: xprtrdma: fix pointer derefs in error cases of rpcrdma_ep_create + +From: Dan Aloni <dan.aloni@vastdata.com> + +commit a9c10b5b3b67b3750a10c8b089b2e05f5e176e33 upstream. + +If there are failures then we must not leave the non-NULL pointers with +the error value, otherwise `rpcrdma_ep_destroy` gets confused and tries +free them, resulting in an Oops. + +Signed-off-by: Dan Aloni <dan.aloni@vastdata.com> +Acked-by: Chuck Lever <chuck.lever@oracle.com> +Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com> +[ Larry: backport to 5.4.y. Minor conflict resolved due to missing commit 93aa8e0a9de80 + xprtrdma: Merge struct rpcrdma_ia into struct rpcrdma_ep ] +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Larry Bassel <larry.bassel@oracle.com> +--- + net/sunrpc/xprtrdma/verbs.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/sunrpc/xprtrdma/verbs.c ++++ b/net/sunrpc/xprtrdma/verbs.c +@@ -525,6 +525,7 @@ int rpcrdma_ep_create(struct rpcrdma_xpr + IB_POLL_WORKQUEUE); + if (IS_ERR(sendcq)) { + rc = PTR_ERR(sendcq); ++ sendcq = NULL; + goto out1; + } + +@@ -533,6 +534,7 @@ int rpcrdma_ep_create(struct rpcrdma_xpr + IB_POLL_WORKQUEUE); + if (IS_ERR(recvcq)) { + rc = PTR_ERR(recvcq); ++ recvcq = NULL; + goto out2; + } + |