From: Greg Kroah-Hartman Date: Mon, 24 Jan 2022 09:48:40 +0000 (+0100) Subject: 4.19-stable patches X-Git-Tag: v4.4.300~92 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9c7850205059da4fc0259b4969928203e249a870;p=thirdparty%2Fkernel%2Fstable-queue.git 4.19-stable patches added patches: asoc-dpcm-prevent-snd_soc_dpcm-use-after-free.patch crypto-stm32-crc32-fix-kernel-bug-triggered-in-probe.patch fuse-fix-bad-inode.patch fuse-fix-live-lock-in-fuse_iget.patch regulator-core-let-boot-on-regulators-be-powered-off.patch --- diff --git a/queue-4.19/asoc-dpcm-prevent-snd_soc_dpcm-use-after-free.patch b/queue-4.19/asoc-dpcm-prevent-snd_soc_dpcm-use-after-free.patch new file mode 100644 index 00000000000..22485d4fe62 --- /dev/null +++ b/queue-4.19/asoc-dpcm-prevent-snd_soc_dpcm-use-after-free.patch @@ -0,0 +1,273 @@ +From a9764869779081e8bf24da07ac040e8f3efcf13a Mon Sep 17 00:00:00 2001 +From: KaiChieh Chuang +Date: Fri, 8 Mar 2019 13:05:53 +0800 +Subject: ASoC: dpcm: prevent snd_soc_dpcm use after free + +From: KaiChieh Chuang + +commit a9764869779081e8bf24da07ac040e8f3efcf13a upstream. + +The dpcm get from fe_clients/be_clients +may be free before use + +Add a spin lock at snd_soc_card level, +to protect the dpcm instance. +The lock may be used in atomic context, so use spin lock. + +Use irq spin lock version, +since the lock may be used in interrupts. + +possible race condition between +void dpcm_be_disconnect( + ... + list_del(&dpcm->list_be); + list_del(&dpcm->list_fe); + kfree(dpcm); + ... + +and + for_each_dpcm_fe() + for_each_dpcm_be*() + +race condition example +Thread 1: + snd_soc_dapm_mixer_update_power() + -> soc_dpcm_runtime_update() + -> dpcm_be_disconnect() + -> kfree(dpcm); +Thread 2: + dpcm_fe_dai_trigger() + -> dpcm_be_dai_trigger() + -> snd_soc_dpcm_can_be_free_stop() + -> if (dpcm->fe == fe) + +Excpetion Scenario: + two FE link to same BE + FE1 -> BE + FE2 -> + + Thread 1: switch of mixer between FE2 -> BE + Thread 2: pcm_stop FE1 + +Exception: + +Unable to handle kernel paging request at virtual address dead0000000000e0 + +pc=<> [] dpcm_be_dai_trigger+0x29c/0x47c + sound/soc/soc-pcm.c:3226 + if (dpcm->fe == fe) +lr=<> [] dpcm_fe_dai_do_trigger+0x94/0x26c + +Backtrace: +[] notify_die+0x68/0xb8 +[] die+0x118/0x2a8 +[] __do_kernel_fault+0x13c/0x14c +[] do_translation_fault+0x64/0xa0 +[] do_mem_abort+0x4c/0xd0 +[] el1_da+0x24/0x40 +[] dpcm_be_dai_trigger+0x29c/0x47c +[] dpcm_fe_dai_do_trigger+0x94/0x26c +[] dpcm_fe_dai_trigger+0x3c/0x44 +[] snd_pcm_do_stop+0x50/0x5c +[] snd_pcm_action+0xb4/0x13c +[] snd_pcm_drop+0xa0/0x128 +[] snd_pcm_common_ioctl+0x9d8/0x30f0 +[] snd_pcm_ioctl_compat+0x29c/0x2f14 +[] compat_SyS_ioctl+0x128/0x244 +[] el0_svc_naked+0x34/0x38 +[] 0xffffffffffffffff + +Signed-off-by: KaiChieh Chuang +Signed-off-by: Mark Brown +[willmcvicker: move spinlock to bottom of struct snd_soc_card] +Signed-off-by: Will McVicker +Cc: stable@vger.kernel.org # 4.19+ +Signed-off-by: Greg Kroah-Hartman +--- + include/sound/soc.h | 2 ++ + sound/soc/soc-core.c | 1 + + sound/soc/soc-pcm.c | 40 +++++++++++++++++++++++++++++++++------- + 3 files changed, 36 insertions(+), 7 deletions(-) + +--- a/include/sound/soc.h ++++ b/include/sound/soc.h +@@ -1113,6 +1113,8 @@ struct snd_soc_card { + u32 pop_time; + + void *drvdata; ++ ++ spinlock_t dpcm_lock; + }; + + /* SoC machine DAI configuration, glues a codec and cpu DAI together */ +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -2752,6 +2752,7 @@ int snd_soc_register_card(struct snd_soc + card->instantiated = 0; + mutex_init(&card->mutex); + mutex_init(&card->dapm_mutex); ++ spin_lock_init(&card->dpcm_lock); + + ret = snd_soc_instantiate_card(card); + if (ret != 0) +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1221,6 +1221,7 @@ static int dpcm_be_connect(struct snd_so + struct snd_soc_pcm_runtime *be, int stream) + { + struct snd_soc_dpcm *dpcm; ++ unsigned long flags; + + /* only add new dpcms */ + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { +@@ -1236,8 +1237,10 @@ static int dpcm_be_connect(struct snd_so + dpcm->fe = fe; + be->dpcm[stream].runtime = fe->dpcm[stream].runtime; + dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; ++ spin_lock_irqsave(&fe->card->dpcm_lock, flags); + list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); + list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); ++ spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); + + dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n", + stream ? "capture" : "playback", fe->dai_link->name, +@@ -1283,6 +1286,7 @@ static void dpcm_be_reparent(struct snd_ + void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) + { + struct snd_soc_dpcm *dpcm, *d; ++ unsigned long flags; + + list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { + dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", +@@ -1302,8 +1306,10 @@ void dpcm_be_disconnect(struct snd_soc_p + #ifdef CONFIG_DEBUG_FS + debugfs_remove(dpcm->debugfs_state); + #endif ++ spin_lock_irqsave(&fe->card->dpcm_lock, flags); + list_del(&dpcm->list_be); + list_del(&dpcm->list_fe); ++ spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); + kfree(dpcm); + } + } +@@ -1557,10 +1563,13 @@ int dpcm_process_paths(struct snd_soc_pc + void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) + { + struct snd_soc_dpcm *dpcm; ++ unsigned long flags; + ++ spin_lock_irqsave(&fe->card->dpcm_lock, flags); + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + dpcm->be->dpcm[stream].runtime_update = + SND_SOC_DPCM_UPDATE_NO; ++ spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); + } + + static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, +@@ -2626,6 +2635,7 @@ static int dpcm_run_update_startup(struc + struct snd_soc_dpcm *dpcm; + enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; + int ret; ++ unsigned long flags; + + dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n", + stream ? "capture" : "playback", fe->dai_link->name); +@@ -2695,11 +2705,13 @@ close: + dpcm_be_dai_shutdown(fe, stream); + disconnect: + /* disconnect any non started BEs */ ++ spin_lock_irqsave(&fe->card->dpcm_lock, flags); + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dpcm->be; + if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) + dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; + } ++ spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); + + return ret; + } +@@ -3278,7 +3290,10 @@ int snd_soc_dpcm_can_be_free_stop(struct + { + struct snd_soc_dpcm *dpcm; + int state; ++ int ret = 1; ++ unsigned long flags; + ++ spin_lock_irqsave(&fe->card->dpcm_lock, flags); + list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + + if (dpcm->fe == fe) +@@ -3287,12 +3302,15 @@ int snd_soc_dpcm_can_be_free_stop(struct + state = dpcm->fe->dpcm[stream].state; + if (state == SND_SOC_DPCM_STATE_START || + state == SND_SOC_DPCM_STATE_PAUSED || +- state == SND_SOC_DPCM_STATE_SUSPEND) +- return 0; ++ state == SND_SOC_DPCM_STATE_SUSPEND) { ++ ret = 0; ++ break; ++ } + } ++ spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); + + /* it's safe to free/stop this BE DAI */ +- return 1; ++ return ret; + } + EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop); + +@@ -3305,7 +3323,10 @@ int snd_soc_dpcm_can_be_params(struct sn + { + struct snd_soc_dpcm *dpcm; + int state; ++ int ret = 1; ++ unsigned long flags; + ++ spin_lock_irqsave(&fe->card->dpcm_lock, flags); + list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + + if (dpcm->fe == fe) +@@ -3315,12 +3336,15 @@ int snd_soc_dpcm_can_be_params(struct sn + if (state == SND_SOC_DPCM_STATE_START || + state == SND_SOC_DPCM_STATE_PAUSED || + state == SND_SOC_DPCM_STATE_SUSPEND || +- state == SND_SOC_DPCM_STATE_PREPARE) +- return 0; ++ state == SND_SOC_DPCM_STATE_PREPARE) { ++ ret = 0; ++ break; ++ } + } ++ spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); + + /* it's safe to change hw_params */ +- return 1; ++ return ret; + } + EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); + +@@ -3359,6 +3383,7 @@ static ssize_t dpcm_show_state(struct sn + struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params; + struct snd_soc_dpcm *dpcm; + ssize_t offset = 0; ++ unsigned long flags; + + /* FE state */ + offset += scnprintf(buf + offset, size - offset, +@@ -3386,6 +3411,7 @@ static ssize_t dpcm_show_state(struct sn + goto out; + } + ++ spin_lock_irqsave(&fe->card->dpcm_lock, flags); + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dpcm->be; + params = &dpcm->hw_params; +@@ -3406,7 +3432,7 @@ static ssize_t dpcm_show_state(struct sn + params_channels(params), + params_rate(params)); + } +- ++ spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); + out: + return offset; + } diff --git a/queue-4.19/crypto-stm32-crc32-fix-kernel-bug-triggered-in-probe.patch b/queue-4.19/crypto-stm32-crc32-fix-kernel-bug-triggered-in-probe.patch new file mode 100644 index 00000000000..0707d8fd03f --- /dev/null +++ b/queue-4.19/crypto-stm32-crc32-fix-kernel-bug-triggered-in-probe.patch @@ -0,0 +1,64 @@ +From 29009604ad4e3ef784fd9b9fef6f23610ddf633d Mon Sep 17 00:00:00 2001 +From: Marek Vasut +Date: Mon, 20 Dec 2021 20:50:22 +0100 +Subject: crypto: stm32/crc32 - Fix kernel BUG triggered in probe() + +From: Marek Vasut + +commit 29009604ad4e3ef784fd9b9fef6f23610ddf633d upstream. + +The include/linux/crypto.h struct crypto_alg field cra_driver_name description +states "Unique name of the transformation provider. " ... " this contains the +name of the chip or provider and the name of the transformation algorithm." + +In case of the stm32-crc driver, field cra_driver_name is identical for all +registered transformation providers and set to the name of the driver itself, +which is incorrect. This patch fixes it by assigning a unique cra_driver_name +to each registered transformation provider. + +The kernel crash is triggered when the driver calls crypto_register_shashes() +which calls crypto_register_shash(), which calls crypto_register_alg(), which +calls __crypto_register_alg(), which returns -EEXIST, which is propagated +back through this call chain. Upon -EEXIST from crypto_register_shash(), the +crypto_register_shashes() starts unregistering the providers back, and calls +crypto_unregister_shash(), which calls crypto_unregister_alg(), and this is +where the BUG() triggers due to incorrect cra_refcnt. + +Fixes: b51dbe90912a ("crypto: stm32 - Support for STM32 CRC32 crypto module") +Signed-off-by: Marek Vasut +Cc: # 4.12+ +Cc: Alexandre Torgue +Cc: Fabien Dessenne +Cc: Herbert Xu +Cc: Lionel Debieve +Cc: Nicolas Toromanoff +Cc: linux-arm-kernel@lists.infradead.org +Cc: linux-stm32@st-md-mailman.stormreply.com +To: linux-crypto@vger.kernel.org +Acked-by: Nicolas Toromanoff +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/stm32/stm32_crc32.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/crypto/stm32/stm32_crc32.c ++++ b/drivers/crypto/stm32/stm32_crc32.c +@@ -230,7 +230,7 @@ static struct shash_alg algs[] = { + .digestsize = CHKSUM_DIGEST_SIZE, + .base = { + .cra_name = "crc32", +- .cra_driver_name = DRIVER_NAME, ++ .cra_driver_name = "stm32-crc32-crc32", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .cra_blocksize = CHKSUM_BLOCK_SIZE, +@@ -252,7 +252,7 @@ static struct shash_alg algs[] = { + .digestsize = CHKSUM_DIGEST_SIZE, + .base = { + .cra_name = "crc32c", +- .cra_driver_name = DRIVER_NAME, ++ .cra_driver_name = "stm32-crc32-crc32c", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .cra_blocksize = CHKSUM_BLOCK_SIZE, diff --git a/queue-4.19/fuse-fix-bad-inode.patch b/queue-4.19/fuse-fix-bad-inode.patch new file mode 100644 index 00000000000..a565ca7b7bc --- /dev/null +++ b/queue-4.19/fuse-fix-bad-inode.patch @@ -0,0 +1,359 @@ +From 5d069dbe8aaf2a197142558b6fb2978189ba3454 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Thu, 10 Dec 2020 15:33:14 +0100 +Subject: fuse: fix bad inode + +From: Miklos Szeredi + +commit 5d069dbe8aaf2a197142558b6fb2978189ba3454 upstream. + +Jan Kara's analysis of the syzbot report (edited): + + The reproducer opens a directory on FUSE filesystem, it then attaches + dnotify mark to the open directory. After that a fuse_do_getattr() call + finds that attributes returned by the server are inconsistent, and calls + make_bad_inode() which, among other things does: + + inode->i_mode = S_IFREG; + + This then confuses dnotify which doesn't tear down its structures + properly and eventually crashes. + +Avoid calling make_bad_inode() on a live inode: switch to a private flag on +the fuse inode. Also add the test to ops which the bad_inode_ops would +have caught. + +This bug goes back to the initial merge of fuse in 2.6.14... + +Reported-by: syzbot+f427adf9324b92652ccc@syzkaller.appspotmail.com +Signed-off-by: Miklos Szeredi +Tested-by: Jan Kara +Cc: +[adjusted for missing fs/fuse/readdir.c and changes in fuse_evict_inode() in 4.14] +Signed-off-by: Samuel Mendoza-Jonas +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/acl.c | 6 ++++++ + fs/fuse/dir.c | 37 ++++++++++++++++++++++++++++++++----- + fs/fuse/file.c | 21 +++++++++++++++------ + fs/fuse/fuse_i.h | 12 ++++++++++++ + fs/fuse/inode.c | 2 +- + fs/fuse/xattr.c | 9 +++++++++ + 6 files changed, 75 insertions(+), 12 deletions(-) + +--- a/fs/fuse/acl.c ++++ b/fs/fuse/acl.c +@@ -19,6 +19,9 @@ struct posix_acl *fuse_get_acl(struct in + void *value = NULL; + struct posix_acl *acl; + ++ if (fuse_is_bad(inode)) ++ return ERR_PTR(-EIO); ++ + if (!fc->posix_acl || fc->no_getxattr) + return NULL; + +@@ -53,6 +56,9 @@ int fuse_set_acl(struct inode *inode, st + const char *name; + int ret; + ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + if (!fc->posix_acl || fc->no_setxattr) + return -EOPNOTSUPP; + +--- a/fs/fuse/dir.c ++++ b/fs/fuse/dir.c +@@ -187,7 +187,7 @@ static int fuse_dentry_revalidate(struct + int ret; + + inode = d_inode_rcu(entry); +- if (inode && is_bad_inode(inode)) ++ if (inode && fuse_is_bad(inode)) + goto invalid; + else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) || + (flags & LOOKUP_REVAL)) { +@@ -364,6 +364,9 @@ static struct dentry *fuse_lookup(struct + bool outarg_valid = true; + bool locked; + ++ if (fuse_is_bad(dir)) ++ return ERR_PTR(-EIO); ++ + locked = fuse_lock_inode(dir); + err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, + &outarg, &inode); +@@ -504,6 +507,9 @@ static int fuse_atomic_open(struct inode + struct fuse_conn *fc = get_fuse_conn(dir); + struct dentry *res = NULL; + ++ if (fuse_is_bad(dir)) ++ return -EIO; ++ + if (d_in_lookup(entry)) { + res = fuse_lookup(dir, entry, 0); + if (IS_ERR(res)) +@@ -552,6 +558,9 @@ static int create_new_entry(struct fuse_ + int err; + struct fuse_forget_link *forget; + ++ if (fuse_is_bad(dir)) ++ return -EIO; ++ + forget = fuse_alloc_forget(); + if (!forget) + return -ENOMEM; +@@ -679,6 +688,9 @@ static int fuse_unlink(struct inode *dir + struct fuse_conn *fc = get_fuse_conn(dir); + FUSE_ARGS(args); + ++ if (fuse_is_bad(dir)) ++ return -EIO; ++ + args.in.h.opcode = FUSE_UNLINK; + args.in.h.nodeid = get_node_id(dir); + args.in.numargs = 1; +@@ -715,6 +727,9 @@ static int fuse_rmdir(struct inode *dir, + struct fuse_conn *fc = get_fuse_conn(dir); + FUSE_ARGS(args); + ++ if (fuse_is_bad(dir)) ++ return -EIO; ++ + args.in.h.opcode = FUSE_RMDIR; + args.in.h.nodeid = get_node_id(dir); + args.in.numargs = 1; +@@ -793,6 +808,9 @@ static int fuse_rename2(struct inode *ol + struct fuse_conn *fc = get_fuse_conn(olddir); + int err; + ++ if (fuse_is_bad(olddir)) ++ return -EIO; ++ + if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) + return -EINVAL; + +@@ -928,7 +946,7 @@ static int fuse_do_getattr(struct inode + if (!err) { + if (fuse_invalid_attr(&outarg.attr) || + (inode->i_mode ^ outarg.attr.mode) & S_IFMT) { +- make_bad_inode(inode); ++ fuse_make_bad(inode); + err = -EIO; + } else { + fuse_change_attributes(inode, &outarg.attr, +@@ -1125,6 +1143,9 @@ static int fuse_permission(struct inode + bool refreshed = false; + int err = 0; + ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + if (!fuse_allow_current_process(fc)) + return -EACCES; + +@@ -1262,7 +1283,7 @@ retry: + dput(dentry); + goto retry; + } +- if (is_bad_inode(inode)) { ++ if (fuse_is_bad(inode)) { + dput(dentry); + return -EIO; + } +@@ -1360,7 +1381,7 @@ static int fuse_readdir(struct file *fil + u64 attr_version = 0; + bool locked; + +- if (is_bad_inode(inode)) ++ if (fuse_is_bad(inode)) + return -EIO; + + req = fuse_get_req(fc, 1); +@@ -1718,7 +1739,7 @@ int fuse_do_setattr(struct dentry *dentr + + if (fuse_invalid_attr(&outarg.attr) || + (inode->i_mode ^ outarg.attr.mode) & S_IFMT) { +- make_bad_inode(inode); ++ fuse_make_bad(inode); + err = -EIO; + goto error; + } +@@ -1774,6 +1795,9 @@ static int fuse_setattr(struct dentry *e + struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL; + int ret; + ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + if (!fuse_allow_current_process(get_fuse_conn(inode))) + return -EACCES; + +@@ -1832,6 +1856,9 @@ static int fuse_getattr(const struct pat + struct inode *inode = d_inode(path->dentry); + struct fuse_conn *fc = get_fuse_conn(inode); + ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + if (!fuse_allow_current_process(fc)) + return -EACCES; + +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -210,6 +210,9 @@ int fuse_open_common(struct inode *inode + fc->atomic_o_trunc && + fc->writeback_cache; + ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + err = generic_file_open(inode, file); + if (err) + return err; +@@ -411,7 +414,7 @@ static int fuse_flush(struct file *file, + struct fuse_flush_in inarg; + int err; + +- if (is_bad_inode(inode)) ++ if (fuse_is_bad(inode)) + return -EIO; + + if (fc->no_flush) +@@ -459,7 +462,7 @@ int fuse_fsync_common(struct file *file, + struct fuse_fsync_in inarg; + int err; + +- if (is_bad_inode(inode)) ++ if (fuse_is_bad(inode)) + return -EIO; + + inode_lock(inode); +@@ -774,7 +777,7 @@ static int fuse_readpage(struct file *fi + int err; + + err = -EIO; +- if (is_bad_inode(inode)) ++ if (fuse_is_bad(inode)) + goto out; + + err = fuse_do_readpage(file, page); +@@ -901,7 +904,7 @@ static int fuse_readpages(struct file *f + int nr_alloc = min_t(unsigned, nr_pages, FUSE_MAX_PAGES_PER_REQ); + + err = -EIO; +- if (is_bad_inode(inode)) ++ if (fuse_is_bad(inode)) + goto out; + + data.file = file; +@@ -931,6 +934,9 @@ static ssize_t fuse_file_read_iter(struc + struct inode *inode = iocb->ki_filp->f_mapping->host; + struct fuse_conn *fc = get_fuse_conn(inode); + ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + /* + * In auto invalidate mode, always update attributes on read. + * Otherwise, only update if we attempt to read past EOF (to ensure +@@ -1188,6 +1194,9 @@ static ssize_t fuse_file_write_iter(stru + ssize_t err; + loff_t endbyte = 0; + ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + if (get_fuse_conn(inode)->writeback_cache) { + /* Update size (EOF optimization) and mode (SUID clearing) */ + err = fuse_update_attributes(mapping->host, file); +@@ -1920,7 +1929,7 @@ static int fuse_writepages(struct addres + int err; + + err = -EIO; +- if (is_bad_inode(inode)) ++ if (fuse_is_bad(inode)) + goto out; + + data.inode = inode; +@@ -2705,7 +2714,7 @@ long fuse_ioctl_common(struct file *file + if (!fuse_allow_current_process(fc)) + return -EACCES; + +- if (is_bad_inode(inode)) ++ if (fuse_is_bad(inode)) + return -EIO; + + return fuse_do_ioctl(file, cmd, arg, flags); +--- a/fs/fuse/fuse_i.h ++++ b/fs/fuse/fuse_i.h +@@ -118,6 +118,8 @@ enum { + FUSE_I_INIT_RDPLUS, + /** An operation changing file size is in progress */ + FUSE_I_SIZE_UNSTABLE, ++ /* Bad inode */ ++ FUSE_I_BAD, + }; + + struct fuse_conn; +@@ -700,6 +702,16 @@ static inline u64 get_node_id(struct ino + return get_fuse_inode(inode)->nodeid; + } + ++static inline void fuse_make_bad(struct inode *inode) ++{ ++ set_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state); ++} ++ ++static inline bool fuse_is_bad(struct inode *inode) ++{ ++ return unlikely(test_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state)); ++} ++ + /** Device operations */ + extern const struct file_operations fuse_dev_operations; + +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -317,7 +317,7 @@ struct inode *fuse_iget(struct super_blo + unlock_new_inode(inode); + } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { + /* Inode has changed type, any I/O on the old should fail */ +- make_bad_inode(inode); ++ fuse_make_bad(inode); + iput(inode); + goto retry; + } +--- a/fs/fuse/xattr.c ++++ b/fs/fuse/xattr.c +@@ -113,6 +113,9 @@ ssize_t fuse_listxattr(struct dentry *en + struct fuse_getxattr_out outarg; + ssize_t ret; + ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + if (!fuse_allow_current_process(fc)) + return -EACCES; + +@@ -178,6 +181,9 @@ static int fuse_xattr_get(const struct x + struct dentry *dentry, struct inode *inode, + const char *name, void *value, size_t size) + { ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + return fuse_getxattr(inode, name, value, size); + } + +@@ -186,6 +192,9 @@ static int fuse_xattr_set(const struct x + const char *name, const void *value, size_t size, + int flags) + { ++ if (fuse_is_bad(inode)) ++ return -EIO; ++ + if (!value) + return fuse_removexattr(inode, name); + diff --git a/queue-4.19/fuse-fix-live-lock-in-fuse_iget.patch b/queue-4.19/fuse-fix-live-lock-in-fuse_iget.patch new file mode 100644 index 00000000000..275dbc1bf77 --- /dev/null +++ b/queue-4.19/fuse-fix-live-lock-in-fuse_iget.patch @@ -0,0 +1,53 @@ +From 775c5033a0d164622d9d10dd0f0a5531639ed3ed Mon Sep 17 00:00:00 2001 +From: Amir Goldstein +Date: Thu, 4 Mar 2021 11:09:12 +0200 +Subject: fuse: fix live lock in fuse_iget() + +From: Amir Goldstein + +commit 775c5033a0d164622d9d10dd0f0a5531639ed3ed upstream. + +Commit 5d069dbe8aaf ("fuse: fix bad inode") replaced make_bad_inode() +in fuse_iget() with a private implementation fuse_make_bad(). + +The private implementation fails to remove the bad inode from inode +cache, so the retry loop with iget5_locked() finds the same bad inode +and marks it bad forever. + +kmsg snip: + +[ ] rcu: INFO: rcu_sched self-detected stall on CPU +... +[ ] ? bit_wait_io+0x50/0x50 +[ ] ? fuse_init_file_inode+0x70/0x70 +[ ] ? find_inode.isra.32+0x60/0xb0 +[ ] ? fuse_init_file_inode+0x70/0x70 +[ ] ilookup5_nowait+0x65/0x90 +[ ] ? fuse_init_file_inode+0x70/0x70 +[ ] ilookup5.part.36+0x2e/0x80 +[ ] ? fuse_init_file_inode+0x70/0x70 +[ ] ? fuse_inode_eq+0x20/0x20 +[ ] iget5_locked+0x21/0x80 +[ ] ? fuse_inode_eq+0x20/0x20 +[ ] fuse_iget+0x96/0x1b0 + +Fixes: 5d069dbe8aaf ("fuse: fix bad inode") +Cc: stable@vger.kernel.org # 5.10+ +Signed-off-by: Amir Goldstein +Signed-off-by: Miklos Szeredi +Signed-off-by: Samuel Mendoza-Jonas +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/fuse_i.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/fuse/fuse_i.h ++++ b/fs/fuse/fuse_i.h +@@ -704,6 +704,7 @@ static inline u64 get_node_id(struct ino + + static inline void fuse_make_bad(struct inode *inode) + { ++ remove_inode_hash(inode); + set_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state); + } + diff --git a/queue-4.19/regulator-core-let-boot-on-regulators-be-powered-off.patch b/queue-4.19/regulator-core-let-boot-on-regulators-be-powered-off.patch new file mode 100644 index 00000000000..f5a328d05e8 --- /dev/null +++ b/queue-4.19/regulator-core-let-boot-on-regulators-be-powered-off.patch @@ -0,0 +1,39 @@ +From 089b3f61ecfc43ca4ea26d595e1d31ead6de3f7b Mon Sep 17 00:00:00 2001 +From: Pascal Paillet +Date: Wed, 13 Nov 2019 11:27:37 +0100 +Subject: regulator: core: Let boot-on regulators be powered off + +From: Pascal Paillet + +commit 089b3f61ecfc43ca4ea26d595e1d31ead6de3f7b upstream. + +Boot-on regulators are always kept on because their use_count value +is now incremented at boot time and never cleaned. + +Only increment count value for alway-on regulators. +regulator_late_cleanup() is now able to power off boot-on regulators +when unused. + +Fixes: 05f224ca6693 ("regulator: core: Clean enabling always-on regulators + their supplies") +Signed-off-by: Pascal Paillet +Link: https://lore.kernel.org/r/20191113102737.27831-1-p.paillet@st.com +Signed-off-by: Mark Brown +Acked-by: Andre Kalb +Signed-off-by: Greg Kroah-Hartman +--- + drivers/regulator/core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1211,7 +1211,9 @@ static int set_machine_constraints(struc + rdev_err(rdev, "failed to enable\n"); + return ret; + } +- rdev->use_count++; ++ ++ if (rdev->constraints->always_on) ++ rdev->use_count++; + } + + print_constraints(rdev); diff --git a/queue-4.19/series b/queue-4.19/series index a49d655e8e4..9e67aba428c 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -204,3 +204,8 @@ ext4-make-sure-quota-gets-properly-shutdown-on-error.patch ext4-set-csum-seed-in-tmp-inode-while-migrating-to-extents.patch ext4-fix-bug_on-in-ext4_bread-when-write-quota-data.patch ext4-don-t-use-the-orphan-list-when-migrating-an-inode.patch +crypto-stm32-crc32-fix-kernel-bug-triggered-in-probe.patch +asoc-dpcm-prevent-snd_soc_dpcm-use-after-free.patch +regulator-core-let-boot-on-regulators-be-powered-off.patch +fuse-fix-bad-inode.patch +fuse-fix-live-lock-in-fuse_iget.patch