From: Greg Kroah-Hartman Date: Mon, 22 May 2017 16:07:04 +0000 (+0200) Subject: 3.18-stable patches X-Git-Tag: v3.18.55~59 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=deae187aa7ba1edfcb3d76f91166f24680491873;p=thirdparty%2Fkernel%2Fstable-queue.git 3.18-stable patches added patches: dm-btree-fix-for-dm_btree_find_lowest_key.patch dm-bufio-avoid-a-possible-abba-deadlock.patch dm-space-map-disk-fix-some-book-keeping-in-the-disk-space-map.patch dm-thin-metadata-call-precommit-before-saving-the-roots.patch mwifiex-pcie-fix-cmd_buf-use-after-free-in-remove-reset.patch --- diff --git a/queue-3.18/dm-btree-fix-for-dm_btree_find_lowest_key.patch b/queue-3.18/dm-btree-fix-for-dm_btree_find_lowest_key.patch new file mode 100644 index 00000000000..ee37eb2eb95 --- /dev/null +++ b/queue-3.18/dm-btree-fix-for-dm_btree_find_lowest_key.patch @@ -0,0 +1,46 @@ +From 7d1fedb6e96a960aa91e4ff70714c3fb09195a5a Mon Sep 17 00:00:00 2001 +From: Vinothkumar Raja +Date: Thu, 6 Apr 2017 22:09:38 -0400 +Subject: dm btree: fix for dm_btree_find_lowest_key() + +From: Vinothkumar Raja + +commit 7d1fedb6e96a960aa91e4ff70714c3fb09195a5a upstream. + +dm_btree_find_lowest_key() is giving incorrect results. find_key() +traverses the btree correctly for finding the highest key, but there is +an error in the way it traverses the btree for retrieving the lowest +key. dm_btree_find_lowest_key() fetches the first key of the rightmost +block of the btree instead of fetching the first key from the leftmost +block. + +Fix this by conditionally passing the correct parameter to value64() +based on the @find_highest flag. + +Signed-off-by: Erez Zadok +Signed-off-by: Vinothkumar Raja +Signed-off-by: Nidhi Panpalia +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/persistent-data/dm-btree.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/md/persistent-data/dm-btree.c ++++ b/drivers/md/persistent-data/dm-btree.c +@@ -788,8 +788,12 @@ static int find_key(struct ro_spine *s, + else + *result_key = le64_to_cpu(ro_node(s)->keys[0]); + +- if (next_block || flags & INTERNAL_NODE) +- block = value64(ro_node(s), i); ++ if (next_block || flags & INTERNAL_NODE) { ++ if (find_highest) ++ block = value64(ro_node(s), i); ++ else ++ block = value64(ro_node(s), 0); ++ } + + } while (flags & INTERNAL_NODE); + diff --git a/queue-3.18/dm-bufio-avoid-a-possible-abba-deadlock.patch b/queue-3.18/dm-bufio-avoid-a-possible-abba-deadlock.patch new file mode 100644 index 00000000000..db52f967b99 --- /dev/null +++ b/queue-3.18/dm-bufio-avoid-a-possible-abba-deadlock.patch @@ -0,0 +1,50 @@ +From 1b0fb5a5b2dc0dddcfa575060441a7176ba7ac37 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Sun, 30 Apr 2017 17:33:26 -0400 +Subject: dm bufio: avoid a possible ABBA deadlock + +From: Mikulas Patocka + +commit 1b0fb5a5b2dc0dddcfa575060441a7176ba7ac37 upstream. + +__get_memory_limit() tests if dm_bufio_cache_size changed and calls +__cache_size_refresh() if it did. It takes dm_bufio_clients_lock while +it already holds the client lock. However, lock ordering is violated +because in cleanup_old_buffers() dm_bufio_clients_lock is taken before +the client lock. + +This results in a possible deadlock and lockdep engine warning. + +Fix this deadlock by changing mutex_lock() to mutex_trylock(). If the +lock can't be taken, it will be re-checked next time when a new buffer +is allocated. + +Also add "unlikely" to the if condition, so that the optimizer assumes +that the condition is false. + +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-bufio.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -862,10 +862,11 @@ static void __get_memory_limit(struct dm + { + unsigned long buffers; + +- if (ACCESS_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch) { +- mutex_lock(&dm_bufio_clients_lock); +- __cache_size_refresh(); +- mutex_unlock(&dm_bufio_clients_lock); ++ if (unlikely(ACCESS_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch)) { ++ if (mutex_trylock(&dm_bufio_clients_lock)) { ++ __cache_size_refresh(); ++ mutex_unlock(&dm_bufio_clients_lock); ++ } + } + + buffers = dm_bufio_cache_size_per_client >> diff --git a/queue-3.18/dm-space-map-disk-fix-some-book-keeping-in-the-disk-space-map.patch b/queue-3.18/dm-space-map-disk-fix-some-book-keeping-in-the-disk-space-map.patch new file mode 100644 index 00000000000..a01da1983f9 --- /dev/null +++ b/queue-3.18/dm-space-map-disk-fix-some-book-keeping-in-the-disk-space-map.patch @@ -0,0 +1,47 @@ +From 0377a07c7a035e0d033cd8b29f0cb15244c0916a Mon Sep 17 00:00:00 2001 +From: Joe Thornber +Date: Mon, 15 May 2017 09:45:40 -0400 +Subject: dm space map disk: fix some book keeping in the disk space map + +From: Joe Thornber + +commit 0377a07c7a035e0d033cd8b29f0cb15244c0916a upstream. + +When decrementing the reference count for a block, the free count wasn't +being updated if the reference count went to zero. + +Signed-off-by: Joe Thornber +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/persistent-data/dm-space-map-disk.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/drivers/md/persistent-data/dm-space-map-disk.c ++++ b/drivers/md/persistent-data/dm-space-map-disk.c +@@ -140,10 +140,23 @@ static int sm_disk_inc_block(struct dm_s + + static int sm_disk_dec_block(struct dm_space_map *sm, dm_block_t b) + { ++ int r; ++ uint32_t old_count; + enum allocation_event ev; + struct sm_disk *smd = container_of(sm, struct sm_disk, sm); + +- return sm_ll_dec(&smd->ll, b, &ev); ++ r = sm_ll_dec(&smd->ll, b, &ev); ++ if (!r && (ev == SM_FREE)) { ++ /* ++ * It's only free if it's also free in the last ++ * transaction. ++ */ ++ r = sm_ll_lookup(&smd->old_ll, b, &old_count); ++ if (!r && !old_count) ++ smd->nr_allocated_this_transaction--; ++ } ++ ++ return r; + } + + static int sm_disk_new_block(struct dm_space_map *sm, dm_block_t *b) diff --git a/queue-3.18/dm-thin-metadata-call-precommit-before-saving-the-roots.patch b/queue-3.18/dm-thin-metadata-call-precommit-before-saving-the-roots.patch new file mode 100644 index 00000000000..32f1c0bda02 --- /dev/null +++ b/queue-3.18/dm-thin-metadata-call-precommit-before-saving-the-roots.patch @@ -0,0 +1,35 @@ +From 91bcdb92d39711d1adb40c26b653b7978d93eb98 Mon Sep 17 00:00:00 2001 +From: Joe Thornber +Date: Mon, 15 May 2017 09:43:05 -0400 +Subject: dm thin metadata: call precommit before saving the roots + +From: Joe Thornber + +commit 91bcdb92d39711d1adb40c26b653b7978d93eb98 upstream. + +These calls were the wrong way round in __write_initial_superblock. + +Signed-off-by: Joe Thornber +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-thin-metadata.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/md/dm-thin-metadata.c ++++ b/drivers/md/dm-thin-metadata.c +@@ -484,11 +484,11 @@ static int __write_initial_superblock(st + if (r < 0) + return r; + +- r = save_sm_roots(pmd); ++ r = dm_tm_pre_commit(pmd->tm); + if (r < 0) + return r; + +- r = dm_tm_pre_commit(pmd->tm); ++ r = save_sm_roots(pmd); + if (r < 0) + return r; + diff --git a/queue-3.18/mwifiex-pcie-fix-cmd_buf-use-after-free-in-remove-reset.patch b/queue-3.18/mwifiex-pcie-fix-cmd_buf-use-after-free-in-remove-reset.patch new file mode 100644 index 00000000000..8f4312d91fb --- /dev/null +++ b/queue-3.18/mwifiex-pcie-fix-cmd_buf-use-after-free-in-remove-reset.patch @@ -0,0 +1,144 @@ +From 3c8cb9ad032d737b874e402c59eb51e3c991a144 Mon Sep 17 00:00:00 2001 +From: Brian Norris +Date: Fri, 14 Apr 2017 14:51:17 -0700 +Subject: mwifiex: pcie: fix cmd_buf use-after-free in remove/reset + +From: Brian Norris + +commit 3c8cb9ad032d737b874e402c59eb51e3c991a144 upstream. + +Command buffers (skb's) are allocated by the main driver, and freed upon +the last use. That last use is often in mwifiex_free_cmd_buffer(). In +the meantime, if the command buffer gets used by the PCI driver, we map +it as DMA-able, and store the mapping information in the 'cb' memory. + +However, if a command was in-flight when resetting the device (and +therefore was still mapped), we don't get a chance to unmap this memory +until after the core has cleaned up its command handling. + +Let's keep a refcount within the PCI driver, so we ensure the memory +only gets freed after we've finished unmapping it. + +Noticed by KASAN when forcing a reset via: + + echo 1 > /sys/bus/pci/.../reset + +The same code path can presumably be exercised in remove() and +shutdown(). + +[ 205.390377] mwifiex_pcie 0000:01:00.0: info: shutdown mwifiex... +[ 205.400393] ================================================================== +[ 205.407719] BUG: KASAN: use-after-free in mwifiex_unmap_pci_memory.isra.14+0x4c/0x100 [mwifiex_pcie] at addr ffffffc0ad471b28 +[ 205.419040] Read of size 16 by task bash/1913 +[ 205.423421] ============================================================================= +[ 205.431625] BUG skbuff_head_cache (Tainted: G B ): kasan: bad access detected +[ 205.439815] ----------------------------------------------------------------------------- +[ 205.439815] +[ 205.449534] INFO: Allocated in __build_skb+0x48/0x114 age=1311 cpu=4 pid=1913 +[ 205.456709] alloc_debug_processing+0x124/0x178 +[ 205.461282] ___slab_alloc.constprop.58+0x528/0x608 +[ 205.466196] __slab_alloc.isra.54.constprop.57+0x44/0x54 +[ 205.471542] kmem_cache_alloc+0xcc/0x278 +[ 205.475497] __build_skb+0x48/0x114 +[ 205.479019] __netdev_alloc_skb+0xe0/0x170 +[ 205.483244] mwifiex_alloc_cmd_buffer+0x68/0xdc [mwifiex] +[ 205.488759] mwifiex_init_fw+0x40/0x6cc [mwifiex] +[ 205.493584] _mwifiex_fw_dpc+0x158/0x520 [mwifiex] +[ 205.498491] mwifiex_reinit_sw+0x2c4/0x398 [mwifiex] +[ 205.503510] mwifiex_pcie_reset_notify+0x114/0x15c [mwifiex_pcie] +[ 205.509643] pci_reset_notify+0x5c/0x6c +[ 205.513519] pci_reset_function+0x6c/0x7c +[ 205.517567] reset_store+0x68/0x98 +[ 205.521003] dev_attr_store+0x54/0x60 +[ 205.524705] sysfs_kf_write+0x9c/0xb0 +[ 205.528413] INFO: Freed in __kfree_skb+0xb0/0xbc age=131 cpu=4 pid=1913 +[ 205.535064] free_debug_processing+0x264/0x370 +[ 205.539550] __slab_free+0x84/0x40c +[ 205.543075] kmem_cache_free+0x1c8/0x2a0 +[ 205.547030] __kfree_skb+0xb0/0xbc +[ 205.550465] consume_skb+0x164/0x178 +[ 205.554079] __dev_kfree_skb_any+0x58/0x64 +[ 205.558304] mwifiex_free_cmd_buffer+0xa0/0x158 [mwifiex] +[ 205.563817] mwifiex_shutdown_drv+0x578/0x5c4 [mwifiex] +[ 205.569164] mwifiex_shutdown_sw+0x178/0x310 [mwifiex] +[ 205.574353] mwifiex_pcie_reset_notify+0xd4/0x15c [mwifiex_pcie] +[ 205.580398] pci_reset_notify+0x5c/0x6c +[ 205.584274] pci_dev_save_and_disable+0x24/0x6c +[ 205.588837] pci_reset_function+0x30/0x7c +[ 205.592885] reset_store+0x68/0x98 +[ 205.596324] dev_attr_store+0x54/0x60 +[ 205.600017] sysfs_kf_write+0x9c/0xb0 +... +[ 205.800488] Call trace: +[ 205.802980] [] dump_backtrace+0x0/0x190 +[ 205.808415] [] show_stack+0x20/0x28 +[ 205.813506] [] dump_stack+0xa4/0xcc +[ 205.818598] [] print_trailer+0x158/0x168 +[ 205.824120] [] object_err+0x4c/0x5c +[ 205.829210] [] kasan_report+0x334/0x500 +[ 205.834641] [] check_memory_region+0x20/0x14c +[ 205.840593] [] __asan_loadN+0x14/0x1c +[ 205.845879] [] mwifiex_unmap_pci_memory.isra.14+0x4c/0x100 [mwifiex_pcie] +[ 205.854282] [] mwifiex_pcie_delete_cmdrsp_buf+0x94/0xa8 [mwifiex_pcie] +[ 205.862421] [] mwifiex_pcie_free_buffers+0x11c/0x158 [mwifiex_pcie] +[ 205.870302] [] mwifiex_pcie_down_dev+0x70/0x80 [mwifiex_pcie] +[ 205.877736] [] mwifiex_shutdown_sw+0x190/0x310 [mwifiex] +[ 205.884658] [] mwifiex_pcie_reset_notify+0xd4/0x15c [mwifiex_pcie] +[ 205.892446] [] pci_reset_notify+0x5c/0x6c +[ 205.898048] [] pci_dev_save_and_disable+0x24/0x6c +[ 205.904350] [] pci_reset_function+0x30/0x7c +[ 205.910134] [] reset_store+0x68/0x98 +[ 205.915312] [] dev_attr_store+0x54/0x60 +[ 205.920750] [] sysfs_kf_write+0x9c/0xb0 +[ 205.926182] [] kernfs_fop_write+0x184/0x1f8 +[ 205.931963] [] __vfs_write+0x6c/0x17c +[ 205.937221] [] vfs_write+0xf0/0x1c4 +[ 205.942310] [] SyS_write+0x78/0xd8 +[ 205.947312] [] el0_svc_naked+0x24/0x28 +... +[ 205.998268] ================================================================== + +This bug has been around in different forms for a while. It was sort of +noticed in commit 955ab095c51a ("mwifiex: Do not kfree cmd buf while +unregistering PCIe"), but it just fixed the double-free, without +acknowledging the potential for use-after-free. + +Fixes: fc3314609047 ("mwifiex: use pci_alloc/free_consistent APIs for PCIe") +Signed-off-by: Brian Norris +Signed-off-by: Kalle Valo +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mwifiex/pcie.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/net/wireless/mwifiex/pcie.c ++++ b/drivers/net/wireless/mwifiex/pcie.c +@@ -930,6 +930,7 @@ static int mwifiex_pcie_delete_cmdrsp_bu + if (card && card->cmd_buf) { + mwifiex_unmap_pci_memory(adapter, card->cmd_buf, + PCI_DMA_TODEVICE); ++ dev_kfree_skb_any(card->cmd_buf); + } + return 0; + } +@@ -1485,6 +1486,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_ada + return -1; + + card->cmd_buf = skb; ++ /* ++ * Need to keep a reference, since core driver might free up this ++ * buffer before we've unmapped it. ++ */ ++ skb_get(skb); + + /* To send a command, the driver will: + 1. Write the 64bit physical address of the data buffer to +@@ -1581,6 +1587,7 @@ static int mwifiex_pcie_process_cmd_comp + if (card->cmd_buf) { + mwifiex_unmap_pci_memory(adapter, card->cmd_buf, + PCI_DMA_TODEVICE); ++ dev_kfree_skb_any(card->cmd_buf); + card->cmd_buf = NULL; + } + diff --git a/queue-3.18/series b/queue-3.18/series index 2e1ebe42158..53018ae1173 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -2,3 +2,8 @@ usb-ene_usb6250-fix-dma-to-the-stack.patch watchdog-pcwd_usb-fix-null-deref-at-probe.patch char-lp-fix-possible-integer-overflow-in-lp_setup.patch usb-core-replace-p-with-pk.patch +dm-btree-fix-for-dm_btree_find_lowest_key.patch +dm-bufio-avoid-a-possible-abba-deadlock.patch +dm-thin-metadata-call-precommit-before-saving-the-roots.patch +dm-space-map-disk-fix-some-book-keeping-in-the-disk-space-map.patch +mwifiex-pcie-fix-cmd_buf-use-after-free-in-remove-reset.patch