]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 11 Sep 2020 07:57:14 +0000 (09:57 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 11 Sep 2020 07:57:14 +0000 (09:57 +0200)
added patches:
bnxt-don-t-enable-napi-until-rings-are-ready.patch
net-disable-netpoll-on-fresh-napis.patch
net-usb-dm9601-add-usb-id-of-keenetic-plus-dsl.patch
netlabel-fix-problems-with-mapping-removal.patch
sctp-not-disable-bh-in-the-whole-sctp_get_port_local.patch
tipc-fix-shutdown-of-connectionless-socket.patch

queue-4.14/bnxt-don-t-enable-napi-until-rings-are-ready.patch [new file with mode: 0644]
queue-4.14/net-disable-netpoll-on-fresh-napis.patch [new file with mode: 0644]
queue-4.14/net-usb-dm9601-add-usb-id-of-keenetic-plus-dsl.patch [new file with mode: 0644]
queue-4.14/netlabel-fix-problems-with-mapping-removal.patch [new file with mode: 0644]
queue-4.14/sctp-not-disable-bh-in-the-whole-sctp_get_port_local.patch [new file with mode: 0644]
queue-4.14/series
queue-4.14/tipc-fix-shutdown-of-connectionless-socket.patch [new file with mode: 0644]

diff --git a/queue-4.14/bnxt-don-t-enable-napi-until-rings-are-ready.patch b/queue-4.14/bnxt-don-t-enable-napi-until-rings-are-ready.patch
new file mode 100644 (file)
index 0000000..64bd81b
--- /dev/null
@@ -0,0 +1,79 @@
+From 96ecdcc992eb7f468b2cf829b0f5408a1fad4668 Mon Sep 17 00:00:00 2001
+From: Jakub Kicinski <kuba@kernel.org>
+Date: Wed, 26 Aug 2020 12:40:07 -0700
+Subject: bnxt: don't enable NAPI until rings are ready
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+commit 96ecdcc992eb7f468b2cf829b0f5408a1fad4668 upstream.
+
+Netpoll can try to poll napi as soon as napi_enable() is called.
+It crashes trying to access a doorbell which is still NULL:
+
+ BUG: kernel NULL pointer dereference, address: 0000000000000000
+ CPU: 59 PID: 6039 Comm: ethtool Kdump: loaded Tainted: G S                5.9.0-rc1-00469-g5fd99b5d9950-dirty #26
+ RIP: 0010:bnxt_poll+0x121/0x1c0
+ Code: c4 20 44 89 e0 5b 5d 41 5c 41 5d 41 5e 41 5f c3 41 8b 86 a0 01 00 00 41 23 85 18 01 00 00 49 8b 96 a8 01 00 00 0d 00 00 00 24 <89> 02
+41 f6 45 77 02 74 cb 49 8b ae d8 01 00 00 31 c0 c7 44 24 1a
+  netpoll_poll_dev+0xbd/0x1a0
+  __netpoll_send_skb+0x1b2/0x210
+  netpoll_send_udp+0x2c9/0x406
+  write_ext_msg+0x1d7/0x1f0
+  console_unlock+0x23c/0x520
+  vprintk_emit+0xe0/0x1d0
+  printk+0x58/0x6f
+  x86_vector_activate.cold+0xf/0x46
+  __irq_domain_activate_irq+0x50/0x80
+  __irq_domain_activate_irq+0x32/0x80
+  __irq_domain_activate_irq+0x32/0x80
+  irq_domain_activate_irq+0x25/0x40
+  __setup_irq+0x2d2/0x700
+  request_threaded_irq+0xfb/0x160
+  __bnxt_open_nic+0x3b1/0x750
+  bnxt_open_nic+0x19/0x30
+  ethtool_set_channels+0x1ac/0x220
+  dev_ethtool+0x11ba/0x2240
+  dev_ioctl+0x1cf/0x390
+  sock_do_ioctl+0x95/0x130
+
+Reported-by: Rob Sherwood <rsher@fb.com>
+Fixes: c0c050c58d84 ("bnxt_en: New Broadcom ethernet driver.")
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c |    9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -6378,14 +6378,14 @@ static int __bnxt_open_nic(struct bnxt *
+               }
+       }
+-      bnxt_enable_napi(bp);
+-
+       rc = bnxt_init_nic(bp, irq_re_init);
+       if (rc) {
+               netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc);
+-              goto open_err;
++              goto open_err_irq;
+       }
++      bnxt_enable_napi(bp);
++
+       if (link_re_init) {
+               mutex_lock(&bp->link_lock);
+               rc = bnxt_update_phy_setting(bp);
+@@ -6410,9 +6410,6 @@ static int __bnxt_open_nic(struct bnxt *
+               bnxt_vf_reps_open(bp);
+       return 0;
+-open_err:
+-      bnxt_disable_napi(bp);
+-
+ open_err_irq:
+       bnxt_del_napi(bp);
diff --git a/queue-4.14/net-disable-netpoll-on-fresh-napis.patch b/queue-4.14/net-disable-netpoll-on-fresh-napis.patch
new file mode 100644 (file)
index 0000000..be9a9b1
--- /dev/null
@@ -0,0 +1,58 @@
+From foo@baz Fri Sep 11 09:55:41 AM CEST 2020
+From: Jakub Kicinski <kuba@kernel.org>
+Date: Wed, 26 Aug 2020 12:40:06 -0700
+Subject: net: disable netpoll on fresh napis
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit 96e97bc07e90f175a8980a22827faf702ca4cb30 ]
+
+napi_disable() makes sure to set the NAPI_STATE_NPSVC bit to prevent
+netpoll from accessing rings before init is complete. However, the
+same is not done for fresh napi instances in netif_napi_add(),
+even though we expect NAPI instances to be added as disabled.
+
+This causes crashes during driver reconfiguration (enabling XDP,
+changing the channel count) - if there is any printk() after
+netif_napi_add() but before napi_enable().
+
+To ensure memory ordering is correct we need to use RCU accessors.
+
+Reported-by: Rob Sherwood <rsher@fb.com>
+Fixes: 2d8bff12699a ("netpoll: Close race condition between poll_one_napi and napi_disable")
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/core/dev.c     |    3 ++-
+ net/core/netpoll.c |    2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -5532,12 +5532,13 @@ void netif_napi_add(struct net_device *d
+               pr_err_once("netif_napi_add() called with weight %d on device %s\n",
+                           weight, dev->name);
+       napi->weight = weight;
+-      list_add(&napi->dev_list, &dev->napi_list);
+       napi->dev = dev;
+ #ifdef CONFIG_NETPOLL
+       napi->poll_owner = -1;
+ #endif
+       set_bit(NAPI_STATE_SCHED, &napi->state);
++      set_bit(NAPI_STATE_NPSVC, &napi->state);
++      list_add_rcu(&napi->dev_list, &dev->napi_list);
+       napi_hash_add(napi);
+ }
+ EXPORT_SYMBOL(netif_napi_add);
+--- a/net/core/netpoll.c
++++ b/net/core/netpoll.c
+@@ -179,7 +179,7 @@ static void poll_napi(struct net_device
+       struct napi_struct *napi;
+       int cpu = smp_processor_id();
+-      list_for_each_entry(napi, &dev->napi_list, dev_list) {
++      list_for_each_entry_rcu(napi, &dev->napi_list, dev_list) {
+               if (cmpxchg(&napi->poll_owner, -1, cpu) == -1) {
+                       poll_one_napi(napi);
+                       smp_store_release(&napi->poll_owner, -1);
diff --git a/queue-4.14/net-usb-dm9601-add-usb-id-of-keenetic-plus-dsl.patch b/queue-4.14/net-usb-dm9601-add-usb-id-of-keenetic-plus-dsl.patch
new file mode 100644 (file)
index 0000000..a29b84b
--- /dev/null
@@ -0,0 +1,31 @@
+From foo@baz Fri Sep 11 09:55:41 AM CEST 2020
+From: Kamil Lorenc <kamil@re-ws.pl>
+Date: Tue, 1 Sep 2020 10:57:38 +0200
+Subject: net: usb: dm9601: Add USB ID of Keenetic Plus DSL
+
+From: Kamil Lorenc <kamil@re-ws.pl>
+
+[ Upstream commit a609d0259183a841621f252e067f40f8cc25d6f6 ]
+
+Keenetic Plus DSL is a xDSL modem that uses dm9620 as its USB interface.
+
+Signed-off-by: Kamil Lorenc <kamil@re-ws.pl>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/usb/dm9601.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/usb/dm9601.c
++++ b/drivers/net/usb/dm9601.c
+@@ -625,6 +625,10 @@ static const struct usb_device_id produc
+        USB_DEVICE(0x0a46, 0x1269),    /* DM9621A USB to Fast Ethernet Adapter */
+        .driver_info = (unsigned long)&dm9601_info,
+       },
++      {
++       USB_DEVICE(0x0586, 0x3427),    /* ZyXEL Keenetic Plus DSL xDSL modem */
++       .driver_info = (unsigned long)&dm9601_info,
++      },
+       {},                     // END
+ };
diff --git a/queue-4.14/netlabel-fix-problems-with-mapping-removal.patch b/queue-4.14/netlabel-fix-problems-with-mapping-removal.patch
new file mode 100644 (file)
index 0000000..681eb6b
--- /dev/null
@@ -0,0 +1,140 @@
+From foo@baz Fri Sep 11 09:55:41 AM CEST 2020
+From: Paul Moore <paul@paul-moore.com>
+Date: Fri, 21 Aug 2020 16:34:52 -0400
+Subject: netlabel: fix problems with mapping removal
+
+From: Paul Moore <paul@paul-moore.com>
+
+[ Upstream commit d3b990b7f327e2afa98006e7666fb8ada8ed8683 ]
+
+This patch fixes two main problems seen when removing NetLabel
+mappings: memory leaks and potentially extra audit noise.
+
+The memory leaks are caused by not properly free'ing the mapping's
+address selector struct when free'ing the entire entry as well as
+not properly cleaning up a temporary mapping entry when adding new
+address selectors to an existing entry.  This patch fixes both these
+problems such that kmemleak reports no NetLabel associated leaks
+after running the SELinux test suite.
+
+The potentially extra audit noise was caused by the auditing code in
+netlbl_domhsh_remove_entry() being called regardless of the entry's
+validity.  If another thread had already marked the entry as invalid,
+but not removed/free'd it from the list of mappings, then it was
+possible that an additional mapping removal audit record would be
+generated.  This patch fixes this by returning early from the removal
+function when the entry was previously marked invalid.  This change
+also had the side benefit of improving the code by decreasing the
+indentation level of large chunk of code by one (accounting for most
+of the diffstat).
+
+Fixes: 63c416887437 ("netlabel: Add network address selectors to the NetLabel/LSM domain mapping")
+Reported-by: Stephen Smalley <stephen.smalley.work@gmail.com>
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netlabel/netlabel_domainhash.c |   59 ++++++++++++++++++-------------------
+ 1 file changed, 30 insertions(+), 29 deletions(-)
+
+--- a/net/netlabel/netlabel_domainhash.c
++++ b/net/netlabel/netlabel_domainhash.c
+@@ -99,6 +99,7 @@ static void netlbl_domhsh_free_entry(str
+                       kfree(netlbl_domhsh_addr6_entry(iter6));
+               }
+ #endif /* IPv6 */
++              kfree(ptr->def.addrsel);
+       }
+       kfree(ptr->domain);
+       kfree(ptr);
+@@ -550,6 +551,8 @@ int netlbl_domhsh_add(struct netlbl_dom_
+                               goto add_return;
+               }
+ #endif /* IPv6 */
++              /* cleanup the new entry since we've moved everything over */
++              netlbl_domhsh_free_entry(&entry->rcu);
+       } else
+               ret_val = -EINVAL;
+@@ -593,6 +596,12 @@ int netlbl_domhsh_remove_entry(struct ne
+ {
+       int ret_val = 0;
+       struct audit_buffer *audit_buf;
++      struct netlbl_af4list *iter4;
++      struct netlbl_domaddr4_map *map4;
++#if IS_ENABLED(CONFIG_IPV6)
++      struct netlbl_af6list *iter6;
++      struct netlbl_domaddr6_map *map6;
++#endif /* IPv6 */
+       if (entry == NULL)
+               return -ENOENT;
+@@ -610,6 +619,9 @@ int netlbl_domhsh_remove_entry(struct ne
+               ret_val = -ENOENT;
+       spin_unlock(&netlbl_domhsh_lock);
++      if (ret_val)
++              return ret_val;
++
+       audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
+       if (audit_buf != NULL) {
+               audit_log_format(audit_buf,
+@@ -619,40 +631,29 @@ int netlbl_domhsh_remove_entry(struct ne
+               audit_log_end(audit_buf);
+       }
+-      if (ret_val == 0) {
+-              struct netlbl_af4list *iter4;
+-              struct netlbl_domaddr4_map *map4;
+-#if IS_ENABLED(CONFIG_IPV6)
+-              struct netlbl_af6list *iter6;
+-              struct netlbl_domaddr6_map *map6;
+-#endif /* IPv6 */
+-
+-              switch (entry->def.type) {
+-              case NETLBL_NLTYPE_ADDRSELECT:
+-                      netlbl_af4list_foreach_rcu(iter4,
+-                                           &entry->def.addrsel->list4) {
+-                              map4 = netlbl_domhsh_addr4_entry(iter4);
+-                              cipso_v4_doi_putdef(map4->def.cipso);
+-                      }
++      switch (entry->def.type) {
++      case NETLBL_NLTYPE_ADDRSELECT:
++              netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
++                      map4 = netlbl_domhsh_addr4_entry(iter4);
++                      cipso_v4_doi_putdef(map4->def.cipso);
++              }
+ #if IS_ENABLED(CONFIG_IPV6)
+-                      netlbl_af6list_foreach_rcu(iter6,
+-                                           &entry->def.addrsel->list6) {
+-                              map6 = netlbl_domhsh_addr6_entry(iter6);
+-                              calipso_doi_putdef(map6->def.calipso);
+-                      }
++              netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
++                      map6 = netlbl_domhsh_addr6_entry(iter6);
++                      calipso_doi_putdef(map6->def.calipso);
++              }
+ #endif /* IPv6 */
+-                      break;
+-              case NETLBL_NLTYPE_CIPSOV4:
+-                      cipso_v4_doi_putdef(entry->def.cipso);
+-                      break;
++              break;
++      case NETLBL_NLTYPE_CIPSOV4:
++              cipso_v4_doi_putdef(entry->def.cipso);
++              break;
+ #if IS_ENABLED(CONFIG_IPV6)
+-              case NETLBL_NLTYPE_CALIPSO:
+-                      calipso_doi_putdef(entry->def.calipso);
+-                      break;
++      case NETLBL_NLTYPE_CALIPSO:
++              calipso_doi_putdef(entry->def.calipso);
++              break;
+ #endif /* IPv6 */
+-              }
+-              call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+       }
++      call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+       return ret_val;
+ }
diff --git a/queue-4.14/sctp-not-disable-bh-in-the-whole-sctp_get_port_local.patch b/queue-4.14/sctp-not-disable-bh-in-the-whole-sctp_get_port_local.patch
new file mode 100644 (file)
index 0000000..5f7bea3
--- /dev/null
@@ -0,0 +1,105 @@
+From foo@baz Fri Sep 11 09:55:41 AM CEST 2020
+From: Xin Long <lucien.xin@gmail.com>
+Date: Fri, 21 Aug 2020 14:59:38 +0800
+Subject: sctp: not disable bh in the whole sctp_get_port_local()
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit 3106ecb43a05dc3e009779764b9da245a5d082de ]
+
+With disabling bh in the whole sctp_get_port_local(), when
+snum == 0 and too many ports have been used, the do-while
+loop will take the cpu for a long time and cause cpu stuck:
+
+  [ ] watchdog: BUG: soft lockup - CPU#11 stuck for 22s!
+  [ ] RIP: 0010:native_queued_spin_lock_slowpath+0x4de/0x940
+  [ ] Call Trace:
+  [ ]  _raw_spin_lock+0xc1/0xd0
+  [ ]  sctp_get_port_local+0x527/0x650 [sctp]
+  [ ]  sctp_do_bind+0x208/0x5e0 [sctp]
+  [ ]  sctp_autobind+0x165/0x1e0 [sctp]
+  [ ]  sctp_connect_new_asoc+0x355/0x480 [sctp]
+  [ ]  __sctp_connect+0x360/0xb10 [sctp]
+
+There's no need to disable bh in the whole function of
+sctp_get_port_local. So fix this cpu stuck by removing
+local_bh_disable() called at the beginning, and using
+spin_lock_bh() instead.
+
+The same thing was actually done for inet_csk_get_port() in
+Commit ea8add2b1903 ("tcp/dccp: better use of ephemeral
+ports in bind()").
+
+Thanks to Marcelo for pointing the buggy code out.
+
+v1->v2:
+  - use cond_resched() to yield cpu to other tasks if needed,
+    as Eric noticed.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Ying Xu <yinxu@redhat.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sctp/socket.c |   16 ++++++----------
+ 1 file changed, 6 insertions(+), 10 deletions(-)
+
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -7086,8 +7086,6 @@ static long sctp_get_port_local(struct s
+       pr_debug("%s: begins, snum:%d\n", __func__, snum);
+-      local_bh_disable();
+-
+       if (snum == 0) {
+               /* Search for an available port. */
+               int low, high, remaining, index;
+@@ -7106,20 +7104,21 @@ static long sctp_get_port_local(struct s
+                               continue;
+                       index = sctp_phashfn(sock_net(sk), rover);
+                       head = &sctp_port_hashtable[index];
+-                      spin_lock(&head->lock);
++                      spin_lock_bh(&head->lock);
+                       sctp_for_each_hentry(pp, &head->chain)
+                               if ((pp->port == rover) &&
+                                   net_eq(sock_net(sk), pp->net))
+                                       goto next;
+                       break;
+               next:
+-                      spin_unlock(&head->lock);
++                      spin_unlock_bh(&head->lock);
++                      cond_resched();
+               } while (--remaining > 0);
+               /* Exhausted local port range during search? */
+               ret = 1;
+               if (remaining <= 0)
+-                      goto fail;
++                      return ret;
+               /* OK, here is the one we will use.  HEAD (the port
+                * hash table list entry) is non-NULL and we hold it's
+@@ -7134,7 +7133,7 @@ static long sctp_get_port_local(struct s
+                * port iterator, pp being NULL.
+                */
+               head = &sctp_port_hashtable[sctp_phashfn(sock_net(sk), snum)];
+-              spin_lock(&head->lock);
++              spin_lock_bh(&head->lock);
+               sctp_for_each_hentry(pp, &head->chain) {
+                       if ((pp->port == snum) && net_eq(pp->net, sock_net(sk)))
+                               goto pp_found;
+@@ -7218,10 +7217,7 @@ success:
+       ret = 0;
+ fail_unlock:
+-      spin_unlock(&head->lock);
+-
+-fail:
+-      local_bh_enable();
++      spin_unlock_bh(&head->lock);
+       return ret;
+ }
index 0534695e904e63b11313adc9953aa1bd4d8a88fb..c7000b379056410ffcc930508a837ba205ff750e 100644 (file)
@@ -4,3 +4,9 @@ vfio-type1-support-faulting-pfnmap-vmas.patch
 vfio-pci-fault-mmaps-to-enable-vma-tracking.patch
 vfio-pci-invalidate-mmaps-and-block-mmio-access-on-disabled-memory.patch
 vfio-pci-fix-sr-iov-vf-handling-with-mmio-blocking.patch
+bnxt-don-t-enable-napi-until-rings-are-ready.patch
+netlabel-fix-problems-with-mapping-removal.patch
+net-usb-dm9601-add-usb-id-of-keenetic-plus-dsl.patch
+sctp-not-disable-bh-in-the-whole-sctp_get_port_local.patch
+tipc-fix-shutdown-of-connectionless-socket.patch
+net-disable-netpoll-on-fresh-napis.patch
diff --git a/queue-4.14/tipc-fix-shutdown-of-connectionless-socket.patch b/queue-4.14/tipc-fix-shutdown-of-connectionless-socket.patch
new file mode 100644 (file)
index 0000000..da3b357
--- /dev/null
@@ -0,0 +1,85 @@
+From foo@baz Fri Sep 11 09:55:41 AM CEST 2020
+From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
+Date: Wed, 2 Sep 2020 22:44:16 +0900
+Subject: tipc: fix shutdown() of connectionless socket
+
+From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
+
+[ Upstream commit 2a63866c8b51a3f72cea388dfac259d0e14c4ba6 ]
+
+syzbot is reporting hung task at nbd_ioctl() [1], for there are two
+problems regarding TIPC's connectionless socket's shutdown() operation.
+
+----------
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/nbd.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+        const int fd = open("/dev/nbd0", 3);
+        alarm(5);
+        ioctl(fd, NBD_SET_SOCK, socket(PF_TIPC, SOCK_DGRAM, 0));
+        ioctl(fd, NBD_DO_IT, 0); /* To be interrupted by SIGALRM. */
+        return 0;
+}
+----------
+
+One problem is that wait_for_completion() from flush_workqueue() from
+nbd_start_device_ioctl() from nbd_ioctl() cannot be completed when
+nbd_start_device_ioctl() received a signal at wait_event_interruptible(),
+for tipc_shutdown() from kernel_sock_shutdown(SHUT_RDWR) from
+nbd_mark_nsock_dead() from sock_shutdown() from nbd_start_device_ioctl()
+is failing to wake up a WQ thread sleeping at wait_woken() from
+tipc_wait_for_rcvmsg() from sock_recvmsg() from sock_xmit() from
+nbd_read_stat() from recv_work() scheduled by nbd_start_device() from
+nbd_start_device_ioctl(). Fix this problem by always invoking
+sk->sk_state_change() (like inet_shutdown() does) when tipc_shutdown() is
+called.
+
+The other problem is that tipc_wait_for_rcvmsg() cannot return when
+tipc_shutdown() is called, for tipc_shutdown() sets sk->sk_shutdown to
+SEND_SHUTDOWN (despite "how" is SHUT_RDWR) while tipc_wait_for_rcvmsg()
+needs sk->sk_shutdown set to RCV_SHUTDOWN or SHUTDOWN_MASK. Fix this
+problem by setting sk->sk_shutdown to SHUTDOWN_MASK (like inet_shutdown()
+does) when the socket is connectionless.
+
+[1] https://syzkaller.appspot.com/bug?id=3fe51d307c1f0a845485cf1798aa059d12bf18b2
+
+Reported-by: syzbot <syzbot+e36f41d207137b5d12f7@syzkaller.appspotmail.com>
+Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/tipc/socket.c |    9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/net/tipc/socket.c
++++ b/net/tipc/socket.c
+@@ -2126,18 +2126,21 @@ static int tipc_shutdown(struct socket *
+       lock_sock(sk);
+       __tipc_shutdown(sock, TIPC_CONN_SHUTDOWN);
+-      sk->sk_shutdown = SEND_SHUTDOWN;
++      if (tipc_sk_type_connectionless(sk))
++              sk->sk_shutdown = SHUTDOWN_MASK;
++      else
++              sk->sk_shutdown = SEND_SHUTDOWN;
+       if (sk->sk_state == TIPC_DISCONNECTING) {
+               /* Discard any unreceived messages */
+               __skb_queue_purge(&sk->sk_receive_queue);
+-              /* Wake up anyone sleeping in poll */
+-              sk->sk_state_change(sk);
+               res = 0;
+       } else {
+               res = -ENOTCONN;
+       }
++      /* Wake up anyone sleeping in poll. */
++      sk->sk_state_change(sk);
+       release_sock(sk);
+       return res;