summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShahriyar Jalayeri <[email protected]>2026-07-28 08:55:39 +0200
committerTom Rini <[email protected]>2026-08-27 15:01:02 -0600
commit561ae28cb56a082cfa90c1c421c4955bc215470b (patch)
treea066a3d7673ecfffc564896495c730ad136b563f
parentfdfe2ec48d5c1c2ed03073d73edd3fdd3fe1ffa1 (diff)
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 <[email protected]> Reviewed-by: Richard Genoud <[email protected]>
-rw-r--r--fs/squashfs/sqfs.c23
1 files 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);