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@vger.kernel.org Signed-off-by: Shao Mingyin --- 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,