]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 30 Jan 2020 10:18:34 +0000 (11:18 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 30 Jan 2020 10:18:34 +0000 (11:18 +0100)
added patches:
net_sched-ematch-reject-invalid-tcf_em_simple.patch
net_sched-fix-ops-bind_class-implementations.patch

queue-4.19/net_sched-ematch-reject-invalid-tcf_em_simple.patch [new file with mode: 0644]
queue-4.19/net_sched-fix-ops-bind_class-implementations.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/net_sched-ematch-reject-invalid-tcf_em_simple.patch b/queue-4.19/net_sched-ematch-reject-invalid-tcf_em_simple.patch
new file mode 100644 (file)
index 0000000..6e6615d
--- /dev/null
@@ -0,0 +1,79 @@
+From foo@baz Thu 30 Jan 2020 11:17:10 AM CET
+From: Eric Dumazet <edumazet@google.com>
+Date: Fri, 24 Jan 2020 14:57:20 -0800
+Subject: net_sched: ematch: reject invalid TCF_EM_SIMPLE
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 55cd9f67f1e45de8517cdaab985fb8e56c0bc1d8 ]
+
+It is possible for malicious userspace to set TCF_EM_SIMPLE bit
+even for matches that should not have this bit set.
+
+This can fool two places using tcf_em_is_simple()
+
+1) tcf_em_tree_destroy() -> memory leak of em->data
+   if ops->destroy() is NULL
+
+2) tcf_em_tree_dump() wrongly report/leak 4 low-order bytes
+   of a kernel pointer.
+
+BUG: memory leak
+unreferenced object 0xffff888121850a40 (size 32):
+  comm "syz-executor927", pid 7193, jiffies 4294941655 (age 19.840s)
+  hex dump (first 32 bytes):
+    00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00  ................
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+  backtrace:
+    [<00000000f67036ea>] kmemleak_alloc_recursive include/linux/kmemleak.h:43 [inline]
+    [<00000000f67036ea>] slab_post_alloc_hook mm/slab.h:586 [inline]
+    [<00000000f67036ea>] slab_alloc mm/slab.c:3320 [inline]
+    [<00000000f67036ea>] __do_kmalloc mm/slab.c:3654 [inline]
+    [<00000000f67036ea>] __kmalloc_track_caller+0x165/0x300 mm/slab.c:3671
+    [<00000000fab0cc8e>] kmemdup+0x27/0x60 mm/util.c:127
+    [<00000000d9992e0a>] kmemdup include/linux/string.h:453 [inline]
+    [<00000000d9992e0a>] em_nbyte_change+0x5b/0x90 net/sched/em_nbyte.c:32
+    [<000000007e04f711>] tcf_em_validate net/sched/ematch.c:241 [inline]
+    [<000000007e04f711>] tcf_em_tree_validate net/sched/ematch.c:359 [inline]
+    [<000000007e04f711>] tcf_em_tree_validate+0x332/0x46f net/sched/ematch.c:300
+    [<000000007a769204>] basic_set_parms net/sched/cls_basic.c:157 [inline]
+    [<000000007a769204>] basic_change+0x1d7/0x5f0 net/sched/cls_basic.c:219
+    [<00000000e57a5997>] tc_new_tfilter+0x566/0xf70 net/sched/cls_api.c:2104
+    [<0000000074b68559>] rtnetlink_rcv_msg+0x3b2/0x4b0 net/core/rtnetlink.c:5415
+    [<00000000b7fe53fb>] netlink_rcv_skb+0x61/0x170 net/netlink/af_netlink.c:2477
+    [<00000000e83a40d0>] rtnetlink_rcv+0x1d/0x30 net/core/rtnetlink.c:5442
+    [<00000000d62ba933>] netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline]
+    [<00000000d62ba933>] netlink_unicast+0x223/0x310 net/netlink/af_netlink.c:1328
+    [<0000000088070f72>] netlink_sendmsg+0x2c0/0x570 net/netlink/af_netlink.c:1917
+    [<00000000f70b15ea>] sock_sendmsg_nosec net/socket.c:639 [inline]
+    [<00000000f70b15ea>] sock_sendmsg+0x54/0x70 net/socket.c:659
+    [<00000000ef95a9be>] ____sys_sendmsg+0x2d0/0x300 net/socket.c:2330
+    [<00000000b650f1ab>] ___sys_sendmsg+0x8a/0xd0 net/socket.c:2384
+    [<0000000055bfa74a>] __sys_sendmsg+0x80/0xf0 net/socket.c:2417
+    [<000000002abac183>] __do_sys_sendmsg net/socket.c:2426 [inline]
+    [<000000002abac183>] __se_sys_sendmsg net/socket.c:2424 [inline]
+    [<000000002abac183>] __x64_sys_sendmsg+0x23/0x30 net/socket.c:2424
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reported-by: syzbot+03c4738ed29d5d366ddf@syzkaller.appspotmail.com
+Cc: Cong Wang <xiyou.wangcong@gmail.com>
+Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sched/ematch.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/net/sched/ematch.c
++++ b/net/sched/ematch.c
+@@ -242,6 +242,9 @@ static int tcf_em_validate(struct tcf_pr
+                       goto errout;
+               if (em->ops->change) {
++                      err = -EINVAL;
++                      if (em_hdr->flags & TCF_EM_SIMPLE)
++                              goto errout;
+                       err = em->ops->change(net, data, data_len, em);
+                       if (err < 0)
+                               goto errout;
diff --git a/queue-4.19/net_sched-fix-ops-bind_class-implementations.patch b/queue-4.19/net_sched-fix-ops-bind_class-implementations.patch
new file mode 100644 (file)
index 0000000..b506f36
--- /dev/null
@@ -0,0 +1,364 @@
+From foo@baz Thu 30 Jan 2020 11:17:10 AM CET
+From: Cong Wang <xiyou.wangcong@gmail.com>
+Date: Thu, 23 Jan 2020 16:26:18 -0800
+Subject: net_sched: fix ops->bind_class() implementations
+
+From: Cong Wang <xiyou.wangcong@gmail.com>
+
+[ Upstream commit 2e24cd755552350b94a7617617c6877b8cbcb701 ]
+
+The current implementations of ops->bind_class() are merely
+searching for classid and updating class in the struct tcf_result,
+without invoking either of cl_ops->bind_tcf() or
+cl_ops->unbind_tcf(). This breaks the design of them as qdisc's
+like cbq use them to count filters too. This is why syzbot triggered
+the warning in cbq_destroy_class().
+
+In order to fix this, we have to call cl_ops->bind_tcf() and
+cl_ops->unbind_tcf() like the filter binding path. This patch does
+so by refactoring out two helper functions __tcf_bind_filter()
+and __tcf_unbind_filter(), which are lockless and accept a Qdisc
+pointer, then teaching each implementation to call them correctly.
+
+Note, we merely pass the Qdisc pointer as an opaque pointer to
+each filter, they only need to pass it down to the helper
+functions without understanding it at all.
+
+Fixes: 07d79fc7d94e ("net_sched: add reverse binding for tc class")
+Reported-and-tested-by: syzbot+0a0596220218fcb603a8@syzkaller.appspotmail.com
+Reported-and-tested-by: syzbot+63bdb6006961d8c917c6@syzkaller.appspotmail.com
+Cc: Jamal Hadi Salim <jhs@mojatatu.com>
+Cc: Jiri Pirko <jiri@resnulli.us>
+Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/pkt_cls.h     |   33 +++++++++++++++++++--------------
+ include/net/sch_generic.h |    3 ++-
+ net/sched/cls_basic.c     |   11 ++++++++---
+ net/sched/cls_bpf.c       |   11 ++++++++---
+ net/sched/cls_flower.c    |   11 ++++++++---
+ net/sched/cls_fw.c        |   11 ++++++++---
+ net/sched/cls_matchall.c  |   11 ++++++++---
+ net/sched/cls_route.c     |   11 ++++++++---
+ net/sched/cls_rsvp.h      |   11 ++++++++---
+ net/sched/cls_tcindex.c   |   11 ++++++++---
+ net/sched/cls_u32.c       |   11 ++++++++---
+ net/sched/sch_api.c       |    6 ++++--
+ 12 files changed, 97 insertions(+), 44 deletions(-)
+
+--- a/include/net/pkt_cls.h
++++ b/include/net/pkt_cls.h
+@@ -206,31 +206,38 @@ __cls_set_class(unsigned long *clp, unsi
+       return xchg(clp, cl);
+ }
+-static inline unsigned long
+-cls_set_class(struct Qdisc *q, unsigned long *clp, unsigned long cl)
++static inline void
++__tcf_bind_filter(struct Qdisc *q, struct tcf_result *r, unsigned long base)
+ {
+-      unsigned long old_cl;
++      unsigned long cl;
+-      sch_tree_lock(q);
+-      old_cl = __cls_set_class(clp, cl);
+-      sch_tree_unlock(q);
+-      return old_cl;
++      cl = q->ops->cl_ops->bind_tcf(q, base, r->classid);
++      cl = __cls_set_class(&r->class, cl);
++      if (cl)
++              q->ops->cl_ops->unbind_tcf(q, cl);
+ }
+ static inline void
+ tcf_bind_filter(struct tcf_proto *tp, struct tcf_result *r, unsigned long base)
+ {
+       struct Qdisc *q = tp->chain->block->q;
+-      unsigned long cl;
+       /* Check q as it is not set for shared blocks. In that case,
+        * setting class is not supported.
+        */
+       if (!q)
+               return;
+-      cl = q->ops->cl_ops->bind_tcf(q, base, r->classid);
+-      cl = cls_set_class(q, &r->class, cl);
+-      if (cl)
++      sch_tree_lock(q);
++      __tcf_bind_filter(q, r, base);
++      sch_tree_unlock(q);
++}
++
++static inline void
++__tcf_unbind_filter(struct Qdisc *q, struct tcf_result *r)
++{
++      unsigned long cl;
++
++      if ((cl = __cls_set_class(&r->class, 0)) != 0)
+               q->ops->cl_ops->unbind_tcf(q, cl);
+ }
+@@ -238,12 +245,10 @@ static inline void
+ tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r)
+ {
+       struct Qdisc *q = tp->chain->block->q;
+-      unsigned long cl;
+       if (!q)
+               return;
+-      if ((cl = __cls_set_class(&r->class, 0)) != 0)
+-              q->ops->cl_ops->unbind_tcf(q, cl);
++      __tcf_unbind_filter(q, r);
+ }
+ struct tcf_exts {
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -273,7 +273,8 @@ struct tcf_proto_ops {
+       int                     (*reoffload)(struct tcf_proto *tp, bool add,
+                                            tc_setup_cb_t *cb, void *cb_priv,
+                                            struct netlink_ext_ack *extack);
+-      void                    (*bind_class)(void *, u32, unsigned long);
++      void                    (*bind_class)(void *, u32, unsigned long,
++                                            void *, unsigned long);
+       void *                  (*tmplt_create)(struct net *net,
+                                               struct tcf_chain *chain,
+                                               struct nlattr **tca,
+--- a/net/sched/cls_basic.c
++++ b/net/sched/cls_basic.c
+@@ -254,12 +254,17 @@ skip:
+       }
+ }
+-static void basic_bind_class(void *fh, u32 classid, unsigned long cl)
++static void basic_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
++                           unsigned long base)
+ {
+       struct basic_filter *f = fh;
+-      if (f && f->res.classid == classid)
+-              f->res.class = cl;
++      if (f && f->res.classid == classid) {
++              if (cl)
++                      __tcf_bind_filter(q, &f->res, base);
++              else
++                      __tcf_unbind_filter(q, &f->res);
++      }
+ }
+ static int basic_dump(struct net *net, struct tcf_proto *tp, void *fh,
+--- a/net/sched/cls_bpf.c
++++ b/net/sched/cls_bpf.c
+@@ -627,12 +627,17 @@ nla_put_failure:
+       return -1;
+ }
+-static void cls_bpf_bind_class(void *fh, u32 classid, unsigned long cl)
++static void cls_bpf_bind_class(void *fh, u32 classid, unsigned long cl,
++                             void *q, unsigned long base)
+ {
+       struct cls_bpf_prog *prog = fh;
+-      if (prog && prog->res.classid == classid)
+-              prog->res.class = cl;
++      if (prog && prog->res.classid == classid) {
++              if (cl)
++                      __tcf_bind_filter(q, &prog->res, base);
++              else
++                      __tcf_unbind_filter(q, &prog->res);
++      }
+ }
+ static void cls_bpf_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+--- a/net/sched/cls_flower.c
++++ b/net/sched/cls_flower.c
+@@ -1942,12 +1942,17 @@ nla_put_failure:
+       return -EMSGSIZE;
+ }
+-static void fl_bind_class(void *fh, u32 classid, unsigned long cl)
++static void fl_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
++                        unsigned long base)
+ {
+       struct cls_fl_filter *f = fh;
+-      if (f && f->res.classid == classid)
+-              f->res.class = cl;
++      if (f && f->res.classid == classid) {
++              if (cl)
++                      __tcf_bind_filter(q, &f->res, base);
++              else
++                      __tcf_unbind_filter(q, &f->res);
++      }
+ }
+ static struct tcf_proto_ops cls_fl_ops __read_mostly = {
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -432,12 +432,17 @@ nla_put_failure:
+       return -1;
+ }
+-static void fw_bind_class(void *fh, u32 classid, unsigned long cl)
++static void fw_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
++                        unsigned long base)
+ {
+       struct fw_filter *f = fh;
+-      if (f && f->res.classid == classid)
+-              f->res.class = cl;
++      if (f && f->res.classid == classid) {
++              if (cl)
++                      __tcf_bind_filter(q, &f->res, base);
++              else
++                      __tcf_unbind_filter(q, &f->res);
++      }
+ }
+ static struct tcf_proto_ops cls_fw_ops __read_mostly = {
+--- a/net/sched/cls_matchall.c
++++ b/net/sched/cls_matchall.c
+@@ -310,12 +310,17 @@ nla_put_failure:
+       return -1;
+ }
+-static void mall_bind_class(void *fh, u32 classid, unsigned long cl)
++static void mall_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
++                          unsigned long base)
+ {
+       struct cls_mall_head *head = fh;
+-      if (head && head->res.classid == classid)
+-              head->res.class = cl;
++      if (head && head->res.classid == classid) {
++              if (cl)
++                      __tcf_bind_filter(q, &head->res, base);
++              else
++                      __tcf_unbind_filter(q, &head->res);
++      }
+ }
+ static struct tcf_proto_ops cls_mall_ops __read_mostly = {
+--- a/net/sched/cls_route.c
++++ b/net/sched/cls_route.c
+@@ -645,12 +645,17 @@ nla_put_failure:
+       return -1;
+ }
+-static void route4_bind_class(void *fh, u32 classid, unsigned long cl)
++static void route4_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
++                            unsigned long base)
+ {
+       struct route4_filter *f = fh;
+-      if (f && f->res.classid == classid)
+-              f->res.class = cl;
++      if (f && f->res.classid == classid) {
++              if (cl)
++                      __tcf_bind_filter(q, &f->res, base);
++              else
++                      __tcf_unbind_filter(q, &f->res);
++      }
+ }
+ static struct tcf_proto_ops cls_route4_ops __read_mostly = {
+--- a/net/sched/cls_rsvp.h
++++ b/net/sched/cls_rsvp.h
+@@ -736,12 +736,17 @@ nla_put_failure:
+       return -1;
+ }
+-static void rsvp_bind_class(void *fh, u32 classid, unsigned long cl)
++static void rsvp_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
++                          unsigned long base)
+ {
+       struct rsvp_filter *f = fh;
+-      if (f && f->res.classid == classid)
+-              f->res.class = cl;
++      if (f && f->res.classid == classid) {
++              if (cl)
++                      __tcf_bind_filter(q, &f->res, base);
++              else
++                      __tcf_unbind_filter(q, &f->res);
++      }
+ }
+ static struct tcf_proto_ops RSVP_OPS __read_mostly = {
+--- a/net/sched/cls_tcindex.c
++++ b/net/sched/cls_tcindex.c
+@@ -652,12 +652,17 @@ nla_put_failure:
+       return -1;
+ }
+-static void tcindex_bind_class(void *fh, u32 classid, unsigned long cl)
++static void tcindex_bind_class(void *fh, u32 classid, unsigned long cl,
++                             void *q, unsigned long base)
+ {
+       struct tcindex_filter_result *r = fh;
+-      if (r && r->res.classid == classid)
+-              r->res.class = cl;
++      if (r && r->res.classid == classid) {
++              if (cl)
++                      __tcf_bind_filter(q, &r->res, base);
++              else
++                      __tcf_unbind_filter(q, &r->res);
++      }
+ }
+ static struct tcf_proto_ops cls_tcindex_ops __read_mostly = {
+--- a/net/sched/cls_u32.c
++++ b/net/sched/cls_u32.c
+@@ -1315,12 +1315,17 @@ static int u32_reoffload(struct tcf_prot
+       return 0;
+ }
+-static void u32_bind_class(void *fh, u32 classid, unsigned long cl)
++static void u32_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
++                         unsigned long base)
+ {
+       struct tc_u_knode *n = fh;
+-      if (n && n->res.classid == classid)
+-              n->res.class = cl;
++      if (n && n->res.classid == classid) {
++              if (cl)
++                      __tcf_bind_filter(q, &n->res, base);
++              else
++                      __tcf_unbind_filter(q, &n->res);
++      }
+ }
+ static int u32_dump(struct net *net, struct tcf_proto *tp, void *fh,
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -1803,8 +1803,9 @@ static int tclass_del_notify(struct net
+ struct tcf_bind_args {
+       struct tcf_walker w;
+-      u32 classid;
++      unsigned long base;
+       unsigned long cl;
++      u32 classid;
+ };
+ static int tcf_node_bind(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
+@@ -1815,7 +1816,7 @@ static int tcf_node_bind(struct tcf_prot
+               struct Qdisc *q = tcf_block_q(tp->chain->block);
+               sch_tree_lock(q);
+-              tp->ops->bind_class(n, a->classid, a->cl);
++              tp->ops->bind_class(n, a->classid, a->cl, q, a->base);
+               sch_tree_unlock(q);
+       }
+       return 0;
+@@ -1846,6 +1847,7 @@ static void tc_bind_tclass(struct Qdisc
+                       arg.w.fn = tcf_node_bind;
+                       arg.classid = clid;
++                      arg.base = cl;
+                       arg.cl = new_cl;
+                       tp->ops->walk(tp, &arg.w);
+               }
index 6dc3154d4e4bffcb1bc685d437bffe2b2a4dcecc..ba737fcaeec1a3b82fe3fb668b62fa56a6b874e4 100644 (file)
@@ -20,3 +20,5 @@ ath9k-fix-storage-endpoint-lookup.patch
 brcmfmac-fix-interface-sanity-check.patch
 rtl8xxxu-fix-interface-sanity-check.patch
 zd1211rw-fix-storage-endpoint-lookup.patch
+net_sched-ematch-reject-invalid-tcf_em_simple.patch
+net_sched-fix-ops-bind_class-implementations.patch