From: Greg Kroah-Hartman Date: Sat, 7 Dec 2019 12:25:27 +0000 (+0100) Subject: 5.4-stable patches X-Git-Tag: v5.4.3~63 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0f4dabb70063df40c8ee62e69a91290de0ae8088;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: fuse-fix-leak-of-fuse_io_priv.patch fuse-verify-attributes.patch fuse-verify-nlink.patch fuse-verify-write-return.patch io_uring-fix-dead-hung-for-non-iter-fixed-rw.patch io_uring-transform-send-recvmsg-erestartsys-to-eintr.patch mwifiex-re-work-support-for-sdio-hw-reset.patch --- diff --git a/queue-5.4/fuse-fix-leak-of-fuse_io_priv.patch b/queue-5.4/fuse-fix-leak-of-fuse_io_priv.patch new file mode 100644 index 00000000000..330a98d0ec4 --- /dev/null +++ b/queue-5.4/fuse-fix-leak-of-fuse_io_priv.patch @@ -0,0 +1,46 @@ +From f1ebdeffc6f325e30e0ddb9f7a70f1370fa4b851 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Mon, 25 Nov 2019 20:48:46 +0100 +Subject: fuse: fix leak of fuse_io_priv + +From: Miklos Szeredi + +commit f1ebdeffc6f325e30e0ddb9f7a70f1370fa4b851 upstream. + +exit_aio() is sometimes stuck in wait_for_completion() after aio is issued +with direct IO and the task receives a signal. + +The reason is failure to call ->ki_complete() due to a leaked reference to +fuse_io_priv. This happens in fuse_async_req_send() if +fuse_simple_background() returns an error (e.g. -EINTR). + +In this case the error value is propagated via io->err, so return success +to not confuse callers. + +This issue is tracked as a virtio-fs issue: +https://gitlab.com/virtio-fs/qemu/issues/14 + +Reported-by: Masayoshi Mizuma +Fixes: 45ac96ed7c36 ("fuse: convert direct_io to simple api") +Cc: # v5.4 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/file.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -713,8 +713,10 @@ static ssize_t fuse_async_req_send(struc + + ia->ap.args.end = fuse_aio_complete_req; + err = fuse_simple_background(fc, &ia->ap.args, GFP_KERNEL); ++ if (err) ++ fuse_aio_complete_req(fc, &ia->ap.args, err); + +- return err ?: num_bytes; ++ return num_bytes; + } + + static ssize_t fuse_send_read(struct fuse_io_args *ia, loff_t pos, size_t count, diff --git a/queue-5.4/fuse-verify-attributes.patch b/queue-5.4/fuse-verify-attributes.patch new file mode 100644 index 00000000000..bb711667b8a --- /dev/null +++ b/queue-5.4/fuse-verify-attributes.patch @@ -0,0 +1,124 @@ +From eb59bd17d2fa6e5e84fba61a5ebdea984222e6d5 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 12 Nov 2019 11:49:04 +0100 +Subject: fuse: verify attributes + +From: Miklos Szeredi + +commit eb59bd17d2fa6e5e84fba61a5ebdea984222e6d5 upstream. + +If a filesystem returns negative inode sizes, future reads on the file were +causing the cpu to spin on truncate_pagecache. + +Create a helper to validate the attributes. This now does two things: + + - check the file mode + - check if the file size fits in i_size without overflowing + +Reported-by: Arijit Banerjee +Fixes: d8a5ba45457e ("[PATCH] FUSE - core") +Cc: # v2.6.14 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/dir.c | 22 ++++++++++++++++------ + fs/fuse/fuse_i.h | 2 ++ + fs/fuse/readdir.c | 2 +- + 3 files changed, 19 insertions(+), 7 deletions(-) + +--- a/fs/fuse/dir.c ++++ b/fs/fuse/dir.c +@@ -248,7 +248,8 @@ static int fuse_dentry_revalidate(struct + kfree(forget); + if (ret == -ENOMEM) + goto out; +- if (ret || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) ++ if (ret || fuse_invalid_attr(&outarg.attr) || ++ (outarg.attr.mode ^ inode->i_mode) & S_IFMT) + goto invalid; + + forget_all_cached_acls(inode); +@@ -319,6 +320,12 @@ int fuse_valid_type(int m) + S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); + } + ++bool fuse_invalid_attr(struct fuse_attr *attr) ++{ ++ return !fuse_valid_type(attr->mode) || ++ attr->size > LLONG_MAX; ++} ++ + int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name, + struct fuse_entry_out *outarg, struct inode **inode) + { +@@ -350,7 +357,7 @@ int fuse_lookup_name(struct super_block + err = -EIO; + if (!outarg->nodeid) + goto out_put_forget; +- if (!fuse_valid_type(outarg->attr.mode)) ++ if (fuse_invalid_attr(&outarg->attr)) + goto out_put_forget; + + *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, +@@ -475,7 +482,8 @@ static int fuse_create_open(struct inode + goto out_free_ff; + + err = -EIO; +- if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) ++ if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) || ++ fuse_invalid_attr(&outentry.attr)) + goto out_free_ff; + + ff->fh = outopen.fh; +@@ -583,7 +591,7 @@ static int create_new_entry(struct fuse_ + goto out_put_forget_req; + + err = -EIO; +- if (invalid_nodeid(outarg.nodeid)) ++ if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr)) + goto out_put_forget_req; + + if ((outarg.attr.mode ^ mode) & S_IFMT) +@@ -943,7 +951,8 @@ static int fuse_do_getattr(struct inode + args.out_args[0].value = &outarg; + err = fuse_simple_request(fc, &args); + if (!err) { +- if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { ++ if (fuse_invalid_attr(&outarg.attr) || ++ (inode->i_mode ^ outarg.attr.mode) & S_IFMT) { + make_bad_inode(inode); + err = -EIO; + } else { +@@ -1564,7 +1573,8 @@ int fuse_do_setattr(struct dentry *dentr + goto error; + } + +- if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { ++ if (fuse_invalid_attr(&outarg.attr) || ++ (inode->i_mode ^ outarg.attr.mode) & S_IFMT) { + make_bad_inode(inode); + err = -EIO; + goto error; +--- a/fs/fuse/fuse_i.h ++++ b/fs/fuse/fuse_i.h +@@ -989,6 +989,8 @@ void fuse_ctl_remove_conn(struct fuse_co + */ + int fuse_valid_type(int m); + ++bool fuse_invalid_attr(struct fuse_attr *attr); ++ + /** + * Is current process allowed to perform filesystem operation? + */ +--- a/fs/fuse/readdir.c ++++ b/fs/fuse/readdir.c +@@ -184,7 +184,7 @@ static int fuse_direntplus_link(struct f + + if (invalid_nodeid(o->nodeid)) + return -EIO; +- if (!fuse_valid_type(o->attr.mode)) ++ if (fuse_invalid_attr(&o->attr)) + return -EIO; + + fc = get_fuse_conn(dir); diff --git a/queue-5.4/fuse-verify-nlink.patch b/queue-5.4/fuse-verify-nlink.patch new file mode 100644 index 00000000000..706a2caabb4 --- /dev/null +++ b/queue-5.4/fuse-verify-nlink.patch @@ -0,0 +1,32 @@ +From c634da718db9b2fac201df2ae1b1b095344ce5eb Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 12 Nov 2019 11:49:04 +0100 +Subject: fuse: verify nlink + +From: Miklos Szeredi + +commit c634da718db9b2fac201df2ae1b1b095344ce5eb upstream. + +When adding a new hard link, make sure that i_nlink doesn't overflow. + +Fixes: ac45d61357e8 ("fuse: fix nlink after unlink") +Cc: # v3.4 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/dir.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/fuse/dir.c ++++ b/fs/fuse/dir.c +@@ -862,7 +862,8 @@ static int fuse_link(struct dentry *entr + + spin_lock(&fi->lock); + fi->attr_version = atomic64_inc_return(&fc->attr_version); +- inc_nlink(inode); ++ if (likely(inode->i_nlink < UINT_MAX)) ++ inc_nlink(inode); + spin_unlock(&fi->lock); + fuse_invalidate_attr(inode); + fuse_update_ctime(inode); diff --git a/queue-5.4/fuse-verify-write-return.patch b/queue-5.4/fuse-verify-write-return.patch new file mode 100644 index 00000000000..9ba1d649083 --- /dev/null +++ b/queue-5.4/fuse-verify-write-return.patch @@ -0,0 +1,31 @@ +From 8aab336b14c115c6bf1d4baeb9247e41ed9ce6de Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 12 Nov 2019 11:49:04 +0100 +Subject: fuse: verify write return + +From: Miklos Szeredi + +commit 8aab336b14c115c6bf1d4baeb9247e41ed9ce6de upstream. + +Make sure filesystem is not returning a bogus number of bytes written. + +Fixes: ea9b9907b82a ("fuse: implement perform_write") +Cc: # v2.6.26 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/file.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -1098,6 +1098,8 @@ static ssize_t fuse_send_write_pages(str + ia->write.in.flags = fuse_write_flags(iocb); + + err = fuse_simple_request(fc, &ap->args); ++ if (!err && ia->write.out.size > count) ++ err = -EIO; + + offset = ap->descs[0].offset; + count = ia->write.out.size; diff --git a/queue-5.4/io_uring-fix-dead-hung-for-non-iter-fixed-rw.patch b/queue-5.4/io_uring-fix-dead-hung-for-non-iter-fixed-rw.patch new file mode 100644 index 00000000000..6762cabe5a3 --- /dev/null +++ b/queue-5.4/io_uring-fix-dead-hung-for-non-iter-fixed-rw.patch @@ -0,0 +1,60 @@ +From 311ae9e159d81a1ec1cf645daf40b39ae5a0bd84 Mon Sep 17 00:00:00 2001 +From: Pavel Begunkov +Date: Sun, 24 Nov 2019 11:58:24 +0300 +Subject: io_uring: fix dead-hung for non-iter fixed rw + +From: Pavel Begunkov + +commit 311ae9e159d81a1ec1cf645daf40b39ae5a0bd84 upstream. + +Read/write requests to devices without implemented read/write_iter +using fixed buffers can cause general protection fault, which totally +hangs a machine. + +io_import_fixed() initialises iov_iter with bvec, but loop_rw_iter() +accesses it as iovec, dereferencing random address. + +kmap() page by page in this case + +Cc: stable@vger.kernel.org +Signed-off-by: Pavel Begunkov +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + fs/io_uring.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/fs/io_uring.c ++++ b/fs/io_uring.c +@@ -1351,9 +1351,19 @@ static ssize_t loop_rw_iter(int rw, stru + return -EAGAIN; + + while (iov_iter_count(iter)) { +- struct iovec iovec = iov_iter_iovec(iter); ++ struct iovec iovec; + ssize_t nr; + ++ if (!iov_iter_is_bvec(iter)) { ++ iovec = iov_iter_iovec(iter); ++ } else { ++ /* fixed buffers import bvec */ ++ iovec.iov_base = kmap(iter->bvec->bv_page) ++ + iter->iov_offset; ++ iovec.iov_len = min(iter->count, ++ iter->bvec->bv_len - iter->iov_offset); ++ } ++ + if (rw == READ) { + nr = file->f_op->read(file, iovec.iov_base, + iovec.iov_len, &kiocb->ki_pos); +@@ -1362,6 +1372,9 @@ static ssize_t loop_rw_iter(int rw, stru + iovec.iov_len, &kiocb->ki_pos); + } + ++ if (iov_iter_is_bvec(iter)) ++ kunmap(iter->bvec->bv_page); ++ + if (nr < 0) { + if (!ret) + ret = nr; diff --git a/queue-5.4/io_uring-transform-send-recvmsg-erestartsys-to-eintr.patch b/queue-5.4/io_uring-transform-send-recvmsg-erestartsys-to-eintr.patch new file mode 100644 index 00000000000..896cd297d1f --- /dev/null +++ b/queue-5.4/io_uring-transform-send-recvmsg-erestartsys-to-eintr.patch @@ -0,0 +1,31 @@ +From 441cdbd5449b4923cd413d3ba748124f91388be9 Mon Sep 17 00:00:00 2001 +From: Jens Axboe +Date: Mon, 2 Dec 2019 18:49:10 -0700 +Subject: io_uring: transform send/recvmsg() -ERESTARTSYS to -EINTR + +From: Jens Axboe + +commit 441cdbd5449b4923cd413d3ba748124f91388be9 upstream. + +We should never return -ERESTARTSYS to userspace, transform it into +-EINTR. + +Cc: stable@vger.kernel.org # v5.3+ +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + fs/io_uring.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/io_uring.c ++++ b/fs/io_uring.c +@@ -1667,6 +1667,8 @@ static int io_send_recvmsg(struct io_kio + ret = fn(sock, msg, flags); + if (force_nonblock && ret == -EAGAIN) + return ret; ++ if (ret == -ERESTARTSYS) ++ ret = -EINTR; + } + + io_cqring_add_event(req->ctx, sqe->user_data, ret); diff --git a/queue-5.4/mwifiex-re-work-support-for-sdio-hw-reset.patch b/queue-5.4/mwifiex-re-work-support-for-sdio-hw-reset.patch new file mode 100644 index 00000000000..b0e3051c6db --- /dev/null +++ b/queue-5.4/mwifiex-re-work-support-for-sdio-hw-reset.patch @@ -0,0 +1,137 @@ +From cdb2256f795e8e78cc43f32d091695b127dfb4df Mon Sep 17 00:00:00 2001 +From: Ulf Hansson +Date: Fri, 25 Oct 2019 09:28:17 +0200 +Subject: mwifiex: Re-work support for SDIO HW reset + +From: Ulf Hansson + +commit cdb2256f795e8e78cc43f32d091695b127dfb4df upstream. + +The SDIO HW reset procedure in mwifiex_sdio_card_reset_work() is broken, +when the SDIO card is shared with another SDIO func driver. This is the +case when the Bluetooth btmrvl driver is being used in combination with +mwifiex. More precisely, when mwifiex_sdio_card_reset_work() runs to resets +the SDIO card, the btmrvl driver doesn't get notified about it. Beyond that +point, the btmrvl driver will fail to communicate with the SDIO card. + +This is a generic problem for SDIO func drivers sharing an SDIO card, which +are about to be addressed in subsequent changes to the mmc core and the +mmc_hw_reset() interface. In principle, these changes means the +mmc_hw_reset() interface starts to return 1 if the are multiple drivers for +the SDIO card, as to indicate to the caller that the reset needed to be +scheduled asynchronously through a hotplug mechanism of the SDIO card. + +Let's prepare the mwifiex driver to support the upcoming new behaviour of +mmc_hw_reset(), which means extending the mwifiex_sdio_card_reset_work() to +support the asynchronous SDIO HW reset path. This also means, we need to +allow the ->remove() callback to run, without waiting for the FW to be +loaded. Additionally, during system suspend, mwifiex_sdio_suspend() may be +called when a reset has been scheduled, but waiting to be executed. In this +scenario let's simply return -EBUSY to abort the suspend process, as to +allow the reset to be completed first. + +Reviewed-by: Douglas Anderson +Tested-by: Douglas Anderson +Cc: stable@vger.kernel.org # v5.4+ +Acked-by: Kalle Valo +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/marvell/mwifiex/main.c | 5 +++- + drivers/net/wireless/marvell/mwifiex/main.h | 1 + drivers/net/wireless/marvell/mwifiex/sdio.c | 33 ++++++++++++++++++---------- + 3 files changed, 27 insertions(+), 12 deletions(-) + +--- a/drivers/net/wireless/marvell/mwifiex/main.c ++++ b/drivers/net/wireless/marvell/mwifiex/main.c +@@ -631,6 +631,7 @@ static int _mwifiex_fw_dpc(const struct + + mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); + mwifiex_dbg(adapter, MSG, "driver_version = %s\n", fmt); ++ adapter->is_up = true; + goto done; + + err_add_intf: +@@ -1469,6 +1470,7 @@ int mwifiex_shutdown_sw(struct mwifiex_a + mwifiex_deauthenticate(priv, NULL); + + mwifiex_uninit_sw(adapter); ++ adapter->is_up = false; + + if (adapter->if_ops.down_dev) + adapter->if_ops.down_dev(adapter); +@@ -1730,7 +1732,8 @@ int mwifiex_remove_card(struct mwifiex_a + if (!adapter) + return 0; + +- mwifiex_uninit_sw(adapter); ++ if (adapter->is_up) ++ mwifiex_uninit_sw(adapter); + + if (adapter->irq_wakeup >= 0) + device_init_wakeup(adapter->dev, false); +--- a/drivers/net/wireless/marvell/mwifiex/main.h ++++ b/drivers/net/wireless/marvell/mwifiex/main.h +@@ -1017,6 +1017,7 @@ struct mwifiex_adapter { + + /* For synchronizing FW initialization with device lifecycle. */ + struct completion *fw_done; ++ bool is_up; + + bool ext_scan; + u8 fw_api_ver; +--- a/drivers/net/wireless/marvell/mwifiex/sdio.c ++++ b/drivers/net/wireless/marvell/mwifiex/sdio.c +@@ -444,6 +444,9 @@ static int mwifiex_sdio_suspend(struct d + return 0; + } + ++ if (!adapter->is_up) ++ return -EBUSY; ++ + mwifiex_enable_wake(adapter); + + /* Enable the Host Sleep */ +@@ -2220,22 +2223,30 @@ static void mwifiex_sdio_card_reset_work + struct sdio_func *func = card->func; + int ret; + ++ /* Prepare the adapter for the reset. */ + mwifiex_shutdown_sw(adapter); ++ clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); ++ clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); + +- /* power cycle the adapter */ ++ /* Run a HW reset of the SDIO interface. */ + sdio_claim_host(func); +- mmc_hw_reset(func->card->host); ++ ret = mmc_hw_reset(func->card->host); + sdio_release_host(func); + +- /* Previous save_adapter won't be valid after this. We will cancel +- * pending work requests. +- */ +- clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); +- clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); +- +- ret = mwifiex_reinit_sw(adapter); +- if (ret) +- dev_err(&func->dev, "reinit failed: %d\n", ret); ++ switch (ret) { ++ case 1: ++ dev_dbg(&func->dev, "SDIO HW reset asynchronous\n"); ++ complete_all(adapter->fw_done); ++ break; ++ case 0: ++ ret = mwifiex_reinit_sw(adapter); ++ if (ret) ++ dev_err(&func->dev, "reinit failed: %d\n", ret); ++ break; ++ default: ++ dev_err(&func->dev, "SDIO HW reset failed: %d\n", ret); ++ break; ++ } + } + + /* This function read/write firmware */ diff --git a/queue-5.4/series b/queue-5.4/series index 8d417fb02c9..217d77483fa 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -16,3 +16,10 @@ serial-serial_core-perform-null-checks-for-break_ctl-ops.patch serial-stm32-fix-clearing-interrupt-error-flags.patch serial-8250_dw-avoid-double-error-messaging-when-irq-absent.patch serial-ifx6x60-add-missed-pm_runtime_disable.patch +mwifiex-re-work-support-for-sdio-hw-reset.patch +io_uring-fix-dead-hung-for-non-iter-fixed-rw.patch +io_uring-transform-send-recvmsg-erestartsys-to-eintr.patch +fuse-fix-leak-of-fuse_io_priv.patch +fuse-verify-nlink.patch +fuse-verify-write-return.patch +fuse-verify-attributes.patch