--- /dev/null
+From 3c0315424f5e3d2a4113c7272367bee1e8e6a174 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Thu, 4 Mar 2021 21:43:10 -0800
+Subject: f2fs: fix error handling in f2fs_end_enable_verity()
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit 3c0315424f5e3d2a4113c7272367bee1e8e6a174 upstream.
+
+f2fs didn't properly clean up if verity failed to be enabled on a file:
+
+- It left verity metadata (pages past EOF) in the page cache, which
+ would be exposed to userspace if the file was later extended.
+
+- It didn't truncate the verity metadata at all (either from cache or
+ from disk) if an error occurred while setting the verity bit.
+
+Fix these bugs by adding a call to truncate_inode_pages() and ensuring
+that we truncate the verity metadata (both from cache and from disk) in
+all error paths. Also rework the code to cleanly separate the success
+path from the error paths, which makes it much easier to understand.
+
+Finally, log a message if f2fs_truncate() fails, since it might
+otherwise fail silently.
+
+Reported-by: Yunlei He <heyunlei@hihonor.com>
+Fixes: 95ae251fe828 ("f2fs: add fs-verity support")
+Cc: <stable@vger.kernel.org> # v5.4+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/verity.c | 79 ++++++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 56 insertions(+), 23 deletions(-)
+
+--- a/fs/f2fs/verity.c
++++ b/fs/f2fs/verity.c
+@@ -150,40 +150,73 @@ static int f2fs_end_enable_verity(struct
+ size_t desc_size, u64 merkle_tree_size)
+ {
+ struct inode *inode = file_inode(filp);
++ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ u64 desc_pos = f2fs_verity_metadata_pos(inode) + merkle_tree_size;
+ struct fsverity_descriptor_location dloc = {
+ .version = cpu_to_le32(1),
+ .size = cpu_to_le32(desc_size),
+ .pos = cpu_to_le64(desc_pos),
+ };
+- int err = 0;
++ int err = 0, err2 = 0;
+
+- if (desc != NULL) {
+- /* Succeeded; write the verity descriptor. */
+- err = pagecache_write(inode, desc, desc_size, desc_pos);
+-
+- /* Write all pages before clearing FI_VERITY_IN_PROGRESS. */
+- if (!err)
+- err = filemap_write_and_wait(inode->i_mapping);
+- }
+-
+- /* If we failed, truncate anything we wrote past i_size. */
+- if (desc == NULL || err)
+- f2fs_truncate(inode);
++ /*
++ * If an error already occurred (which fs/verity/ signals by passing
++ * desc == NULL), then only clean-up is needed.
++ */
++ if (desc == NULL)
++ goto cleanup;
++
++ /* Append the verity descriptor. */
++ err = pagecache_write(inode, desc, desc_size, desc_pos);
++ if (err)
++ goto cleanup;
++
++ /*
++ * Write all pages (both data and verity metadata). Note that this must
++ * happen before clearing FI_VERITY_IN_PROGRESS; otherwise pages beyond
++ * i_size won't be written properly. For crash consistency, this also
++ * must happen before the verity inode flag gets persisted.
++ */
++ err = filemap_write_and_wait(inode->i_mapping);
++ if (err)
++ goto cleanup;
++
++ /* Set the verity xattr. */
++ err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_VERITY,
++ F2FS_XATTR_NAME_VERITY, &dloc, sizeof(dloc),
++ NULL, XATTR_CREATE);
++ if (err)
++ goto cleanup;
++
++ /* Finally, set the verity inode flag. */
++ file_set_verity(inode);
++ f2fs_set_inode_flags(inode);
++ f2fs_mark_inode_dirty_sync(inode, true);
+
+ clear_inode_flag(inode, FI_VERITY_IN_PROGRESS);
++ return 0;
+
+- if (desc != NULL && !err) {
+- err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_VERITY,
+- F2FS_XATTR_NAME_VERITY, &dloc, sizeof(dloc),
+- NULL, XATTR_CREATE);
+- if (!err) {
+- file_set_verity(inode);
+- f2fs_set_inode_flags(inode);
+- f2fs_mark_inode_dirty_sync(inode, true);
+- }
++cleanup:
++ /*
++ * Verity failed to be enabled, so clean up by truncating any verity
++ * metadata that was written beyond i_size (both from cache and from
++ * disk) and clearing FI_VERITY_IN_PROGRESS.
++ *
++ * Taking i_gc_rwsem[WRITE] is needed to stop f2fs garbage collection
++ * from re-instantiating cached pages we are truncating (since unlike
++ * normal file accesses, garbage collection isn't limited by i_size).
++ */
++ down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
++ truncate_inode_pages(inode->i_mapping, inode->i_size);
++ err2 = f2fs_truncate(inode);
++ if (err2) {
++ f2fs_err(sbi, "Truncating verity metadata failed (errno=%d)",
++ err2);
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ }
+- return err;
++ up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
++ clear_inode_flag(inode, FI_VERITY_IN_PROGRESS);
++ return err ?: err2;
+ }
+
+ static int f2fs_get_verity_descriptor(struct inode *inode, void *buf,