]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 6 May 2023 07:00:07 +0000 (16:00 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 6 May 2023 07:00:07 +0000 (16:00 +0900)
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

queue-4.19/revert-ubifs-dirty_cow_znode-fix-memleak-in-error-handling-path.patch [new file with mode: 0644]
queue-4.19/series
queue-4.19/ubi-fix-return-value-overwrite-issue-in-try_write_vid_and_data.patch [new file with mode: 0644]
queue-4.19/ubifs-fix-memleak-when-insert_old_idx-failed.patch [new file with mode: 0644]
queue-4.19/ubifs-free-memory-for-tmpfile-name.patch [new file with mode: 0644]

diff --git a/queue-4.19/revert-ubifs-dirty_cow_znode-fix-memleak-in-error-handling-path.patch b/queue-4.19/revert-ubifs-dirty_cow_znode-fix-memleak-in-error-handling-path.patch
new file mode 100644 (file)
index 0000000..e4ee341
--- /dev/null
@@ -0,0 +1,47 @@
+From 7d01cb27f6aebc54efbe28d8961a973b8f795b13 Mon Sep 17 00:00:00 2001
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+Date: Wed, 1 Mar 2023 20:29:18 +0800
+Subject: Revert "ubifs: dirty_cow_znode: Fix memleak in error handling path"
+
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+
+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 <chengzhihao1@huawei.com>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ubifs/tnc.c |    9 +--------
+ 1 file changed, 1 insertion(+), 8 deletions(-)
+
+--- a/fs/ubifs/tnc.c
++++ b/fs/ubifs/tnc.c
+@@ -279,18 +279,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;
index 52c33f6e5a0ca6ea49a2f9784063c7608becaf1a..5f4a4562b99605f0183450f1aeb127415a4d1dba 100644 (file)
@@ -17,3 +17,7 @@ crypto-api-demote-bug_on-in-crypto_unregister_alg-to-a-warn_on.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-4.19/ubi-fix-return-value-overwrite-issue-in-try_write_vid_and_data.patch b/queue-4.19/ubi-fix-return-value-overwrite-issue-in-try_write_vid_and_data.patch
new file mode 100644 (file)
index 0000000..cc8e292
--- /dev/null
@@ -0,0 +1,63 @@
+From 31a149d5c13c4cbcf97de3435817263a2d8c9d6e Mon Sep 17 00:00:00 2001
+From: Wang YanQing <udknight@gmail.com>
+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 <udknight@gmail.com>
+
+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 <udknight@gmail.com>
+Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -960,7 +960,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) {
+@@ -995,10 +995,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-4.19/ubifs-fix-memleak-when-insert_old_idx-failed.patch b/queue-4.19/ubifs-fix-memleak-when-insert_old_idx-failed.patch
new file mode 100644 (file)
index 0000000..df674b0
--- /dev/null
@@ -0,0 +1,222 @@
+From b5fda08ef213352ac2df7447611eb4d383cce929 Mon Sep 17 00:00:00 2001
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+Date: Wed, 1 Mar 2023 20:29:19 +0800
+Subject: ubifs: Fix memleak when insert_old_idx() failed
+
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+
+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 <chengzhihao1@huawei.com>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ubifs/tnc.c |  137 ++++++++++++++++++++++++++++++++++++---------------------
+ 1 file changed, 87 insertions(+), 50 deletions(-)
+
+--- a/fs/ubifs/tnc.c
++++ b/fs/ubifs/tnc.c
+@@ -56,6 +56,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
+@@ -81,35 +108,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;
+ }
+@@ -211,23 +218,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;
+ }
+@@ -246,6 +236,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
+@@ -277,21 +303,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-4.19/ubifs-free-memory-for-tmpfile-name.patch b/queue-4.19/ubifs-free-memory-for-tmpfile-name.patch
new file mode 100644 (file)
index 0000000..7ab534b
--- /dev/null
@@ -0,0 +1,52 @@
+From 1fb815b38bb31d6af9bd0540b8652a0d6fe6cfd3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?M=C3=A5rten=20Lindahl?= <marten.lindahl@axis.com>
+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 <marten.lindahl@axis.com>
+
+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 <marten.lindahl@axis.com>
+Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ubifs/dir.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -445,6 +445,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;