[PATCH v2 4/5] ubifs: validate inode and data node sizes during replay

From: shao.mingyin

Date: Tue Nov 03 2026 - 01:27:50 EST


replay_bud() trusts the size fields of inode and data nodes from the
journal. An image that is corrupt but has a matching CRC can therefore
carry an inode node with a negative or too large size, or a data node
with a size outside 1..UBIFS_BLOCK_SIZE. During recovery
ubifs_recover_size_accum() uses these values and ubifs_recover_size()
may extend the inode to the bogus size.

The normal read paths already reject such nodes (read_block(),
populate_page()) and truncation nodes are validated in replay_bud() as
well. Do the same for inode and data nodes. While at it, compute the
data node end offset with 64-bit arithmetic so that a large block
number cannot wrap.

Fixes: 1e51764a3c2a ("UBIFS: add new flash file system")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
---
v2: no change since v1.

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 263045e05cf1..14cd5598ca0b 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -741,6 +741,12 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
struct ubifs_ino_node *ino = snod->node;
loff_t new_size = le64_to_cpu(ino->size);

+ /* Validate inode node */
+ if (new_size < 0 || new_size > c->max_inode_sz) {
+ ubifs_err(c, "bad inode node");
+ goto out_dump;
+ }
+
if (le32_to_cpu(ino->nlink) == 0)
deletion = 1;
err = insert_node(c, lnum, snod->offs, snod->len, hash,
@@ -751,9 +757,21 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
case UBIFS_DATA_NODE:
{
struct ubifs_data_node *dn = snod->node;
- loff_t new_size = le32_to_cpu(dn->size) +
- key_block(c, &snod->key) *
- UBIFS_BLOCK_SIZE;
+ u32 dsize = le32_to_cpu(dn->size);
+ loff_t new_size;
+
+ /* Validate data node */
+ if (!dsize || dsize > UBIFS_BLOCK_SIZE) {
+ ubifs_err(c, "bad data node");
+ goto out_dump;
+ }
+
+ new_size = (loff_t)key_block(c, &snod->key) *
+ UBIFS_BLOCK_SIZE + dsize;
+ if (new_size > c->max_inode_sz) {
+ ubifs_err(c, "bad data node");
+ goto out_dump;
+ }

err = insert_node(c, lnum, snod->offs, snod->len, hash,
&snod->key, snod->sqnum, deletion,