]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Mar 2021 16:06:44 +0000 (17:06 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Mar 2021 16:06:44 +0000 (17:06 +0100)
added patches:
net-qrtr-fix-memory-leak-in-qrtr_tun_open.patch
net_sched-fix-rtnl-deadlock-again-caused-by-request_module.patch

queue-5.10/net-qrtr-fix-memory-leak-in-qrtr_tun_open.patch [new file with mode: 0644]
queue-5.10/net_sched-fix-rtnl-deadlock-again-caused-by-request_module.patch [new file with mode: 0644]
queue-5.10/series

diff --git a/queue-5.10/net-qrtr-fix-memory-leak-in-qrtr_tun_open.patch b/queue-5.10/net-qrtr-fix-memory-leak-in-qrtr_tun_open.patch
new file mode 100644 (file)
index 0000000..5b6018f
--- /dev/null
@@ -0,0 +1,75 @@
+From fc0494ead6398609c49afa37bc949b61c5c16b91 Mon Sep 17 00:00:00 2001
+From: Takeshi Misawa <jeliantsurux@gmail.com>
+Date: Mon, 22 Feb 2021 08:44:27 +0900
+Subject: net: qrtr: Fix memory leak in qrtr_tun_open
+
+From: Takeshi Misawa <jeliantsurux@gmail.com>
+
+commit fc0494ead6398609c49afa37bc949b61c5c16b91 upstream.
+
+If qrtr_endpoint_register() failed, tun is leaked.
+Fix this, by freeing tun in error path.
+
+syzbot report:
+BUG: memory leak
+unreferenced object 0xffff88811848d680 (size 64):
+  comm "syz-executor684", pid 10171, jiffies 4294951561 (age 26.070s)
+  hex dump (first 32 bytes):
+    80 dd 0a 84 ff ff ff ff 00 00 00 00 00 00 00 00  ................
+    90 d6 48 18 81 88 ff ff 90 d6 48 18 81 88 ff ff  ..H.......H.....
+  backtrace:
+    [<0000000018992a50>] kmalloc include/linux/slab.h:552 [inline]
+    [<0000000018992a50>] kzalloc include/linux/slab.h:682 [inline]
+    [<0000000018992a50>] qrtr_tun_open+0x22/0x90 net/qrtr/tun.c:35
+    [<0000000003a453ef>] misc_open+0x19c/0x1e0 drivers/char/misc.c:141
+    [<00000000dec38ac8>] chrdev_open+0x10d/0x340 fs/char_dev.c:414
+    [<0000000079094996>] do_dentry_open+0x1e6/0x620 fs/open.c:817
+    [<000000004096d290>] do_open fs/namei.c:3252 [inline]
+    [<000000004096d290>] path_openat+0x74a/0x1b00 fs/namei.c:3369
+    [<00000000b8e64241>] do_filp_open+0xa0/0x190 fs/namei.c:3396
+    [<00000000a3299422>] do_sys_openat2+0xed/0x230 fs/open.c:1172
+    [<000000002c1bdcef>] do_sys_open fs/open.c:1188 [inline]
+    [<000000002c1bdcef>] __do_sys_openat fs/open.c:1204 [inline]
+    [<000000002c1bdcef>] __se_sys_openat fs/open.c:1199 [inline]
+    [<000000002c1bdcef>] __x64_sys_openat+0x7f/0xe0 fs/open.c:1199
+    [<00000000f3a5728f>] do_syscall_64+0x2d/0x70 arch/x86/entry/common.c:46
+    [<000000004b38b7ec>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+Fixes: 28fb4e59a47d ("net: qrtr: Expose tunneling endpoint to user space")
+Reported-by: syzbot+5d6e4af21385f5cfc56a@syzkaller.appspotmail.com
+Signed-off-by: Takeshi Misawa <jeliantsurux@gmail.com>
+Link: https://lore.kernel.org/r/20210221234427.GA2140@DESKTOP
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/qrtr/tun.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/net/qrtr/tun.c
++++ b/net/qrtr/tun.c
+@@ -31,6 +31,7 @@ static int qrtr_tun_send(struct qrtr_end
+ static int qrtr_tun_open(struct inode *inode, struct file *filp)
+ {
+       struct qrtr_tun *tun;
++      int ret;
+       tun = kzalloc(sizeof(*tun), GFP_KERNEL);
+       if (!tun)
+@@ -43,7 +44,16 @@ static int qrtr_tun_open(struct inode *i
+       filp->private_data = tun;
+-      return qrtr_endpoint_register(&tun->ep, QRTR_EP_NID_AUTO);
++      ret = qrtr_endpoint_register(&tun->ep, QRTR_EP_NID_AUTO);
++      if (ret)
++              goto out;
++
++      return 0;
++
++out:
++      filp->private_data = NULL;
++      kfree(tun);
++      return ret;
+ }
+ static ssize_t qrtr_tun_read_iter(struct kiocb *iocb, struct iov_iter *to)
diff --git a/queue-5.10/net_sched-fix-rtnl-deadlock-again-caused-by-request_module.patch b/queue-5.10/net_sched-fix-rtnl-deadlock-again-caused-by-request_module.patch
new file mode 100644 (file)
index 0000000..75661c0
--- /dev/null
@@ -0,0 +1,311 @@
+From d349f997686887906b1183b5be96933c5452362a Mon Sep 17 00:00:00 2001
+From: Cong Wang <cong.wang@bytedance.com>
+Date: Sat, 16 Jan 2021 16:56:57 -0800
+Subject: net_sched: fix RTNL deadlock again caused by request_module()
+
+From: Cong Wang <cong.wang@bytedance.com>
+
+commit d349f997686887906b1183b5be96933c5452362a upstream.
+
+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: syzbot+82752bc5331601cf4899@syzkaller.appspotmail.com
+Reported-and-tested-by: syzbot+b3b63b6bff456bd95294@syzkaller.appspotmail.com
+Reported-by: syzbot+ba67b12b1ca729912834@syzkaller.appspotmail.com
+Cc: Jiri Pirko <jiri@resnulli.us>
+Signed-off-by: Cong Wang <cong.wang@bytedance.com>
+Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://lore.kernel.org/r/20210117005657.14810-1-xiyou.wangcong@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/act_api.h |    5 +-
+ net/sched/act_api.c   |  104 +++++++++++++++++++++++++++++++-------------------
+ net/sched/cls_api.c   |   11 ++++-
+ 3 files changed, 79 insertions(+), 41 deletions(-)
+
+--- a/include/net/act_api.h
++++ b/include/net/act_api.h
+@@ -187,10 +187,13 @@ int tcf_action_init(struct net *net, str
+                   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);
+--- a/net/sched/act_api.c
++++ b/net/sched/act_api.c
+@@ -908,19 +908,13 @@ void tcf_idr_insert_many(struct tc_actio
+       }
+ }
+-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 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 nla_bitfield32 flags = { 0, 0 };
+-      u8 hw_stats = TCA_ACT_HW_STATS_ANY;
+-      struct tc_action *a;
++      struct nlattr *tb[TCA_ACT_MAX + 1];
+       struct tc_action_ops *a_o;
+-      struct tc_cookie *cookie = NULL;
+       char act_name[IFNAMSIZ];
+-      struct nlattr *tb[TCA_ACT_MAX + 1];
+       struct nlattr *kind;
+       int err;
+@@ -928,33 +922,21 @@ struct tc_action *tcf_action_init_1(stru
+               err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX, nla,
+                                                 tcf_action_policy, extack);
+               if (err < 0)
+-                      goto err_out;
++                      return ERR_PTR(err);
+               err = -EINVAL;
+               kind = tb[TCA_ACT_KIND];
+               if (!kind) {
+                       NL_SET_ERR_MSG(extack, "TC action kind must be specified");
+-                      goto err_out;
++                      return ERR_PTR(err);
+               }
+               if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ) {
+                       NL_SET_ERR_MSG(extack, "TC action name too long");
+-                      goto err_out;
++                      return ERR_PTR(err);
+               }
+-              if (tb[TCA_ACT_COOKIE]) {
+-                      cookie = nla_memdup_cookie(tb);
+-                      if (!cookie) {
+-                              NL_SET_ERR_MSG(extack, "No memory to generate TC cookie");
+-                              err = -ENOMEM;
+-                              goto err_out;
+-                      }
+-              }
+-              hw_stats = tcf_action_hw_stats_get(tb[TCA_ACT_HW_STATS]);
+-              if (tb[TCA_ACT_FLAGS])
+-                      flags = nla_get_bitfield32(tb[TCA_ACT_FLAGS]);
+       } else {
+               if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ) {
+                       NL_SET_ERR_MSG(extack, "TC action name too long");
+-                      err = -EINVAL;
+-                      goto err_out;
++                      return ERR_PTR(-EINVAL);
+               }
+       }
+@@ -976,24 +958,56 @@ struct tc_action *tcf_action_init_1(stru
+                * indicate this using -EAGAIN.
+                */
+               if (a_o != NULL) {
+-                      err = -EAGAIN;
+-                      goto err_mod;
++                      module_put(a_o->owner);
++                      return ERR_PTR(-EAGAIN);
+               }
+ #endif
+               NL_SET_ERR_MSG(extack, "Failed to load TC action module");
+-              err = -ENOENT;
+-              goto err_free;
++              return ERR_PTR(-ENOENT);
+       }
++      return a_o;
++}
++
++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,
++                                  struct tc_action_ops *a_o, bool rtnl_held,
++                                  struct netlink_ext_ack *extack)
++{
++      struct nla_bitfield32 flags = { 0, 0 };
++      u8 hw_stats = TCA_ACT_HW_STATS_ANY;
++      struct nlattr *tb[TCA_ACT_MAX + 1];
++      struct tc_cookie *cookie = NULL;
++      struct tc_action *a;
++      int err;
++
+       /* backward compatibility for policer */
+-      if (name == NULL)
++      if (name == NULL) {
++              err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX, nla,
++                                                tcf_action_policy, extack);
++              if (err < 0)
++                      return ERR_PTR(err);
++              if (tb[TCA_ACT_COOKIE]) {
++                      cookie = nla_memdup_cookie(tb);
++                      if (!cookie) {
++                              NL_SET_ERR_MSG(extack, "No memory to generate TC cookie");
++                              err = -ENOMEM;
++                              goto err_out;
++                      }
++              }
++              hw_stats = tcf_action_hw_stats_get(tb[TCA_ACT_HW_STATS]);
++              if (tb[TCA_ACT_FLAGS])
++                      flags = nla_get_bitfield32(tb[TCA_ACT_FLAGS]);
++
+               err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, ovr, bind,
+                               rtnl_held, tp, flags.value, extack);
+-      else
++      } else {
+               err = a_o->init(net, nla, est, &a, ovr, bind, rtnl_held,
+                               tp, flags.value, extack);
++      }
+       if (err < 0)
+-              goto err_mod;
++              goto err_out;
+       if (!name && tb[TCA_ACT_COOKIE])
+               tcf_set_action_cookie(&a->act_cookie, cookie);
+@@ -1010,14 +1024,11 @@ struct tc_action *tcf_action_init_1(stru
+       return a;
+-err_mod:
+-      module_put(a_o->owner);
+-err_free:
++err_out:
+       if (cookie) {
+               kfree(cookie->data);
+               kfree(cookie);
+       }
+-err_out:
+       return ERR_PTR(err);
+ }
+@@ -1028,6 +1039,7 @@ int tcf_action_init(struct net *net, str
+                   struct tc_action *actions[], size_t *attr_size,
+                   bool rtnl_held, struct netlink_ext_ack *extack)
+ {
++      struct tc_action_ops *ops[TCA_ACT_MAX_PRIO] = {};
+       struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
+       struct tc_action *act;
+       size_t sz = 0;
+@@ -1040,8 +1052,19 @@ int tcf_action_init(struct net *net, str
+               return err;
+       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], rtnl_held, extack);
++              if (IS_ERR(a_o)) {
++                      err = PTR_ERR(a_o);
++                      goto err_mod;
++              }
++              ops[i - 1] = a_o;
++      }
++
++      for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
+               act = tcf_action_init_1(net, tp, tb[i], est, name, ovr, bind,
+-                                      rtnl_held, extack);
++                                      ops[i - 1], rtnl_held, extack);
+               if (IS_ERR(act)) {
+                       err = PTR_ERR(act);
+                       goto err;
+@@ -1061,6 +1084,11 @@ int tcf_action_init(struct net *net, str
+ err:
+       tcf_action_destroy(actions, bind);
++err_mod:
++      for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
++              if (ops[i])
++                      module_put(ops[i]->owner);
++      }
+       return err;
+ }
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -3055,12 +3055,19 @@ int tcf_exts_validate(struct net *net, s
+               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;
index cdfb9c934be19f3c6984b2e81a9a7681fa888cca..6330c463c84eddd8a170486eabe136e123e1e6c0 100644 (file)
@@ -659,3 +659,5 @@ net-icmp-pass-zeroed-opts-from-icmp-v6-_ndo_send-before-sending.patch
 wireguard-selftests-test-multiple-parallel-streams.patch
 wireguard-queueing-get-rid-of-per-peer-ring-buffers.patch
 net-sched-fix-police-ext-initialization.patch
+net-qrtr-fix-memory-leak-in-qrtr_tun_open.patch
+net_sched-fix-rtnl-deadlock-again-caused-by-request_module.patch