netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress
@ 2024-02-15 14:33 Jakub Kicinski
  2024-02-15 14:33 ` [PATCH net v3 2/2] net/sched: act_mirred: don't override retval if we already lost the skb Jakub Kicinski
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Jakub Kicinski @ 2024-02-15 14:33 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, Jakub Kicinski, Marcelo Ricardo Leitner,
	Davide Caratti, jhs, xiyou.wangcong, jiri, shmulik.ladkani

The test Davide added in commit ca22da2fbd69 ("act_mirred: use the backlog
for nested calls to mirred ingress") hangs our testing VMs every 10 or so
runs, with the familiar tcp_v4_rcv -> tcp_v4_rcv deadlock reported by
lockdep.

The problem as previously described by Davide (see Link) is that
if we reverse flow of traffic with the redirect (egress -> ingress)
we may reach the same socket which generated the packet. And we may
still be holding its socket lock. The common solution to such deadlocks
is to put the packet in the Rx backlog, rather than run the Rx path
inline. Do that for all egress -> ingress reversals, not just once
we started to nest mirred calls.

In the past there was a concern that the backlog indirection will
lead to loss of error reporting / less accurate stats. But the current
workaround does not seem to address the issue.

Fixes: 53592b364001 ("net/sched: act_mirred: Implement ingress actions")
Cc: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Suggested-by: Davide Caratti <dcaratti@redhat.com>
Link: https://lore.kernel.org/netdev/33dc43f587ec1388ba456b4915c75f02a8aae226.1663945716.git.dcaratti@redhat.com/
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: jhs@mojatatu.com
CC: xiyou.wangcong@gmail.com
CC: jiri@resnulli.us
CC: shmulik.ladkani@gmail.com
---
 net/sched/act_mirred.c                             | 14 +++++---------
 .../testing/selftests/net/forwarding/tc_actions.sh |  3 ---
 2 files changed, 5 insertions(+), 12 deletions(-)

diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 0a1a9e40f237..291d47c9eb69 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -232,18 +232,14 @@ 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)
+static int
+tcf_mirred_forward(bool at_ingress, bool want_ingress, struct sk_buff *skb)
 {
 	int err;
 
 	if (!want_ingress)
 		err = tcf_dev_queue_xmit(skb, dev_queue_xmit);
-	else if (is_mirred_nested())
+	else if (!at_ingress)
 		err = netif_rx(skb);
 	else
 		err = netif_receive_skb(skb);
@@ -319,9 +315,9 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
 
 		skb_set_redirected(skb_to_send, skb_to_send->tc_at_ingress);
 
-		err = tcf_mirred_forward(want_ingress, skb_to_send);
+		err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send);
 	} else {
-		err = tcf_mirred_forward(want_ingress, skb_to_send);
+		err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send);
 	}
 
 	if (err) {
diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh
index b0f5e55d2d0b..589629636502 100755
--- a/tools/testing/selftests/net/forwarding/tc_actions.sh
+++ b/tools/testing/selftests/net/forwarding/tc_actions.sh
@@ -235,9 +235,6 @@ mirred_egress_to_ingress_tcp_test()
 	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
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net v3 2/2] net/sched: act_mirred: don't override retval if we already lost the skb
  2024-02-15 14:33 [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress Jakub Kicinski
@ 2024-02-15 14:33 ` Jakub Kicinski
  2024-02-15 17:33   ` Jamal Hadi Salim
  2024-02-15 17:33 ` [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress Jamal Hadi Salim
  2024-02-16 10:20 ` patchwork-bot+netdevbpf
  2 siblings, 1 reply; 5+ messages in thread
From: Jakub Kicinski @ 2024-02-15 14:33 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, Jakub Kicinski, Michal Swiatkowski, jhs,
	xiyou.wangcong, jiri

If we're redirecting the skb, and haven't called tcf_mirred_forward(),
yet, we need to tell the core to drop the skb by setting the retcode
to SHOT. If we have called tcf_mirred_forward(), however, the skb
is out of our hands and returning SHOT will lead to UaF.

Move the retval override to the error path which actually need it.

Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Fixes: e5cf1baf92cb ("act_mirred: use TC_ACT_REINSERT when possible")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: jhs@mojatatu.com
CC: xiyou.wangcong@gmail.com
CC: jiri@resnulli.us
---
 net/sched/act_mirred.c | 22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 291d47c9eb69..6faa7d00da09 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -266,8 +266,7 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
 	if (unlikely(!(dev->flags & IFF_UP)) || !netif_carrier_ok(dev)) {
 		net_notice_ratelimited("tc mirred to Houston: device %s is down\n",
 				       dev->name);
-		err = -ENODEV;
-		goto out;
+		goto err_cant_do;
 	}
 
 	/* we could easily avoid the clone only if called by ingress and clsact;
@@ -279,10 +278,8 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
 		tcf_mirred_can_reinsert(retval);
 	if (!dont_clone) {
 		skb_to_send = skb_clone(skb, GFP_ATOMIC);
-		if (!skb_to_send) {
-			err =  -ENOMEM;
-			goto out;
-		}
+		if (!skb_to_send)
+			goto err_cant_do;
 	}
 
 	want_ingress = tcf_mirred_act_wants_ingress(m_eaction);
@@ -319,15 +316,16 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
 	} else {
 		err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send);
 	}
-
-	if (err) {
-out:
+	if (err)
 		tcf_action_inc_overlimit_qstats(&m->common);
-		if (is_redirect)
-			retval = TC_ACT_SHOT;
-	}
 
 	return retval;
+
+err_cant_do:
+	if (is_redirect)
+		retval = TC_ACT_SHOT;
+	tcf_action_inc_overlimit_qstats(&m->common);
+	return retval;
 }
 
 static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress
  2024-02-15 14:33 [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress Jakub Kicinski
  2024-02-15 14:33 ` [PATCH net v3 2/2] net/sched: act_mirred: don't override retval if we already lost the skb Jakub Kicinski
@ 2024-02-15 17:33 ` Jamal Hadi Salim
  2024-02-16 10:20 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 5+ messages in thread
From: Jamal Hadi Salim @ 2024-02-15 17:33 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, Marcelo Ricardo Leitner,
	Davide Caratti, xiyou.wangcong, jiri, shmulik.ladkani

On Thu, Feb 15, 2024 at 9:33 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> The test Davide added in commit ca22da2fbd69 ("act_mirred: use the backlog
> for nested calls to mirred ingress") hangs our testing VMs every 10 or so
> runs, with the familiar tcp_v4_rcv -> tcp_v4_rcv deadlock reported by
> lockdep.
>
> The problem as previously described by Davide (see Link) is that
> if we reverse flow of traffic with the redirect (egress -> ingress)
> we may reach the same socket which generated the packet. And we may
> still be holding its socket lock. The common solution to such deadlocks
> is to put the packet in the Rx backlog, rather than run the Rx path
> inline. Do that for all egress -> ingress reversals, not just once
> we started to nest mirred calls.
>
> In the past there was a concern that the backlog indirection will
> lead to loss of error reporting / less accurate stats. But the current
> workaround does not seem to address the issue.
>
> Fixes: 53592b364001 ("net/sched: act_mirred: Implement ingress actions")
> Cc: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> Suggested-by: Davide Caratti <dcaratti@redhat.com>
> Link: https://lore.kernel.org/netdev/33dc43f587ec1388ba456b4915c75f02a8aae226.1663945716.git.dcaratti@redhat.com/
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>

Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>

cheers,
jamal

> ---
> CC: jhs@mojatatu.com
> CC: xiyou.wangcong@gmail.com
> CC: jiri@resnulli.us
> CC: shmulik.ladkani@gmail.com
> ---
>  net/sched/act_mirred.c                             | 14 +++++---------
>  .../testing/selftests/net/forwarding/tc_actions.sh |  3 ---
>  2 files changed, 5 insertions(+), 12 deletions(-)
>
> diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
> index 0a1a9e40f237..291d47c9eb69 100644
> --- a/net/sched/act_mirred.c
> +++ b/net/sched/act_mirred.c
> @@ -232,18 +232,14 @@ 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)
> +static int
> +tcf_mirred_forward(bool at_ingress, bool want_ingress, struct sk_buff *skb)
>  {
>         int err;
>
>         if (!want_ingress)
>                 err = tcf_dev_queue_xmit(skb, dev_queue_xmit);
> -       else if (is_mirred_nested())
> +       else if (!at_ingress)
>                 err = netif_rx(skb);
>         else
>                 err = netif_receive_skb(skb);
> @@ -319,9 +315,9 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
>
>                 skb_set_redirected(skb_to_send, skb_to_send->tc_at_ingress);
>
> -               err = tcf_mirred_forward(want_ingress, skb_to_send);
> +               err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send);
>         } else {
> -               err = tcf_mirred_forward(want_ingress, skb_to_send);
> +               err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send);
>         }
>
>         if (err) {
> diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh
> index b0f5e55d2d0b..589629636502 100755
> --- a/tools/testing/selftests/net/forwarding/tc_actions.sh
> +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh
> @@ -235,9 +235,6 @@ mirred_egress_to_ingress_tcp_test()
>         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
> --
> 2.43.0
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net v3 2/2] net/sched: act_mirred: don't override retval if we already lost the skb
  2024-02-15 14:33 ` [PATCH net v3 2/2] net/sched: act_mirred: don't override retval if we already lost the skb Jakub Kicinski
@ 2024-02-15 17:33   ` Jamal Hadi Salim
  0 siblings, 0 replies; 5+ messages in thread
From: Jamal Hadi Salim @ 2024-02-15 17:33 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, Michal Swiatkowski,
	xiyou.wangcong, jiri

On Thu, Feb 15, 2024 at 9:33 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> If we're redirecting the skb, and haven't called tcf_mirred_forward(),
> yet, we need to tell the core to drop the skb by setting the retcode
> to SHOT. If we have called tcf_mirred_forward(), however, the skb
> is out of our hands and returning SHOT will lead to UaF.
>
> Move the retval override to the error path which actually need it.
>
> Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
> Fixes: e5cf1baf92cb ("act_mirred: use TC_ACT_REINSERT when possible")
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>

Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>


cheers,
jamal

> ---
> CC: jhs@mojatatu.com
> CC: xiyou.wangcong@gmail.com
> CC: jiri@resnulli.us
> ---
>  net/sched/act_mirred.c | 22 ++++++++++------------
>  1 file changed, 10 insertions(+), 12 deletions(-)
>
> diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
> index 291d47c9eb69..6faa7d00da09 100644
> --- a/net/sched/act_mirred.c
> +++ b/net/sched/act_mirred.c
> @@ -266,8 +266,7 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
>         if (unlikely(!(dev->flags & IFF_UP)) || !netif_carrier_ok(dev)) {
>                 net_notice_ratelimited("tc mirred to Houston: device %s is down\n",
>                                        dev->name);
> -               err = -ENODEV;
> -               goto out;
> +               goto err_cant_do;
>         }
>
>         /* we could easily avoid the clone only if called by ingress and clsact;
> @@ -279,10 +278,8 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
>                 tcf_mirred_can_reinsert(retval);
>         if (!dont_clone) {
>                 skb_to_send = skb_clone(skb, GFP_ATOMIC);
> -               if (!skb_to_send) {
> -                       err =  -ENOMEM;
> -                       goto out;
> -               }
> +               if (!skb_to_send)
> +                       goto err_cant_do;
>         }
>
>         want_ingress = tcf_mirred_act_wants_ingress(m_eaction);
> @@ -319,15 +316,16 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
>         } else {
>                 err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send);
>         }
> -
> -       if (err) {
> -out:
> +       if (err)
>                 tcf_action_inc_overlimit_qstats(&m->common);
> -               if (is_redirect)
> -                       retval = TC_ACT_SHOT;
> -       }
>
>         return retval;
> +
> +err_cant_do:
> +       if (is_redirect)
> +               retval = TC_ACT_SHOT;
> +       tcf_action_inc_overlimit_qstats(&m->common);
> +       return retval;
>  }
>
>  static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m,
> --
> 2.43.0
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress
  2024-02-15 14:33 [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress Jakub Kicinski
  2024-02-15 14:33 ` [PATCH net v3 2/2] net/sched: act_mirred: don't override retval if we already lost the skb Jakub Kicinski
  2024-02-15 17:33 ` [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress Jamal Hadi Salim
@ 2024-02-16 10:20 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2024-02-16 10:20 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, marcelo.leitner, dcaratti, jhs,
	xiyou.wangcong, jiri, shmulik.ladkani

Hello:

This series was applied to netdev/net.git (main)
by David S. Miller <davem@davemloft.net>:

On Thu, 15 Feb 2024 06:33:45 -0800 you wrote:
> The test Davide added in commit ca22da2fbd69 ("act_mirred: use the backlog
> for nested calls to mirred ingress") hangs our testing VMs every 10 or so
> runs, with the familiar tcp_v4_rcv -> tcp_v4_rcv deadlock reported by
> lockdep.
> 
> The problem as previously described by Davide (see Link) is that
> if we reverse flow of traffic with the redirect (egress -> ingress)
> we may reach the same socket which generated the packet. And we may
> still be holding its socket lock. The common solution to such deadlocks
> is to put the packet in the Rx backlog, rather than run the Rx path
> inline. Do that for all egress -> ingress reversals, not just once
> we started to nest mirred calls.
> 
> [...]

Here is the summary with links:
  - [net,v3,1/2] net/sched: act_mirred: use the backlog for mirred ingress
    https://git.kernel.org/netdev/net/c/52f671db1882
  - [net,v3,2/2] net/sched: act_mirred: don't override retval if we already lost the skb
    https://git.kernel.org/netdev/net/c/166c2c8a6a4d

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-02-16 10:20 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-15 14:33 [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress Jakub Kicinski
2024-02-15 14:33 ` [PATCH net v3 2/2] net/sched: act_mirred: don't override retval if we already lost the skb Jakub Kicinski
2024-02-15 17:33   ` Jamal Hadi Salim
2024-02-15 17:33 ` [PATCH net v3 1/2] net/sched: act_mirred: use the backlog for mirred ingress Jamal Hadi Salim
2024-02-16 10:20 ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).