Skip to contentSkip to conversation

FAILED: patch "[PATCH] net_sched: fix RTNL deadlock again caused by request_module()" failed to apply to 5.4-stable tree

PATCH [email protected] 2 participants 4 messages Mar 1, 2021 – Mar 3, 2021

Subsystems (3)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From d349f997686887906b1183b5be96933c5452362a Mon Sep 17 00:00:00 2001
From: Cong Wang <[email protected]>
Date: Sat, 16 Jan 2021 16:56:57 -0800
Subject: [PATCH] net_sched: fix RTNL deadlock again caused by request_module()

tcf_action_init_1() loads tc action modules automatically with request_module() after parsing the tc action names, and it drops RTNL lock and re-holds it before and after request_module(). This causes a lot of troubles, as discovered by syzbot, because we can be in the middle of batch initializations when we create an array of tc actions.

One of the problem is deadlock:

CPU 0 CPU 1
rtnl_lock();
for (...) {

  tcf_action_init_1();
    -> rtnl_unlock();
    -> request_module();
				rtnl_lock();
				for (...) {
				  tcf_action_init_1();
				    -> tcf_idr_check_alloc();
				   // Insert one action into idr,
				   // but it is not committed until
				   // tcf_idr_insert_many(), then drop
				   // the RTNL lock in the _next_
				   // iteration
				   -> rtnl_unlock();
    -> rtnl_lock();
    -> a_o->init();
      -> tcf_idr_check_alloc();
      // Now waiting for the same index
      // to be committed
				    -> request_module();
				    -> rtnl_lock()
				    // Now waiting for RTNL lock
				}
				rtnl_unlock();
}

rtnl_unlock();

This is not easy to solve, we can move the request_module() before this loop and pre-load all the modules we need for this netlink message and then do the rest initializations. So the loop breaks down to two now:

        for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
                struct tc_action_ops *a_o;

                a_o = tc_action_load_ops(name, tb[i]...);
                ops[i - 1] = a_o;
        }

        for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
                act = tcf_action_init_1(ops[i - 1]...);
        }

Although this looks serious, it only has been reported by syzbot, so it seems hard to trigger this by humans. And given the size of this patch, I'd suggest to make it to net-next and not to backport to stable.

This patch has been tested by syzbot and tested with tdc.py by me.

Fixes 0fedc63fadf0 ("net_sched: commit action insertions together")
Reported-and-tested-by [email protected]
Reported-and-tested-by [email protected]
Reported-by [email protected]
Cc Jiri Pirko <[email protected]>
include/net/act_api.h +4 -1
index 55dab604861f..761c0e331915 100644
@@ -186,10 +186,13 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
 		    struct nlattr *est, char *name, int ovr, int bind,
 		    struct tc_action *actions[], size_t *attr_size,
 		    bool rtnl_held, struct netlink_ext_ack *extack);
+struct tc_action_ops *tc_action_load_ops(char *name, struct nlattr *nla,
+					 bool rtnl_held,
+					 struct netlink_ext_ack *extack);
 struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 				    struct nlattr *nla, struct nlattr *est,
 				    char *name, int ovr, int bind,
-				    bool rtnl_held,
+				    struct tc_action_ops *ops, bool rtnl_held,
 				    struct netlink_ext_ack *extack);
 int tcf_action_dump(struct sk_buff *skb, struct tc_action *actions[], int bind,
 		    int ref, bool terse);
net/sched/act_api.c +66 -38

177 lines not on this page · raw message

net/sched/cls_api.c +9 -2
index 37b77bd30974..a67c66a512a4 100644
@@ -3043,12 +3043,19 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
 		size_t attr_size = 0;
 
 		if (exts->police && tb[exts->police]) {
+			struct tc_action_ops *a_o;
+
+			a_o = tc_action_load_ops("police", tb[exts->police], rtnl_held, extack);
+			if (IS_ERR(a_o))
+				return PTR_ERR(a_o);
 			act = tcf_action_init_1(net, tp, tb[exts->police],
 						rate_tlv, "police", ovr,
-						TCA_ACT_BIND, rtnl_held,
+						TCA_ACT_BIND, a_o, rtnl_held,
 						extack);
-			if (IS_ERR(act))
+			if (IS_ERR(act)) {
+				module_put(a_o->owner);
 				return PTR_ERR(act);
+			}
 
 			act->type = exts->type = TCA_OLD_COMPAT;
 			exts->actions[0] = act;
#1 lore raw
Quoted 6 lines · On Mon, Mar 1, 2021 at 8:02 AM <[email protected]> wrote:

The patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

This patch is not suitable for -stable due to its large size.

Thanks.

author maintainer
#2 lore raw
Quoted 9 lines · Cong Wang .
Quoted 6 lines · On Mon, Mar 1, 2021 at 8:02 AM <[email protected]> wrote:

The patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

This patch is not suitable for -stable due to its large size.

The size here is fine:

 3 files changed, 79 insertions(+), 41 deletions(-)

Given that syzbot can trigger this, that means that humans can as well, so why shouldn't we fix this?

thanks,

greg k-h

#3 lore raw
Quoted 10 lines · Greg KH
Quoted 8 lines · Cong Wang .
Quoted 6 lines · On Mon, Mar 1, 2021 at 8:02 AM <[email protected]> wrote:

The patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

Quoted 5 lines
Quoted 1 line

This patch is not suitable for -stable due to its large size.

The size here is fine:

 3 files changed, 79 insertions(+), 41 deletions(-)

If you are fine with this, sure. I will take a look at your backports.

Quoted 2 lines

Given that syzbot can trigger this, that means that humans can as well, so why shouldn't we fix this?

I meant, it existed for a long time, probably longer than what the Fixes tag indicates, and no human reported it.

Thanks.