From: Greg Kroah-Hartman Date: Sat, 6 May 2023 07:00:09 +0000 (+0900) Subject: 5.4-stable patches X-Git-Tag: v5.15.111~111 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=929fe1bccaa2b1f08eaddaee4a7068a46665db40;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: revert-ubifs-dirty_cow_znode-fix-memleak-in-error-handling-path.patch ubi-fix-return-value-overwrite-issue-in-try_write_vid_and_data.patch ubifs-fix-memleak-when-insert_old_idx-failed.patch ubifs-free-memory-for-tmpfile-name.patch --- diff --git a/queue-5.4/revert-ubifs-dirty_cow_znode-fix-memleak-in-error-handling-path.patch b/queue-5.4/revert-ubifs-dirty_cow_znode-fix-memleak-in-error-handling-path.patch new file mode 100644 index 00000000000..c83244d4ac9 --- /dev/null +++ b/queue-5.4/revert-ubifs-dirty_cow_znode-fix-memleak-in-error-handling-path.patch @@ -0,0 +1,47 @@ +From 7d01cb27f6aebc54efbe28d8961a973b8f795b13 Mon Sep 17 00:00:00 2001 +From: Zhihao Cheng +Date: Wed, 1 Mar 2023 20:29:18 +0800 +Subject: Revert "ubifs: dirty_cow_znode: Fix memleak in error handling path" + +From: Zhihao Cheng + +commit 7d01cb27f6aebc54efbe28d8961a973b8f795b13 upstream. + +This reverts commit 122deabfe1428 (ubifs: dirty_cow_znode: Fix memleak +in error handling path). +After commit 122deabfe1428 applied, if insert_old_idx() failed, old +index neither exists in TNC nor in old-index tree. Which means that +old index node could be overwritten in layout_leb_in_gaps(), then +ubifs image will be corrupted in power-cut. + +Fixes: 122deabfe1428 (ubifs: dirty_cow_znode: Fix memleak ... path) +Cc: stable@vger.kernel.org +Signed-off-by: Zhihao Cheng +Signed-off-by: Richard Weinberger +Signed-off-by: Greg Kroah-Hartman +--- + fs/ubifs/tnc.c | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +--- a/fs/ubifs/tnc.c ++++ b/fs/ubifs/tnc.c +@@ -267,18 +267,11 @@ static struct ubifs_znode *dirty_cow_zno + if (zbr->len) { + err = insert_old_idx(c, zbr->lnum, zbr->offs); + if (unlikely(err)) +- /* +- * Obsolete znodes will be freed by tnc_destroy_cnext() +- * or free_obsolete_znodes(), copied up znodes should +- * be added back to tnc and freed by +- * ubifs_destroy_tnc_subtree(). +- */ +- goto out; ++ return ERR_PTR(err); + err = add_idx_dirt(c, zbr->lnum, zbr->len); + } else + err = 0; + +-out: + zbr->znode = zn; + zbr->lnum = 0; + zbr->offs = 0; diff --git a/queue-5.4/series b/queue-5.4/series index ae1dd6460de..a3d89ab4e01 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -26,3 +26,7 @@ crypto-safexcel-cleanup-ring-irq-workqueues-on-load-failure.patch reiserfs-add-security-prefix-to-xattr-name-in-reiserfs_security_write.patch kvm-nvmx-emulate-nops-in-l2-and-pause-if-it-s-not-intercepted.patch i2c-omap-fix-standard-mode-false-ack-readings.patch +revert-ubifs-dirty_cow_znode-fix-memleak-in-error-handling-path.patch +ubifs-fix-memleak-when-insert_old_idx-failed.patch +ubi-fix-return-value-overwrite-issue-in-try_write_vid_and_data.patch +ubifs-free-memory-for-tmpfile-name.patch diff --git a/queue-5.4/ubi-fix-return-value-overwrite-issue-in-try_write_vid_and_data.patch b/queue-5.4/ubi-fix-return-value-overwrite-issue-in-try_write_vid_and_data.patch new file mode 100644 index 00000000000..9f4b41a5301 --- /dev/null +++ b/queue-5.4/ubi-fix-return-value-overwrite-issue-in-try_write_vid_and_data.patch @@ -0,0 +1,63 @@ +From 31a149d5c13c4cbcf97de3435817263a2d8c9d6e Mon Sep 17 00:00:00 2001 +From: Wang YanQing +Date: Tue, 28 Mar 2023 23:35:34 +0800 +Subject: ubi: Fix return value overwrite issue in try_write_vid_and_data() + +From: Wang YanQing + +commit 31a149d5c13c4cbcf97de3435817263a2d8c9d6e upstream. + +The commit 2d78aee426d8 ("UBI: simplify LEB write and atomic LEB change code") +adds helper function, try_write_vid_and_data(), to simplify the code, but this +helper function has bug, it will return 0 (success) when ubi_io_write_vid_hdr() +or the ubi_io_write_data() return error number (-EIO, etc), because the return +value of ubi_wl_put_peb() will overwrite the original return value. + +This issue will cause unexpected data loss issue, because the caller of this +function and UBIFS willn't know the data is lost. + +Fixes: 2d78aee426d8 ("UBI: simplify LEB write and atomic LEB change code") +Cc: stable@vger.kernel.org +Signed-off-by: Wang YanQing +Reviewed-by: Zhihao Cheng +Signed-off-by: Richard Weinberger +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/ubi/eba.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +--- a/drivers/mtd/ubi/eba.c ++++ b/drivers/mtd/ubi/eba.c +@@ -947,7 +947,7 @@ static int try_write_vid_and_data(struct + int offset, int len) + { + struct ubi_device *ubi = vol->ubi; +- int pnum, opnum, err, vol_id = vol->vol_id; ++ int pnum, opnum, err, err2, vol_id = vol->vol_id; + + pnum = ubi_wl_get_peb(ubi); + if (pnum < 0) { +@@ -982,10 +982,19 @@ static int try_write_vid_and_data(struct + out_put: + up_read(&ubi->fm_eba_sem); + +- if (err && pnum >= 0) +- err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); +- else if (!err && opnum >= 0) +- err = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0); ++ if (err && pnum >= 0) { ++ err2 = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); ++ if (err2) { ++ ubi_warn(ubi, "failed to return physical eraseblock %d, error %d", ++ pnum, err2); ++ } ++ } else if (!err && opnum >= 0) { ++ err2 = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0); ++ if (err2) { ++ ubi_warn(ubi, "failed to return physical eraseblock %d, error %d", ++ opnum, err2); ++ } ++ } + + return err; + } diff --git a/queue-5.4/ubifs-fix-memleak-when-insert_old_idx-failed.patch b/queue-5.4/ubifs-fix-memleak-when-insert_old_idx-failed.patch new file mode 100644 index 00000000000..e0e29c3f3e8 --- /dev/null +++ b/queue-5.4/ubifs-fix-memleak-when-insert_old_idx-failed.patch @@ -0,0 +1,222 @@ +From b5fda08ef213352ac2df7447611eb4d383cce929 Mon Sep 17 00:00:00 2001 +From: Zhihao Cheng +Date: Wed, 1 Mar 2023 20:29:19 +0800 +Subject: ubifs: Fix memleak when insert_old_idx() failed + +From: Zhihao Cheng + +commit b5fda08ef213352ac2df7447611eb4d383cce929 upstream. + +Following process will cause a memleak for copied up znode: + +dirty_cow_znode + zn = copy_znode(c, znode); + err = insert_old_idx(c, zbr->lnum, zbr->offs); + if (unlikely(err)) + return ERR_PTR(err); // No one refers to zn. + +Fetch a reproducer in [Link]. + +Function copy_znode() is split into 2 parts: resource allocation +and znode replacement, insert_old_idx() is split in similar way, +so resource cleanup could be done in error handling path without +corrupting metadata(mem & disk). +It's okay that old index inserting is put behind of add_idx_dirt(), +old index is used in layout_leb_in_gaps(), so the two processes do +not depend on each other. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=216705 +Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") +Cc: stable@vger.kernel.org +Signed-off-by: Zhihao Cheng +Signed-off-by: Richard Weinberger +Signed-off-by: Greg Kroah-Hartman +--- + fs/ubifs/tnc.c | 137 ++++++++++++++++++++++++++++++++++++--------------------- + 1 file changed, 87 insertions(+), 50 deletions(-) + +--- a/fs/ubifs/tnc.c ++++ b/fs/ubifs/tnc.c +@@ -44,6 +44,33 @@ enum { + NOT_ON_MEDIA = 3, + }; + ++static void do_insert_old_idx(struct ubifs_info *c, ++ struct ubifs_old_idx *old_idx) ++{ ++ struct ubifs_old_idx *o; ++ struct rb_node **p, *parent = NULL; ++ ++ p = &c->old_idx.rb_node; ++ while (*p) { ++ parent = *p; ++ o = rb_entry(parent, struct ubifs_old_idx, rb); ++ if (old_idx->lnum < o->lnum) ++ p = &(*p)->rb_left; ++ else if (old_idx->lnum > o->lnum) ++ p = &(*p)->rb_right; ++ else if (old_idx->offs < o->offs) ++ p = &(*p)->rb_left; ++ else if (old_idx->offs > o->offs) ++ p = &(*p)->rb_right; ++ else { ++ ubifs_err(c, "old idx added twice!"); ++ kfree(old_idx); ++ } ++ } ++ rb_link_node(&old_idx->rb, parent, p); ++ rb_insert_color(&old_idx->rb, &c->old_idx); ++} ++ + /** + * insert_old_idx - record an index node obsoleted since the last commit start. + * @c: UBIFS file-system description object +@@ -69,35 +96,15 @@ enum { + */ + static int insert_old_idx(struct ubifs_info *c, int lnum, int offs) + { +- struct ubifs_old_idx *old_idx, *o; +- struct rb_node **p, *parent = NULL; ++ struct ubifs_old_idx *old_idx; + + old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS); + if (unlikely(!old_idx)) + return -ENOMEM; + old_idx->lnum = lnum; + old_idx->offs = offs; ++ do_insert_old_idx(c, old_idx); + +- p = &c->old_idx.rb_node; +- while (*p) { +- parent = *p; +- o = rb_entry(parent, struct ubifs_old_idx, rb); +- if (lnum < o->lnum) +- p = &(*p)->rb_left; +- else if (lnum > o->lnum) +- p = &(*p)->rb_right; +- else if (offs < o->offs) +- p = &(*p)->rb_left; +- else if (offs > o->offs) +- p = &(*p)->rb_right; +- else { +- ubifs_err(c, "old idx added twice!"); +- kfree(old_idx); +- return 0; +- } +- } +- rb_link_node(&old_idx->rb, parent, p); +- rb_insert_color(&old_idx->rb, &c->old_idx); + return 0; + } + +@@ -199,23 +206,6 @@ static struct ubifs_znode *copy_znode(st + __set_bit(DIRTY_ZNODE, &zn->flags); + __clear_bit(COW_ZNODE, &zn->flags); + +- ubifs_assert(c, !ubifs_zn_obsolete(znode)); +- __set_bit(OBSOLETE_ZNODE, &znode->flags); +- +- if (znode->level != 0) { +- int i; +- const int n = zn->child_cnt; +- +- /* The children now have new parent */ +- for (i = 0; i < n; i++) { +- struct ubifs_zbranch *zbr = &zn->zbranch[i]; +- +- if (zbr->znode) +- zbr->znode->parent = zn; +- } +- } +- +- atomic_long_inc(&c->dirty_zn_cnt); + return zn; + } + +@@ -234,6 +224,42 @@ static int add_idx_dirt(struct ubifs_inf + } + + /** ++ * replace_znode - replace old znode with new znode. ++ * @c: UBIFS file-system description object ++ * @new_zn: new znode ++ * @old_zn: old znode ++ * @zbr: the branch of parent znode ++ * ++ * Replace old znode with new znode in TNC. ++ */ ++static void replace_znode(struct ubifs_info *c, struct ubifs_znode *new_zn, ++ struct ubifs_znode *old_zn, struct ubifs_zbranch *zbr) ++{ ++ ubifs_assert(c, !ubifs_zn_obsolete(old_zn)); ++ __set_bit(OBSOLETE_ZNODE, &old_zn->flags); ++ ++ if (old_zn->level != 0) { ++ int i; ++ const int n = new_zn->child_cnt; ++ ++ /* The children now have new parent */ ++ for (i = 0; i < n; i++) { ++ struct ubifs_zbranch *child = &new_zn->zbranch[i]; ++ ++ if (child->znode) ++ child->znode->parent = new_zn; ++ } ++ } ++ ++ zbr->znode = new_zn; ++ zbr->lnum = 0; ++ zbr->offs = 0; ++ zbr->len = 0; ++ ++ atomic_long_inc(&c->dirty_zn_cnt); ++} ++ ++/** + * dirty_cow_znode - ensure a znode is not being committed. + * @c: UBIFS file-system description object + * @zbr: branch of znode to check +@@ -265,21 +291,32 @@ static struct ubifs_znode *dirty_cow_zno + return zn; + + if (zbr->len) { +- err = insert_old_idx(c, zbr->lnum, zbr->offs); +- if (unlikely(err)) +- return ERR_PTR(err); ++ struct ubifs_old_idx *old_idx; ++ ++ old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS); ++ if (unlikely(!old_idx)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ old_idx->lnum = zbr->lnum; ++ old_idx->offs = zbr->offs; ++ + err = add_idx_dirt(c, zbr->lnum, zbr->len); +- } else +- err = 0; ++ if (err) { ++ kfree(old_idx); ++ goto out; ++ } + +- zbr->znode = zn; +- zbr->lnum = 0; +- zbr->offs = 0; +- zbr->len = 0; ++ do_insert_old_idx(c, old_idx); ++ } ++ ++ replace_znode(c, zn, znode, zbr); + +- if (unlikely(err)) +- return ERR_PTR(err); + return zn; ++ ++out: ++ kfree(zn); ++ return ERR_PTR(err); + } + + /** diff --git a/queue-5.4/ubifs-free-memory-for-tmpfile-name.patch b/queue-5.4/ubifs-free-memory-for-tmpfile-name.patch new file mode 100644 index 00000000000..0bc8d468e9e --- /dev/null +++ b/queue-5.4/ubifs-free-memory-for-tmpfile-name.patch @@ -0,0 +1,52 @@ +From 1fb815b38bb31d6af9bd0540b8652a0d6fe6cfd3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?M=C3=A5rten=20Lindahl?= +Date: Thu, 30 Mar 2023 11:32:14 +0200 +Subject: ubifs: Free memory for tmpfile name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: MÃ¥rten Lindahl + +commit 1fb815b38bb31d6af9bd0540b8652a0d6fe6cfd3 upstream. + +When opening a ubifs tmpfile on an encrypted directory, function +fscrypt_setup_filename allocates memory for the name that is to be +stored in the directory entry, but after the name has been copied to the +directory entry inode, the memory is not freed. + +When running kmemleak on it we see that it is registered as a leak. The +report below is triggered by a simple program 'tmpfile' just opening a +tmpfile: + + unreferenced object 0xffff88810178f380 (size 32): + comm "tmpfile", pid 509, jiffies 4294934744 (age 1524.742s) + backtrace: + __kmem_cache_alloc_node + __kmalloc + fscrypt_setup_filename + ubifs_tmpfile + vfs_tmpfile + path_openat + +Free this memory after it has been copied to the inode. + +Signed-off-by: MÃ¥rten Lindahl +Reviewed-by: Zhihao Cheng +Cc: stable@vger.kernel.org +Signed-off-by: Richard Weinberger +Signed-off-by: Greg Kroah-Hartman +--- + fs/ubifs/dir.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ubifs/dir.c ++++ b/fs/ubifs/dir.c +@@ -433,6 +433,7 @@ static int do_tmpfile(struct inode *dir, + mutex_unlock(&dir_ui->ui_mutex); + + ubifs_release_budget(c, &req); ++ fscrypt_free_filename(&nm); + + return 0; +