]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 4 Oct 2021 10:51:05 +0000 (12:51 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 4 Oct 2021 10:51:05 +0000 (12:51 +0200)
added patches:
libnvdimm-pmem-fix-crash-triggered-when-i-o-in-flight-during-unbind.patch
pci-fix-pci_host_bridge-struct-device-release-free-handling.patch

queue-5.4/libnvdimm-pmem-fix-crash-triggered-when-i-o-in-flight-during-unbind.patch [new file with mode: 0644]
queue-5.4/pci-fix-pci_host_bridge-struct-device-release-free-handling.patch [new file with mode: 0644]
queue-5.4/series

diff --git a/queue-5.4/libnvdimm-pmem-fix-crash-triggered-when-i-o-in-flight-during-unbind.patch b/queue-5.4/libnvdimm-pmem-fix-crash-triggered-when-i-o-in-flight-during-unbind.patch
new file mode 100644 (file)
index 0000000..c0b1b4f
--- /dev/null
@@ -0,0 +1,82 @@
+From 32b2397c1e56f33b0b1881def965bb89bd12f448 Mon Sep 17 00:00:00 2001
+From: sumiyawang <sumiyawang@tencent.com>
+Date: Sun, 22 Aug 2021 19:49:09 +0800
+Subject: libnvdimm/pmem: Fix crash triggered when I/O in-flight during unbind
+
+From: sumiyawang <sumiyawang@tencent.com>
+
+commit 32b2397c1e56f33b0b1881def965bb89bd12f448 upstream.
+
+There is a use after free crash when the pmem driver tears down its
+mapping while I/O is still inbound.
+
+This is triggered by driver unbind, "ndctl destroy-namespace", while I/O
+is in flight.
+
+Fix the sequence of blk_cleanup_queue() vs memunmap().
+
+The crash signature is of the form:
+
+ BUG: unable to handle page fault for address: ffffc90080200000
+ CPU: 36 PID: 9606 Comm: systemd-udevd
+ Call Trace:
+  ? pmem_do_bvec+0xf9/0x3a0
+  ? xas_alloc+0x55/0xd0
+  pmem_rw_page+0x4b/0x80
+  bdev_read_page+0x86/0xb0
+  do_mpage_readpage+0x5d4/0x7a0
+  ? lru_cache_add+0xe/0x10
+  mpage_readpages+0xf9/0x1c0
+  ? bd_link_disk_holder+0x1a0/0x1a0
+  blkdev_readpages+0x1d/0x20
+  read_pages+0x67/0x1a0
+
+  ndctl Call Trace in vmcore:
+  PID: 23473  TASK: ffff88c4fbbe8000  CPU: 1   COMMAND: "ndctl"
+  __schedule
+  schedule
+  blk_mq_freeze_queue_wait
+  blk_freeze_queue
+  blk_cleanup_queue
+  pmem_release_queue
+  devm_action_release
+  release_nodes
+  devres_release_all
+  device_release_driver_internal
+  device_driver_detach
+  unbind_store
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: sumiyawang <sumiyawang@tencent.com>
+Reviewed-by: yongduan <yongduan@tencent.com>
+Link: https://lore.kernel.org/r/1629632949-14749-1-git-send-email-sumiyawang@tencent.com
+Fixes: 50f44ee7248a ("mm/devm_memremap_pages: fix final page put race")
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+[tyhicks: Minor contextual change in pmem_attach_disk() due to the
+ transition to 'struct range' not yet taking place. Preserve the
+ memcpy() call rather than initializing the range struct. That change
+ was introduced in v5.10 with commit a4574f63edc6 ("mm/memremap_pages:
+ convert to 'struct range'")]
+Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/nvdimm/pmem.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvdimm/pmem.c
++++ b/drivers/nvdimm/pmem.c
+@@ -423,11 +423,11 @@ static int pmem_attach_disk(struct devic
+               pmem->pfn_flags |= PFN_MAP;
+               memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res));
+       } else {
++              addr = devm_memremap(dev, pmem->phys_addr,
++                              pmem->size, ARCH_MEMREMAP_PMEM);
+               if (devm_add_action_or_reset(dev, pmem_release_queue,
+                                       &pmem->pgmap))
+                       return -ENOMEM;
+-              addr = devm_memremap(dev, pmem->phys_addr,
+-                              pmem->size, ARCH_MEMREMAP_PMEM);
+               memcpy(&bb_res, &nsio->res, sizeof(bb_res));
+       }
diff --git a/queue-5.4/pci-fix-pci_host_bridge-struct-device-release-free-handling.patch b/queue-5.4/pci-fix-pci_host_bridge-struct-device-release-free-handling.patch
new file mode 100644 (file)
index 0000000..2a29271
--- /dev/null
@@ -0,0 +1,161 @@
+From 9885440b16b8fc1dd7275800fd28f56a92f60896 Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Wed, 13 May 2020 17:38:59 -0500
+Subject: PCI: Fix pci_host_bridge struct device release/free handling
+
+From: Rob Herring <robh@kernel.org>
+
+commit 9885440b16b8fc1dd7275800fd28f56a92f60896 upstream.
+
+The PCI code has several paths where the struct pci_host_bridge is freed
+directly. This is wrong because it contains a struct device which is
+refcounted and should be freed using put_device(). This can result in
+use-after-free errors. I think this problem has existed since 2012 with
+commit 7b5436635800 ("PCI: add generic device into pci_host_bridge
+struct"). It generally hasn't mattered as most host bridge drivers are
+still built-in and can't unbind.
+
+The problem is a struct device should never be freed directly once
+device_initialize() is called and a ref is held, but that doesn't happen
+until pci_register_host_bridge(). There's then a window between allocating
+the host bridge and pci_register_host_bridge() where kfree should be used.
+This is fragile and requires callers to do the right thing. To fix this, we
+need to split device_register() into device_initialize() and device_add()
+calls, so that the host bridge struct is always freed by using a
+put_device().
+
+devm_pci_alloc_host_bridge() is using devm_kzalloc() to allocate struct
+pci_host_bridge which will be freed directly. Instead, we can use a custom
+devres action to call put_device().
+
+Link: https://lore.kernel.org/r/20200513223859.11295-2-robh@kernel.org
+Reported-by: Anders Roxell <anders.roxell@linaro.org>
+Tested-by: Anders Roxell <anders.roxell@linaro.org>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+[tyhicks: Minor contextual change in pci_init_host_bridge() due to the
+ lack of a native_dpc member in the pci_host_bridge struct. It was added
+ in v5.7 with commit ac1c8e35a326 ("PCI/DPC: Add Error Disconnect
+ Recover (EDR) support")]
+Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/probe.c  |   36 +++++++++++++++++++-----------------
+ drivers/pci/remove.c |    2 +-
+ 2 files changed, 20 insertions(+), 18 deletions(-)
+
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -564,7 +564,7 @@ static struct pci_bus *pci_alloc_bus(str
+       return b;
+ }
+-static void devm_pci_release_host_bridge_dev(struct device *dev)
++static void pci_release_host_bridge_dev(struct device *dev)
+ {
+       struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
+@@ -573,12 +573,7 @@ static void devm_pci_release_host_bridge
+       pci_free_resource_list(&bridge->windows);
+       pci_free_resource_list(&bridge->dma_ranges);
+-}
+-
+-static void pci_release_host_bridge_dev(struct device *dev)
+-{
+-      devm_pci_release_host_bridge_dev(dev);
+-      kfree(to_pci_host_bridge(dev));
++      kfree(bridge);
+ }
+ static void pci_init_host_bridge(struct pci_host_bridge *bridge)
+@@ -597,6 +592,8 @@ static void pci_init_host_bridge(struct
+       bridge->native_shpc_hotplug = 1;
+       bridge->native_pme = 1;
+       bridge->native_ltr = 1;
++
++      device_initialize(&bridge->dev);
+ }
+ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
+@@ -614,17 +611,25 @@ struct pci_host_bridge *pci_alloc_host_b
+ }
+ EXPORT_SYMBOL(pci_alloc_host_bridge);
++static void devm_pci_alloc_host_bridge_release(void *data)
++{
++      pci_free_host_bridge(data);
++}
++
+ struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev,
+                                                  size_t priv)
+ {
++      int ret;
+       struct pci_host_bridge *bridge;
+-      bridge = devm_kzalloc(dev, sizeof(*bridge) + priv, GFP_KERNEL);
++      bridge = pci_alloc_host_bridge(priv);
+       if (!bridge)
+               return NULL;
+-      pci_init_host_bridge(bridge);
+-      bridge->dev.release = devm_pci_release_host_bridge_dev;
++      ret = devm_add_action_or_reset(dev, devm_pci_alloc_host_bridge_release,
++                                     bridge);
++      if (ret)
++              return NULL;
+       return bridge;
+ }
+@@ -632,10 +637,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge
+ void pci_free_host_bridge(struct pci_host_bridge *bridge)
+ {
+-      pci_free_resource_list(&bridge->windows);
+-      pci_free_resource_list(&bridge->dma_ranges);
+-
+-      kfree(bridge);
++      put_device(&bridge->dev);
+ }
+ EXPORT_SYMBOL(pci_free_host_bridge);
+@@ -866,7 +868,7 @@ static int pci_register_host_bridge(stru
+       if (err)
+               goto free;
+-      err = device_register(&bridge->dev);
++      err = device_add(&bridge->dev);
+       if (err) {
+               put_device(&bridge->dev);
+               goto free;
+@@ -933,7 +935,7 @@ static int pci_register_host_bridge(stru
+ unregister:
+       put_device(&bridge->dev);
+-      device_unregister(&bridge->dev);
++      device_del(&bridge->dev);
+ free:
+       kfree(bus);
+@@ -2945,7 +2947,7 @@ struct pci_bus *pci_create_root_bus(stru
+       return bridge->bus;
+ err_out:
+-      kfree(bridge);
++      put_device(&bridge->dev);
+       return NULL;
+ }
+ EXPORT_SYMBOL_GPL(pci_create_root_bus);
+--- a/drivers/pci/remove.c
++++ b/drivers/pci/remove.c
+@@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus
+       host_bridge->bus = NULL;
+       /* remove the host bridge */
+-      device_unregister(&host_bridge->dev);
++      device_del(&host_bridge->dev);
+ }
+ EXPORT_SYMBOL_GPL(pci_remove_root_bus);
index 9bced4f86e5f04b5dd7a7de4c39b14bd23a22f4e..dc8b7cf703e9465993188614996edaa951ea3dee 100644 (file)
@@ -44,3 +44,5 @@ ext4-fix-potential-infinite-loop-in-ext4_dx_readdir.patch
 hid-u2fzero-ignore-incomplete-packets-without-data.patch
 net-udp-annotate-data-race-around-udp_sk-sk-corkflag.patch
 net-stmmac-don-t-attach-interface-until-resume-finishes.patch
+pci-fix-pci_host_bridge-struct-device-release-free-handling.patch
+libnvdimm-pmem-fix-crash-triggered-when-i-o-in-flight-during-unbind.patch