From 561ae28cb56a082cfa90c1c421c4955bc215470b Mon Sep 17 00:00:00 2001 From: Shahriyar Jalayeri Date: Tue, 28 Jul 2026 08:55:39 +0200 Subject: fs/squashfs: fix integer overflow in directory table allocation sqfs_read_directory_table() allocates the directory table with malloc(metablks_count * SQFS_METADATA_BLOCK_SIZE). metablks_count is an int and SQFS_METADATA_BLOCK_SIZE is 8192, so the multiply is evaluated in int and wraps for metablks_count >= 2^19. metablks_count comes from the attacker-controlled superblock (sqfs_count_metablks() grows it by one per 2-byte metadata header), so a crafted image under-allocates the buffer while the fill loop still writes metablks_count metadata blocks into it, a heap out-of-bounds write. It is reached by listing or reading the image (sqfsls / sqfsload). The position list allocation on the next line has the same unchecked-multiply shape. Size both allocations with __builtin_mul_overflow() and reject the image on overflow, as the disk-read buffers earlier in the same function already do. Set the error return when either allocation fails so the caller does not proceed with a NULL directory table. Fixes: c51006130370 ("fs/squashfs: new filesystem") Signed-off-by: Shahriyar Jalayeri Reviewed-by: Richard Genoud --- fs/squashfs/sqfs.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/fs/squashfs/sqfs.c b/fs/squashfs/sqfs.c index 0768fc4a7b2..3aadcdd36ec 100644 --- a/fs/squashfs/sqfs.c +++ b/fs/squashfs/sqfs.c @@ -852,13 +852,28 @@ static int sqfs_read_directory_table(unsigned char **dir_table, u32 **pos_list) if (metablks_count < 1) goto out; - *dir_table = malloc(metablks_count * SQFS_METADATA_BLOCK_SIZE); - if (!*dir_table) + if (__builtin_mul_overflow(metablks_count, SQFS_METADATA_BLOCK_SIZE, + &buf_size)) { + metablks_count = -1; + goto out; + } + + *dir_table = malloc(buf_size); + if (!*dir_table) { + metablks_count = -1; + goto out; + } + + if (__builtin_mul_overflow(metablks_count, sizeof(u32), &buf_size)) { + metablks_count = -1; goto out; + } - *pos_list = malloc(metablks_count * sizeof(u32)); - if (!*pos_list) + *pos_list = malloc(buf_size); + if (!*pos_list) { + metablks_count = -1; goto out; + } ret = sqfs_get_metablk_pos(*pos_list, dtb, table_offset, metablks_count); -- cgit v1.3.1 From 4750bcfe857c5a0feda86b54f260a11a4e3222cd Mon Sep 17 00:00:00 2001 From: Shahriyar Jalayeri Date: Tue, 28 Jul 2026 08:55:40 +0200 Subject: test: squashfs: add directory table overflow regression test Add a Python test that lists a crafted SquashFS image whose directory table declares an oversized metadata-block count. Such an image must be rejected without corrupting the heap, which the test checks by confirming U-Boot is still responsive afterwards. Signed-off-by: Shahriyar Jalayeri Reviewed-by: Richard Genoud --- .../test_fs/test_squashfs/test_sqfs_overflow.py | 75 ++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 test/py/tests/test_fs/test_squashfs/test_sqfs_overflow.py diff --git a/test/py/tests/test_fs/test_squashfs/test_sqfs_overflow.py b/test/py/tests/test_fs/test_squashfs/test_sqfs_overflow.py new file mode 100644 index 00000000000..df7f875a58f --- /dev/null +++ b/test/py/tests/test_fs/test_squashfs/test_sqfs_overflow.py @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0 +# Regression test for the SquashFS directory-table integer overflow. + +import os +import struct +import pytest + +# metadata block size (SQFS_METADATA_BLOCK_SIZE) and metadata header size +SQFS_METADATA_BLOCK_SIZE = 8192 +# metablks_count that makes metablks_count * SQFS_METADATA_BLOCK_SIZE wrap a +# 32-bit int back down to a tiny value: (2^19 + 1) * 8192 == 2^32 + 8192. +NR_METABLKS = (1 << 19) + 1 + +def make_overflow_image(path): + """Build a SquashFS image whose directory table inflates metablks_count so + that metablks_count * SQFS_METADATA_BLOCK_SIZE wraps a 32-bit int, then + writes one block of data one metadata block past the resulting buffer.""" + def metahdr(size): + # uncompressed metadata block header (bit 15 set) + return struct.pack('