[PATCH 2/4] ocfs2: validate suballoc bit during inode read

From: Joseph Qi

Date: Mon Aug 31 2026 - 02:29:15 EST


i_suballoc_bit of a dinode is currently not validated at all. A
corrupted dinode can carry an abnormally large i_suballoc_bit, which
bypasses ocfs2_validate_inode_block(). When the inode is deleted,
ocfs2_remove_inode() calls ocfs2_free_dinode(), which passes the
unvalidated bit to _ocfs2_free_suballoc_bits() and triggers
BUG_ON((count + start_bit) > ocfs2_bits_per_group(cl)).

Since suballocator block group bitmaps are contained in a single
block, a valid suballoc bit must be smaller than the number of bits
per block. Reject oversized i_suballoc_bit values during dinode
validation.

Signed-off-by: Joseph Qi <joseph.qi@xxxxxxxxxxxxxxxxx>
---
fs/ocfs2/inode.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index eda50f13ffb5..a982c99a9678 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1543,6 +1543,20 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}

+ /*
+ * A suballocator block group bitmap is contained in a single block,
+ * so a valid suballoc bit can never exceed the number of bits per
+ * block. Otherwise deleting the inode will pass the oversized bit
+ * to _ocfs2_free_suballoc_bits() via ocfs2_free_dinode() and trigger
+ * BUG_ON((count + start_bit) > ocfs2_bits_per_group(cl)).
+ */
+ if (le16_to_cpu(di->i_suballoc_bit) >= sb->s_blocksize * 8) {
+ rc = ocfs2_error(sb, "Invalid dinode %llu: suballoc bit %u\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(di->i_suballoc_bit));
+ goto bail;
+ }
+
if ((le32_to_cpu(di->i_flags) & OCFS2_ORPHANED_FL) &&
le16_to_cpu(di->i_orphaned_slot) >= OCFS2_SB(sb)->max_slots) {
rc = ocfs2_error(sb, "Invalid dinode %llu: orphaned slot %u\n",
--
2.39.3