From: Greg Kroah-Hartman Date: Mon, 17 May 2021 10:42:58 +0000 (+0200) Subject: 5.4-stable patches X-Git-Tag: v5.4.120~28 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=15e0aefccadd04397721c0fd75d1ece3a2254d5f;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: f2fs-fix-error-handling-in-f2fs_end_enable_verity.patch --- diff --git a/queue-5.4/f2fs-fix-error-handling-in-f2fs_end_enable_verity.patch b/queue-5.4/f2fs-fix-error-handling-in-f2fs_end_enable_verity.patch new file mode 100644 index 00000000000..a693ca9e16a --- /dev/null +++ b/queue-5.4/f2fs-fix-error-handling-in-f2fs_end_enable_verity.patch @@ -0,0 +1,135 @@ +From 3c0315424f5e3d2a4113c7272367bee1e8e6a174 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Thu, 4 Mar 2021 21:43:10 -0800 +Subject: f2fs: fix error handling in f2fs_end_enable_verity() + +From: Eric Biggers + +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 +Fixes: 95ae251fe828 ("f2fs: add fs-verity support") +Cc: # v5.4+ +Signed-off-by: Eric Biggers +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + 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, diff --git a/queue-5.4/series b/queue-5.4/series index bcdf6809ad9..09d7accae41 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -128,3 +128,4 @@ mips-reinstate-platform-__div64_32-handler.patch mips-avoid-divu-in-__div64_32-is-result-would-be-zero.patch mips-avoid-handcoded-divu-in-__div64_32-altogether.patch thermal-core-fair-share-lock-the-thermal-zone-while-looping-over-instances.patch +f2fs-fix-error-handling-in-f2fs_end_enable_verity.patch