From c36d39abf997c7db46be294640d4881f8c6feb4d Mon Sep 17 00:00:00 2001 From: Michal Kubecek Date: May 09 2023 05:21:29 +0000 Subject: act_mirred: use the backlog for nested calls to mirred ingress (CVE-2022-4269 bsc#1206024). --- diff --git a/patches.suse/act_mirred-use-the-backlog-for-nested-calls-to-mirre.patch b/patches.suse/act_mirred-use-the-backlog-for-nested-calls-to-mirre.patch new file mode 100644 index 0000000..c0706c9 --- /dev/null +++ b/patches.suse/act_mirred-use-the-backlog-for-nested-calls-to-mirre.patch @@ -0,0 +1,131 @@ +From: Davide Caratti +Date: Fri, 20 Jan 2023 18:01:40 +0100 +Subject: act_mirred: use the backlog for nested calls to mirred ingress +Patch-mainline: v6.3-rc1 +Git-commit: ca22da2fbd693b54dc8e3b7b54ccc9f7e9ba3640 +References: CVE-2022-4269 bsc#1206024 + +William reports kernel soft-lockups on some OVS topologies when TC mirred +egress->ingress action is hit by local TCP traffic [1]. +The same can also be reproduced with SCTP (thanks Xin for verifying), when +client and server reach themselves through mirred egress to ingress, and +one of the two peers sends a "heartbeat" packet (from within a timer). + +Enqueueing to backlog proved to fix this soft lockup; however, as Cong +noticed [2], we should preserve - when possible - the current mirred +behavior that counts as "overlimits" any eventual packet drop subsequent to +the mirred forwarding action [3]. A compromise solution might use the +backlog only when tcf_mirred_act() has a nest level greater than one: +change tcf_mirred_forward() accordingly. + +Also, add a kselftest that can reproduce the lockup and verifies TC mirred +ability to account for further packet drops after TC mirred egress->ingress +(when the nest level is 1). + + [1] https://lore.kernel.org/netdev/33dc43f587ec1388ba456b4915c75f02a8aae226.1663945716.git.dcaratti@redhat.com/ + [2] https://lore.kernel.org/netdev/Y0w%2FWWY60gqrtGLp@pop-os.localdomain/ + [3] such behavior is not guaranteed: for example, if RPS or skb RX + timestamping is enabled on the mirred target device, the kernel + can defer receiving the skb and return NET_RX_SUCCESS inside + tcf_mirred_forward(). + +Reported-by: William Zhao +CC: Xin Long +Signed-off-by: Davide Caratti +Reviewed-by: Marcelo Ricardo Leitner +Acked-by: Jamal Hadi Salim +Signed-off-by: Paolo Abeni +Acked-by: Michal Kubecek + +--- + net/sched/act_mirred.c | 7 +++ + .../selftests/net/forwarding/tc_actions.sh | 49 ++++++++++++++++++- + 2 files changed, 55 insertions(+), 1 deletion(-) + +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -207,12 +207,19 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, + return err; + } + ++static bool is_mirred_nested(void) ++{ ++ return unlikely(__this_cpu_read(mirred_nest_level) > 1); ++} ++ + static int tcf_mirred_forward(bool want_ingress, struct sk_buff *skb) + { + int err; + + if (!want_ingress) + err = dev_queue_xmit(skb); ++ else if (is_mirred_nested()) ++ err = netif_rx(skb); + else + err = netif_receive_skb(skb); + +--- a/tools/testing/selftests/net/forwarding/tc_actions.sh ++++ b/tools/testing/selftests/net/forwarding/tc_actions.sh +@@ -2,7 +2,8 @@ + # SPDX-License-Identifier: GPL-2.0 + + ALL_TESTS="gact_drop_and_ok_test mirred_egress_redirect_test \ +- mirred_egress_mirror_test gact_trap_test" ++ mirred_egress_mirror_test gact_trap_test \ ++ mirred_egress_to_ingress_tcp_test" + NUM_NETIFS=4 + source tc_common.sh + source lib.sh +@@ -148,6 +149,52 @@ gact_trap_test() + log_test "trap ($tcflags)" + } + ++mirred_egress_to_ingress_tcp_test() ++{ ++ local tmpfile=$(mktemp) tmpfile1=$(mktemp) ++ ++ RET=0 ++ dd conv=sparse status=none if=/dev/zero bs=1M count=2 of=$tmpfile ++ tc filter add dev $h1 protocol ip pref 100 handle 100 egress flower \ ++ $tcflags ip_proto tcp src_ip 192.0.2.1 dst_ip 192.0.2.2 \ ++ action ct commit nat src addr 192.0.2.2 pipe \ ++ action ct clear pipe \ ++ action ct commit nat dst addr 192.0.2.1 pipe \ ++ action ct clear pipe \ ++ action skbedit ptype host pipe \ ++ action mirred ingress redirect dev $h1 ++ tc filter add dev $h1 protocol ip pref 101 handle 101 egress flower \ ++ $tcflags ip_proto icmp \ ++ action mirred ingress redirect dev $h1 ++ tc filter add dev $h1 protocol ip pref 102 handle 102 ingress flower \ ++ ip_proto icmp \ ++ action drop ++ ++ ip vrf exec v$h1 nc --recv-only -w10 -l -p 12345 -o $tmpfile1 & ++ local rpid=$! ++ ip vrf exec v$h1 nc -w1 --send-only 192.0.2.2 12345 <$tmpfile ++ wait -n $rpid ++ cmp -s $tmpfile $tmpfile1 ++ check_err $? "server output check failed" ++ ++ $MZ $h1 -c 10 -p 64 -a $h1mac -b $h1mac -A 192.0.2.1 -B 192.0.2.1 \ ++ -t icmp "ping,id=42,seq=5" -q ++ tc_check_packets "dev $h1 egress" 101 10 ++ check_err $? "didn't mirred redirect ICMP" ++ tc_check_packets "dev $h1 ingress" 102 10 ++ check_err $? "didn't drop mirred ICMP" ++ local overlimits=$(tc_rule_stats_get ${h1} 101 egress .overlimits) ++ test ${overlimits} = 10 ++ check_err $? "wrong overlimits, expected 10 got ${overlimits}" ++ ++ tc filter del dev $h1 egress protocol ip pref 100 handle 100 flower ++ tc filter del dev $h1 egress protocol ip pref 101 handle 101 flower ++ tc filter del dev $h1 ingress protocol ip pref 102 handle 102 flower ++ ++ rm -f $tmpfile $tmpfile1 ++ log_test "mirred_egress_to_ingress_tcp ($tcflags)" ++} ++ + setup_prepare() + { + h1=${NETIFS[p1]} diff --git a/series.conf b/series.conf index 570fb14..4bc80fd 100644 --- a/series.conf +++ b/series.conf @@ -23097,6 +23097,7 @@ patches.suse/net-mpls-fix-stale-pointer-if-allocation-fails-durin.patch patches.suse/0001-kvm-initialize-all-of-the-kvm_debugregs-structure-be.patch patches.suse/net-sched-act_mirred-better-wording-on-protection-ag.patch + patches.suse/act_mirred-use-the-backlog-for-nested-calls-to-mirre.patch patches.suse/net-add-sock_init_data_uid.patch patches.suse/tun-tun_chr_open-correctly-initialize-socket-uid.patch patches.suse/tap-tap_open-correctly-initialize-socket-uid.patch