]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.2-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 4 Sep 2019 17:36:47 +0000 (19:36 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 4 Sep 2019 17:36:47 +0000 (19:36 +0200)
added patches:
bpf-fix-use-after-free-in-prog-symbol-exposure.patch
hsr-implement-dellink-to-clean-up-resources.patch

queue-5.2/bpf-fix-use-after-free-in-prog-symbol-exposure.patch [new file with mode: 0644]
queue-5.2/hsr-implement-dellink-to-clean-up-resources.patch [new file with mode: 0644]
queue-5.2/series

diff --git a/queue-5.2/bpf-fix-use-after-free-in-prog-symbol-exposure.patch b/queue-5.2/bpf-fix-use-after-free-in-prog-symbol-exposure.patch
new file mode 100644 (file)
index 0000000..0e5b4c7
--- /dev/null
@@ -0,0 +1,127 @@
+From c751798aa224fadc5124b49eeb38fb468c0fa039 Mon Sep 17 00:00:00 2001
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 23 Aug 2019 22:14:23 +0200
+Subject: bpf: fix use after free in prog symbol exposure
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit c751798aa224fadc5124b49eeb38fb468c0fa039 upstream.
+
+syzkaller managed to trigger the warning in bpf_jit_free() which checks via
+bpf_prog_kallsyms_verify_off() for potentially unlinked JITed BPF progs
+in kallsyms, and subsequently trips over GPF when walking kallsyms entries:
+
+  [...]
+  8021q: adding VLAN 0 to HW filter on device batadv0
+  8021q: adding VLAN 0 to HW filter on device batadv0
+  WARNING: CPU: 0 PID: 9869 at kernel/bpf/core.c:810 bpf_jit_free+0x1e8/0x2a0
+  Kernel panic - not syncing: panic_on_warn set ...
+  CPU: 0 PID: 9869 Comm: kworker/0:7 Not tainted 5.0.0-rc8+ #1
+  Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
+  Workqueue: events bpf_prog_free_deferred
+  Call Trace:
+   __dump_stack lib/dump_stack.c:77 [inline]
+   dump_stack+0x113/0x167 lib/dump_stack.c:113
+   panic+0x212/0x40b kernel/panic.c:214
+   __warn.cold.8+0x1b/0x38 kernel/panic.c:571
+   report_bug+0x1a4/0x200 lib/bug.c:186
+   fixup_bug arch/x86/kernel/traps.c:178 [inline]
+   do_error_trap+0x11b/0x200 arch/x86/kernel/traps.c:271
+   do_invalid_op+0x36/0x40 arch/x86/kernel/traps.c:290
+   invalid_op+0x14/0x20 arch/x86/entry/entry_64.S:973
+  RIP: 0010:bpf_jit_free+0x1e8/0x2a0
+  Code: 02 4c 89 e2 83 e2 07 38 d0 7f 08 84 c0 0f 85 86 00 00 00 48 ba 00 02 00 00 00 00 ad de 0f b6 43 02 49 39 d6 0f 84 5f fe ff ff <0f> 0b e9 58 fe ff ff 48 b8 00 00 00 00 00 fc ff df 4c 89 e2 48 c1
+  RSP: 0018:ffff888092f67cd8 EFLAGS: 00010202
+  RAX: 0000000000000007 RBX: ffffc90001947000 RCX: ffffffff816e9d88
+  RDX: dead000000000200 RSI: 0000000000000008 RDI: ffff88808769f7f0
+  RBP: ffff888092f67d00 R08: fffffbfff1394059 R09: fffffbfff1394058
+  R10: fffffbfff1394058 R11: ffffffff89ca02c7 R12: ffffc90001947002
+  R13: ffffc90001947020 R14: ffffffff881eca80 R15: ffff88808769f7e8
+  BUG: unable to handle kernel paging request at fffffbfff400d000
+  #PF error: [normal kernel read fault]
+  PGD 21ffee067 P4D 21ffee067 PUD 21ffed067 PMD 9f942067 PTE 0
+  Oops: 0000 [#1] PREEMPT SMP KASAN
+  CPU: 0 PID: 9869 Comm: kworker/0:7 Not tainted 5.0.0-rc8+ #1
+  Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
+  Workqueue: events bpf_prog_free_deferred
+  RIP: 0010:bpf_get_prog_addr_region kernel/bpf/core.c:495 [inline]
+  RIP: 0010:bpf_tree_comp kernel/bpf/core.c:558 [inline]
+  RIP: 0010:__lt_find include/linux/rbtree_latch.h:115 [inline]
+  RIP: 0010:latch_tree_find include/linux/rbtree_latch.h:208 [inline]
+  RIP: 0010:bpf_prog_kallsyms_find+0x107/0x2e0 kernel/bpf/core.c:632
+  Code: 00 f0 ff ff 44 38 c8 7f 08 84 c0 0f 85 fa 00 00 00 41 f6 45 02 01 75 02 0f 0b 48 39 da 0f 82 92 00 00 00 48 89 d8 48 c1 e8 03 <42> 0f b6 04 30 84 c0 74 08 3c 03 0f 8e 45 01 00 00 8b 03 48 c1 e0
+  [...]
+
+Upon further debugging, it turns out that whenever we trigger this
+issue, the kallsyms removal in bpf_prog_ksym_node_del() was /skipped/
+but yet bpf_jit_free() reported that the entry is /in use/.
+
+Problem is that symbol exposure via bpf_prog_kallsyms_add() but also
+perf_event_bpf_event() were done /after/ bpf_prog_new_fd(). Once the
+fd is exposed to the public, a parallel close request came in right
+before we attempted to do the bpf_prog_kallsyms_add().
+
+Given at this time the prog reference count is one, we start to rip
+everything underneath us via bpf_prog_release() -> bpf_prog_put().
+The memory is eventually released via deferred free, so we're seeing
+that bpf_jit_free() has a kallsym entry because we added it from
+bpf_prog_load() but /after/ bpf_prog_put() from the remote CPU.
+
+Therefore, move both notifications /before/ we install the fd. The
+issue was never seen between bpf_prog_alloc_id() and bpf_prog_new_fd()
+because upon bpf_prog_get_fd_by_id() we'll take another reference to
+the BPF prog, so we're still holding the original reference from the
+bpf_prog_load().
+
+Fixes: 6ee52e2a3fe4 ("perf, bpf: Introduce PERF_RECORD_BPF_EVENT")
+Fixes: 74451e66d516 ("bpf: make jited programs visible in traces")
+Reported-by: syzbot+bd3bba6ff3fcea7a6ec6@syzkaller.appspotmail.com
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Cc: Song Liu <songliubraving@fb.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/bpf/syscall.c |   30 ++++++++++++++++++------------
+ 1 file changed, 18 insertions(+), 12 deletions(-)
+
+--- a/kernel/bpf/syscall.c
++++ b/kernel/bpf/syscall.c
+@@ -1686,20 +1686,26 @@ static int bpf_prog_load(union bpf_attr
+       if (err)
+               goto free_used_maps;
+-      err = bpf_prog_new_fd(prog);
+-      if (err < 0) {
+-              /* failed to allocate fd.
+-               * bpf_prog_put() is needed because the above
+-               * bpf_prog_alloc_id() has published the prog
+-               * to the userspace and the userspace may
+-               * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID.
+-               */
+-              bpf_prog_put(prog);
+-              return err;
+-      }
+-
++      /* Upon success of bpf_prog_alloc_id(), the BPF prog is
++       * effectively publicly exposed. However, retrieving via
++       * bpf_prog_get_fd_by_id() will take another reference,
++       * therefore it cannot be gone underneath us.
++       *
++       * Only for the time /after/ successful bpf_prog_new_fd()
++       * and before returning to userspace, we might just hold
++       * one reference and any parallel close on that fd could
++       * rip everything out. Hence, below notifications must
++       * happen before bpf_prog_new_fd().
++       *
++       * Also, any failure handling from this point onwards must
++       * be using bpf_prog_put() given the program is exposed.
++       */
+       bpf_prog_kallsyms_add(prog);
+       perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0);
++
++      err = bpf_prog_new_fd(prog);
++      if (err < 0)
++              bpf_prog_put(prog);
+       return err;
+ free_used_maps:
diff --git a/queue-5.2/hsr-implement-dellink-to-clean-up-resources.patch b/queue-5.2/hsr-implement-dellink-to-clean-up-resources.patch
new file mode 100644 (file)
index 0000000..802be1b
--- /dev/null
@@ -0,0 +1,152 @@
+From b9a1e627405d68d475a3c1f35e685ccfb5bbe668 Mon Sep 17 00:00:00 2001
+From: Cong Wang <xiyou.wangcong@gmail.com>
+Date: Wed, 3 Jul 2019 17:21:13 -0700
+Subject: hsr: implement dellink to clean up resources
+
+From: Cong Wang <xiyou.wangcong@gmail.com>
+
+commit b9a1e627405d68d475a3c1f35e685ccfb5bbe668 upstream.
+
+hsr_link_ops implements ->newlink() but not ->dellink(),
+which leads that resources not released after removing the device,
+particularly the entries in self_node_db and node_db.
+
+So add ->dellink() implementation to replace the priv_destructor.
+This also makes the code slightly easier to understand.
+
+Reported-by: syzbot+c6167ec3de7def23d1e8@syzkaller.appspotmail.com
+Cc: Arvid Brodin <arvid.brodin@alten.se>
+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>
+
+---
+ net/hsr/hsr_device.c   |   13 +++++--------
+ net/hsr/hsr_device.h   |    1 +
+ net/hsr/hsr_framereg.c |   11 ++++++++++-
+ net/hsr/hsr_framereg.h |    3 ++-
+ net/hsr/hsr_netlink.c  |    7 +++++++
+ 5 files changed, 25 insertions(+), 10 deletions(-)
+
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -344,10 +344,7 @@ static void hsr_announce(struct timer_li
+       rcu_read_unlock();
+ }
+-/* According to comments in the declaration of struct net_device, this function
+- * is "Called from unregister, can be used to call free_netdev". Ok then...
+- */
+-static void hsr_dev_destroy(struct net_device *hsr_dev)
++void hsr_dev_destroy(struct net_device *hsr_dev)
+ {
+       struct hsr_priv *hsr;
+       struct hsr_port *port;
+@@ -356,15 +353,16 @@ static void hsr_dev_destroy(struct net_d
+       hsr_debugfs_term(hsr);
+-      rtnl_lock();
+       hsr_for_each_port(hsr, port)
+               hsr_del_port(port);
+-      rtnl_unlock();
+       del_timer_sync(&hsr->prune_timer);
+       del_timer_sync(&hsr->announce_timer);
+       synchronize_rcu();
++
++      hsr_del_self_node(&hsr->self_node_db);
++      hsr_del_nodes(&hsr->node_db);
+ }
+ static const struct net_device_ops hsr_device_ops = {
+@@ -391,7 +389,6 @@ void hsr_dev_setup(struct net_device *de
+       dev->priv_flags |= IFF_NO_QUEUE;
+       dev->needs_free_netdev = true;
+-      dev->priv_destructor = hsr_dev_destroy;
+       dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
+                          NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |
+@@ -495,7 +492,7 @@ fail:
+       hsr_for_each_port(hsr, port)
+               hsr_del_port(port);
+ err_add_port:
+-      hsr_del_node(&hsr->self_node_db);
++      hsr_del_self_node(&hsr->self_node_db);
+       return res;
+ }
+--- a/net/hsr/hsr_device.h
++++ b/net/hsr/hsr_device.h
+@@ -14,6 +14,7 @@
+ void hsr_dev_setup(struct net_device *dev);
+ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
+                    unsigned char multicast_spec, u8 protocol_version);
++void hsr_dev_destroy(struct net_device *hsr_dev);
+ void hsr_check_carrier_and_operstate(struct hsr_priv *hsr);
+ bool is_hsr_master(struct net_device *dev);
+ int hsr_get_max_mtu(struct hsr_priv *hsr);
+--- a/net/hsr/hsr_framereg.c
++++ b/net/hsr/hsr_framereg.c
+@@ -104,7 +104,7 @@ int hsr_create_self_node(struct list_hea
+       return 0;
+ }
+-void hsr_del_node(struct list_head *self_node_db)
++void hsr_del_self_node(struct list_head *self_node_db)
+ {
+       struct hsr_node *node;
+@@ -117,6 +117,15 @@ void hsr_del_node(struct list_head *self
+       }
+ }
++void hsr_del_nodes(struct list_head *node_db)
++{
++      struct hsr_node *node;
++      struct hsr_node *tmp;
++
++      list_for_each_entry_safe(node, tmp, node_db, mac_list)
++              kfree(node);
++}
++
+ /* Allocate an hsr_node and add it to node_db. 'addr' is the node's address_A;
+  * seq_out is used to initialize filtering of outgoing duplicate frames
+  * originating from the newly added node.
+--- a/net/hsr/hsr_framereg.h
++++ b/net/hsr/hsr_framereg.h
+@@ -12,7 +12,8 @@
+ struct hsr_node;
+-void hsr_del_node(struct list_head *self_node_db);
++void hsr_del_self_node(struct list_head *self_node_db);
++void hsr_del_nodes(struct list_head *node_db);
+ struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[],
+                             u16 seq_out);
+ struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb,
+--- a/net/hsr/hsr_netlink.c
++++ b/net/hsr/hsr_netlink.c
+@@ -69,6 +69,12 @@ static int hsr_newlink(struct net *src_n
+       return hsr_dev_finalize(dev, link, multicast_spec, hsr_version);
+ }
++static void hsr_dellink(struct net_device *hsr_dev, struct list_head *head)
++{
++      hsr_dev_destroy(hsr_dev);
++      unregister_netdevice_queue(hsr_dev, head);
++}
++
+ static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev)
+ {
+       struct hsr_priv *hsr;
+@@ -113,6 +119,7 @@ static struct rtnl_link_ops hsr_link_ops
+       .priv_size      = sizeof(struct hsr_priv),
+       .setup          = hsr_dev_setup,
+       .newlink        = hsr_newlink,
++      .dellink        = hsr_dellink,
+       .fill_info      = hsr_fill_info,
+ };
index 386896c1fe1e22a67970bed025ecf99063c30949..5b3c63225176dcaf08b7d7a5a909abaf1ffe4de1 100644 (file)
@@ -139,3 +139,5 @@ iwlwifi-pcie-handle-switching-killer-qu-b0-nics-to-c.patch
 drm-i915-do-not-create-a-new-max_bpc-prop-for-mst-co.patch
 drm-i915-dp-fix-dsc-enable-code-to-use-cpu_transcode.patch
 x86-ptrace-fix-up-botched-merge-of-spectrev1-fix.patch
+bpf-fix-use-after-free-in-prog-symbol-exposure.patch
+hsr-implement-dellink-to-clean-up-resources.patch