From 433e6f0688ca20dcb917a6b51a3e433fb8f6f858 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 14 May 2020 15:14:56 -0400 Subject: [PATCH] Fixes for 4.14 Signed-off-by: Sasha Levin --- ...k-around-gcc-10-stringop-overflow-wa.patch | 73 ++++++ ...moxa-fix-a-potential-double-free_irq.patch | 36 +++ ...resource-leak-in-an-error-handling-p.patch | 52 +++++ queue-4.14/series | 5 + ...sible-deadlocks-on-shmlock_user_lock.patch | 80 +++++++ ...e-block_device_operations-callbacks-.patch | 217 ++++++++++++++++++ 6 files changed, 463 insertions(+) create mode 100644 queue-4.14/drop_monitor-work-around-gcc-10-stringop-overflow-wa.patch create mode 100644 queue-4.14/net-moxa-fix-a-potential-double-free_irq.patch create mode 100644 queue-4.14/net-sonic-fix-a-resource-leak-in-an-error-handling-p.patch create mode 100644 queue-4.14/shmem-fix-possible-deadlocks-on-shmlock_user_lock.patch create mode 100644 queue-4.14/virtio-blk-handle-block_device_operations-callbacks-.patch diff --git a/queue-4.14/drop_monitor-work-around-gcc-10-stringop-overflow-wa.patch b/queue-4.14/drop_monitor-work-around-gcc-10-stringop-overflow-wa.patch new file mode 100644 index 00000000000..7028f60a1cd --- /dev/null +++ b/queue-4.14/drop_monitor-work-around-gcc-10-stringop-overflow-wa.patch @@ -0,0 +1,73 @@ +From 9c41913f7154699d0d6911334c5227947fa68ca4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2020 23:30:49 +0200 +Subject: drop_monitor: work around gcc-10 stringop-overflow warning + +From: Arnd Bergmann + +[ Upstream commit dc30b4059f6e2abf3712ab537c8718562b21c45d ] + +The current gcc-10 snapshot produces a false-positive warning: + +net/core/drop_monitor.c: In function 'trace_drop_common.constprop': +cc1: error: writing 8 bytes into a region of size 0 [-Werror=stringop-overflow=] +In file included from net/core/drop_monitor.c:23: +include/uapi/linux/net_dropmon.h:36:8: note: at offset 0 to object 'entries' with size 4 declared here + 36 | __u32 entries; + | ^~~~~~~ + +I reported this in the gcc bugzilla, but in case it does not get +fixed in the release, work around it by using a temporary variable. + +Fixes: 9a8afc8d3962 ("Network Drop Monitor: Adding drop monitor implementation & Netlink protocol") +Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94881 +Signed-off-by: Arnd Bergmann +Acked-by: Neil Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/core/drop_monitor.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c +index 70ccda233bd1f..ef9fe5f95093b 100644 +--- a/net/core/drop_monitor.c ++++ b/net/core/drop_monitor.c +@@ -154,6 +154,7 @@ static void sched_send_work(unsigned long _data) + static void trace_drop_common(struct sk_buff *skb, void *location) + { + struct net_dm_alert_msg *msg; ++ struct net_dm_drop_point *point; + struct nlmsghdr *nlh; + struct nlattr *nla; + int i; +@@ -172,11 +173,13 @@ static void trace_drop_common(struct sk_buff *skb, void *location) + nlh = (struct nlmsghdr *)dskb->data; + nla = genlmsg_data(nlmsg_data(nlh)); + msg = nla_data(nla); ++ point = msg->points; + for (i = 0; i < msg->entries; i++) { +- if (!memcmp(&location, msg->points[i].pc, sizeof(void *))) { +- msg->points[i].count++; ++ if (!memcmp(&location, &point->pc, sizeof(void *))) { ++ point->count++; + goto out; + } ++ point++; + } + if (msg->entries == dm_hit_limit) + goto out; +@@ -185,8 +188,8 @@ static void trace_drop_common(struct sk_buff *skb, void *location) + */ + __nla_reserve_nohdr(dskb, sizeof(struct net_dm_drop_point)); + nla->nla_len += NLA_ALIGN(sizeof(struct net_dm_drop_point)); +- memcpy(msg->points[msg->entries].pc, &location, sizeof(void *)); +- msg->points[msg->entries].count = 1; ++ memcpy(point->pc, &location, sizeof(void *)); ++ point->count = 1; + msg->entries++; + + if (!timer_pending(&data->send_timer)) { +-- +2.20.1 + diff --git a/queue-4.14/net-moxa-fix-a-potential-double-free_irq.patch b/queue-4.14/net-moxa-fix-a-potential-double-free_irq.patch new file mode 100644 index 00000000000..f4beab79c16 --- /dev/null +++ b/queue-4.14/net-moxa-fix-a-potential-double-free_irq.patch @@ -0,0 +1,36 @@ +From e210cc7ed12405663c73efdf6e04e55eecf12d4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2020 22:59:21 +0200 +Subject: net: moxa: Fix a potential double 'free_irq()' + +From: Christophe JAILLET + +[ Upstream commit ee8d2267f0e39a1bfd95532da3a6405004114b27 ] + +Should an irq requested with 'devm_request_irq' be released explicitly, +it should be done by 'devm_free_irq()', not 'free_irq()'. + +Fixes: 6c821bd9edc9 ("net: Add MOXA ART SoCs ethernet driver") +Signed-off-by: Christophe JAILLET +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/moxa/moxart_ether.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c +index 2e4effa9fe456..beb730ff5d421 100644 +--- a/drivers/net/ethernet/moxa/moxart_ether.c ++++ b/drivers/net/ethernet/moxa/moxart_ether.c +@@ -561,7 +561,7 @@ static int moxart_remove(struct platform_device *pdev) + struct net_device *ndev = platform_get_drvdata(pdev); + + unregister_netdev(ndev); +- free_irq(ndev->irq, ndev); ++ devm_free_irq(&pdev->dev, ndev->irq, ndev); + moxart_mac_free_memory(ndev); + free_netdev(ndev); + +-- +2.20.1 + diff --git a/queue-4.14/net-sonic-fix-a-resource-leak-in-an-error-handling-p.patch b/queue-4.14/net-sonic-fix-a-resource-leak-in-an-error-handling-p.patch new file mode 100644 index 00000000000..57f46034b78 --- /dev/null +++ b/queue-4.14/net-sonic-fix-a-resource-leak-in-an-error-handling-p.patch @@ -0,0 +1,52 @@ +From 0f3c7dfb7e63fb8552c30ec86f32f7a58d2197cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2020 08:18:03 +0200 +Subject: net/sonic: Fix a resource leak in an error handling path in + 'jazz_sonic_probe()' + +From: Christophe JAILLET + +[ Upstream commit 10e3cc180e64385edc9890c6855acf5ed9ca1339 ] + +A call to 'dma_alloc_coherent()' is hidden in 'sonic_alloc_descriptors()', +called from 'sonic_probe1()'. + +This is correctly freed in the remove function, but not in the error +handling path of the probe function. +Fix it and add the missing 'dma_free_coherent()' call. + +While at it, rename a label in order to be slightly more informative. + +Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update") +Signed-off-by: Christophe JAILLET +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/natsemi/jazzsonic.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/natsemi/jazzsonic.c b/drivers/net/ethernet/natsemi/jazzsonic.c +index d5b28884e21eb..9a6c91c9d111c 100644 +--- a/drivers/net/ethernet/natsemi/jazzsonic.c ++++ b/drivers/net/ethernet/natsemi/jazzsonic.c +@@ -247,13 +247,15 @@ static int jazz_sonic_probe(struct platform_device *pdev) + goto out; + err = register_netdev(dev); + if (err) +- goto out1; ++ goto undo_probe1; + + printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq); + + return 0; + +-out1: ++undo_probe1: ++ dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), ++ lp->descriptors, lp->descriptors_laddr); + release_mem_region(dev->base_addr, SONIC_MEM_SIZE); + out: + free_netdev(dev); +-- +2.20.1 + diff --git a/queue-4.14/series b/queue-4.14/series index d76e6792af1..bbd4ab5efc6 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -46,3 +46,8 @@ f2fs-sanity-check-of-xattr-entry-size.patch f2fs-fix-to-avoid-accessing-xattr-across-the-boundary.patch f2fs-fix-to-avoid-memory-leakage-in-f2fs_listxattr.patch net-stmmac-use-mutex-instead-of-spinlock.patch +shmem-fix-possible-deadlocks-on-shmlock_user_lock.patch +net-sonic-fix-a-resource-leak-in-an-error-handling-p.patch +net-moxa-fix-a-potential-double-free_irq.patch +drop_monitor-work-around-gcc-10-stringop-overflow-wa.patch +virtio-blk-handle-block_device_operations-callbacks-.patch diff --git a/queue-4.14/shmem-fix-possible-deadlocks-on-shmlock_user_lock.patch b/queue-4.14/shmem-fix-possible-deadlocks-on-shmlock_user_lock.patch new file mode 100644 index 00000000000..56118f5f2b1 --- /dev/null +++ b/queue-4.14/shmem-fix-possible-deadlocks-on-shmlock_user_lock.patch @@ -0,0 +1,80 @@ +From eba86af928b15bbf61a50ac1e8787598e3e06bb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2020 18:14:14 -0700 +Subject: shmem: fix possible deadlocks on shmlock_user_lock + +From: Hugh Dickins + +[ Upstream commit ea0dfeb4209b4eab954d6e00ed136bc6b48b380d ] + +Recent commit 71725ed10c40 ("mm: huge tmpfs: try to split_huge_page() +when punching hole") has allowed syzkaller to probe deeper, uncovering a +long-standing lockdep issue between the irq-unsafe shmlock_user_lock, +the irq-safe xa_lock on mapping->i_pages, and shmem inode's info->lock +which nests inside xa_lock (or tree_lock) since 4.8's shmem_uncharge(). + +user_shm_lock(), servicing SysV shmctl(SHM_LOCK), wants +shmlock_user_lock while its caller shmem_lock() holds info->lock with +interrupts disabled; but hugetlbfs_file_setup() calls user_shm_lock() +with interrupts enabled, and might be interrupted by a writeback endio +wanting xa_lock on i_pages. + +This may not risk an actual deadlock, since shmem inodes do not take +part in writeback accounting, but there are several easy ways to avoid +it. + +Requiring interrupts disabled for shmlock_user_lock would be easy, but +it's a high-level global lock for which that seems inappropriate. +Instead, recall that the use of info->lock to guard info->flags in +shmem_lock() dates from pre-3.1 days, when races with SHMEM_PAGEIN and +SHMEM_TRUNCATE could occur: nowadays it serves no purpose, the only flag +added or removed is VM_LOCKED itself, and calls to shmem_lock() an inode +are already serialized by the caller. + +Take info->lock out of the chain and the possibility of deadlock or +lockdep warning goes away. + +Fixes: 4595ef88d136 ("shmem: make shmem_inode_info::lock irq-safe") +Reported-by: syzbot+c8a8197c8852f566b9d9@syzkaller.appspotmail.com +Reported-by: syzbot+40b71e145e73f78f81ad@syzkaller.appspotmail.com +Signed-off-by: Hugh Dickins +Signed-off-by: Andrew Morton +Acked-by: Yang Shi +Cc: Yang Shi +Link: http://lkml.kernel.org/r/alpine.LSU.2.11.2004161707410.16322@eggly.anvils +Link: https://lore.kernel.org/lkml/000000000000e5838c05a3152f53@google.com/ +Link: https://lore.kernel.org/lkml/0000000000003712b305a331d3b1@google.com/ +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + mm/shmem.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/mm/shmem.c b/mm/shmem.c +index f9a1e0ba259f3..24005c3b345ca 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -2129,7 +2129,11 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user) + struct shmem_inode_info *info = SHMEM_I(inode); + int retval = -ENOMEM; + +- spin_lock_irq(&info->lock); ++ /* ++ * What serializes the accesses to info->flags? ++ * ipc_lock_object() when called from shmctl_do_lock(), ++ * no serialization needed when called from shm_destroy(). ++ */ + if (lock && !(info->flags & VM_LOCKED)) { + if (!user_shm_lock(inode->i_size, user)) + goto out_nomem; +@@ -2144,7 +2148,6 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user) + retval = 0; + + out_nomem: +- spin_unlock_irq(&info->lock); + return retval; + } + +-- +2.20.1 + diff --git a/queue-4.14/virtio-blk-handle-block_device_operations-callbacks-.patch b/queue-4.14/virtio-blk-handle-block_device_operations-callbacks-.patch new file mode 100644 index 00000000000..9e90b285a98 --- /dev/null +++ b/queue-4.14/virtio-blk-handle-block_device_operations-callbacks-.patch @@ -0,0 +1,217 @@ +From 6c97229b995f9c18b24ea367d7472ecb1c8a0690 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2020 15:04:42 +0100 +Subject: virtio-blk: handle block_device_operations callbacks after hot unplug + +From: Stefan Hajnoczi + +[ Upstream commit 90b5feb8c4bebc76c27fcaf3e1a0e5ca2d319e9e ] + +A userspace process holding a file descriptor to a virtio_blk device can +still invoke block_device_operations after hot unplug. This leads to a +use-after-free accessing vblk->vdev in virtblk_getgeo() when +ioctl(HDIO_GETGEO) is invoked: + + BUG: unable to handle kernel NULL pointer dereference at 0000000000000090 + IP: [] virtio_check_driver_offered_feature+0x10/0x90 [virtio] + PGD 800000003a92f067 PUD 3a930067 PMD 0 + Oops: 0000 [#1] SMP + CPU: 0 PID: 1310 Comm: hdio-getgeo Tainted: G OE ------------ 3.10.0-1062.el7.x86_64 #1 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 + task: ffff9be5fbfb8000 ti: ffff9be5fa890000 task.ti: ffff9be5fa890000 + RIP: 0010:[] [] virtio_check_driver_offered_feature+0x10/0x90 [virtio] + RSP: 0018:ffff9be5fa893dc8 EFLAGS: 00010246 + RAX: ffff9be5fc3f3400 RBX: ffff9be5fa893e30 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffff9be5fbc10b40 + RBP: ffff9be5fa893dc8 R08: 0000000000000301 R09: 0000000000000301 + R10: 0000000000000000 R11: 0000000000000000 R12: ffff9be5fdc24680 + R13: ffff9be5fbc10b40 R14: ffff9be5fbc10480 R15: 0000000000000000 + FS: 00007f1bfb968740(0000) GS:ffff9be5ffc00000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 0000000000000090 CR3: 000000003a894000 CR4: 0000000000360ff0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 + Call Trace: + [] virtblk_getgeo+0x47/0x110 [virtio_blk] + [] ? handle_mm_fault+0x39d/0x9b0 + [] blkdev_ioctl+0x1f5/0xa20 + [] block_ioctl+0x41/0x50 + [] do_vfs_ioctl+0x3a0/0x5a0 + [] SyS_ioctl+0xa1/0xc0 + +A related problem is that virtblk_remove() leaks the vd_index_ida index +when something still holds a reference to vblk->disk during hot unplug. +This causes virtio-blk device names to be lost (vda, vdb, etc). + +Fix these issues by protecting vblk->vdev with a mutex and reference +counting vblk so the vd_index_ida index can be removed in all cases. + +Fixes: 48e4043d4529 ("virtio: add virtio disk geometry feature") +Reported-by: Lance Digby +Signed-off-by: Stefan Hajnoczi +Link: https://lore.kernel.org/r/20200430140442.171016-1-stefanha@redhat.com +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Stefano Garzarella +Signed-off-by: Sasha Levin +--- + drivers/block/virtio_blk.c | 86 ++++++++++++++++++++++++++++++++++---- + 1 file changed, 78 insertions(+), 8 deletions(-) + +diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c +index 19d226ff15ef8..0e18eed62c575 100644 +--- a/drivers/block/virtio_blk.c ++++ b/drivers/block/virtio_blk.c +@@ -31,6 +31,15 @@ struct virtio_blk_vq { + } ____cacheline_aligned_in_smp; + + struct virtio_blk { ++ /* ++ * This mutex must be held by anything that may run after ++ * virtblk_remove() sets vblk->vdev to NULL. ++ * ++ * blk-mq, virtqueue processing, and sysfs attribute code paths are ++ * shut down before vblk->vdev is set to NULL and therefore do not need ++ * to hold this mutex. ++ */ ++ struct mutex vdev_mutex; + struct virtio_device *vdev; + + /* The disk structure for the kernel. */ +@@ -42,6 +51,13 @@ struct virtio_blk { + /* Process context for config space updates */ + struct work_struct config_work; + ++ /* ++ * Tracks references from block_device_operations open/release and ++ * virtio_driver probe/remove so this object can be freed once no ++ * longer in use. ++ */ ++ refcount_t refs; ++ + /* What host tells us, plus 2 for header & tailer. */ + unsigned int sg_elems; + +@@ -315,10 +331,55 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) + return err; + } + ++static void virtblk_get(struct virtio_blk *vblk) ++{ ++ refcount_inc(&vblk->refs); ++} ++ ++static void virtblk_put(struct virtio_blk *vblk) ++{ ++ if (refcount_dec_and_test(&vblk->refs)) { ++ ida_simple_remove(&vd_index_ida, vblk->index); ++ mutex_destroy(&vblk->vdev_mutex); ++ kfree(vblk); ++ } ++} ++ ++static int virtblk_open(struct block_device *bd, fmode_t mode) ++{ ++ struct virtio_blk *vblk = bd->bd_disk->private_data; ++ int ret = 0; ++ ++ mutex_lock(&vblk->vdev_mutex); ++ ++ if (vblk->vdev) ++ virtblk_get(vblk); ++ else ++ ret = -ENXIO; ++ ++ mutex_unlock(&vblk->vdev_mutex); ++ return ret; ++} ++ ++static void virtblk_release(struct gendisk *disk, fmode_t mode) ++{ ++ struct virtio_blk *vblk = disk->private_data; ++ ++ virtblk_put(vblk); ++} ++ + /* We provide getgeo only to please some old bootloader/partitioning tools */ + static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) + { + struct virtio_blk *vblk = bd->bd_disk->private_data; ++ int ret = 0; ++ ++ mutex_lock(&vblk->vdev_mutex); ++ ++ if (!vblk->vdev) { ++ ret = -ENXIO; ++ goto out; ++ } + + /* see if the host passed in geometry config */ + if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) { +@@ -334,12 +395,16 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) + geo->sectors = 1 << 5; + geo->cylinders = get_capacity(bd->bd_disk) >> 11; + } +- return 0; ++out: ++ mutex_unlock(&vblk->vdev_mutex); ++ return ret; + } + + static const struct block_device_operations virtblk_fops = { + .ioctl = virtblk_ioctl, + .owner = THIS_MODULE, ++ .open = virtblk_open, ++ .release = virtblk_release, + .getgeo = virtblk_getgeo, + }; + +@@ -659,6 +724,10 @@ static int virtblk_probe(struct virtio_device *vdev) + goto out_free_index; + } + ++ /* This reference is dropped in virtblk_remove(). */ ++ refcount_set(&vblk->refs, 1); ++ mutex_init(&vblk->vdev_mutex); ++ + vblk->vdev = vdev; + vblk->sg_elems = sg_elems; + +@@ -821,8 +890,6 @@ static int virtblk_probe(struct virtio_device *vdev) + static void virtblk_remove(struct virtio_device *vdev) + { + struct virtio_blk *vblk = vdev->priv; +- int index = vblk->index; +- int refc; + + /* Make sure no work handler is accessing the device. */ + flush_work(&vblk->config_work); +@@ -832,18 +899,21 @@ static void virtblk_remove(struct virtio_device *vdev) + + blk_mq_free_tag_set(&vblk->tag_set); + ++ mutex_lock(&vblk->vdev_mutex); ++ + /* Stop all the virtqueues. */ + vdev->config->reset(vdev); + +- refc = kref_read(&disk_to_dev(vblk->disk)->kobj.kref); ++ /* Virtqueues are stopped, nothing can use vblk->vdev anymore. */ ++ vblk->vdev = NULL; ++ + put_disk(vblk->disk); + vdev->config->del_vqs(vdev); + kfree(vblk->vqs); +- kfree(vblk); + +- /* Only free device id if we don't have any users */ +- if (refc == 1) +- ida_simple_remove(&vd_index_ida, index); ++ mutex_unlock(&vblk->vdev_mutex); ++ ++ virtblk_put(vblk); + } + + #ifdef CONFIG_PM_SLEEP +-- +2.20.1 + -- 2.47.3