[PATCH v2 1/2] xfs: reject log items with missing regions during recovery

Weiming Shi <[email protected]>
Newsgroups org.kernel.vger.linux-xfs,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Each recovered log item is assembled in xlog_recover_add_to_trans() into
an ri_buf[] of ri_total (= the format's declared region count) slots, and
the regions actually logged are counted in ri_cnt. Nothing checks that
ri_cnt reached ri_total once the transaction is complete, so a crafted or
truncated log can present an item whose format declares more regions than
were logged. The trailing ri_buf[] slots are then NULL, and the reorder,
readahead and replay code dereference them.

For example, an XFS_LI_INODE item declaring two regions but logging only
the format region leaves ri_buf[1] NULL, and mount-time recovery faults
dereferencing it as the log dinode:

 KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
 RIP: xlog_recover_inode_commit_pass2 (fs/xfs/xfs_inode_item_recover.c:370)
 Call Trace:
  xlog_recover_items_pass2 (fs/xfs/xfs_log_recover.c:2011)
  xlog_recover_commit_trans (fs/xfs/xfs_log_recover.c:2078)
  xlog_recovery_process_trans (fs/xfs/xfs_log_recover.c:2328)
  xlog_recover_process_data (fs/xfs/xfs_log_recover.c:2502)
  xlog_recover (fs/xfs/xfs_log_recover.c:3486)
  xfs_log_mount (fs/xfs/xfs_log.c:667)
  xfs_mountfs (fs/xfs/xfs_mount.c:1039)
  xfs_fs_fill_super (fs/xfs/xfs_super.c:1965)
  get_tree_bdev_flags (fs/super.c:1680)
  __x64_sys_mount (fs/namespace.c:4433)

Whether an item logged all its declared regions is a generic log format
property, not a per-item-type concern, so reject any item with a missing
region in xlog_recover_commit_trans() before the item ops run.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Xiang Mei <[email protected]>
Suggested-by: Dave Chinner <[email protected]>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Weiming Shi <[email protected]>
---
 fs/xfs/xfs_log_recover.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 09e6678ca487..5250d512a392 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -2039,6 +2039,17 @@ xlog_recover_commit_trans(
 
 	hlist_del_init(&trans->r_list);
 
+	/*
+	 * Reject an item missing a region its format declared; the NULL slot
+	 * would be dereferenced by the reorder and replay code.
+	 */
+	list_for_each_entry(item, &trans->r_itemq, ri_list) {
+		if (XFS_IS_CORRUPT(log->l_mp,
+				   item->ri_total == 0 ||
+				   item->ri_cnt != item->ri_total))
+			return -EFSCORRUPTED;
+	}
+
 	error = xlog_recover_reorder_trans(log, trans, pass);
 	if (error)
 		return error;
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.