summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoao Marcos Costa <joaomarcos.costa@bootlin.com>2025-02-19 11:16:33 +0100
committerTom Rini <trini@konsulko.com>2025-02-24 08:49:04 -0600
commit59fd62d71c6a04b3ab9db848414a7c386cfd2cfb (patch)
treee30a0d341111f0eb8cae3dd52c2f18ca02bfd2a7
parent5061eab96acd60d28149e080f3a37fbe7220ca54 (diff)
fs/squashfs: fix potential integer overflows
The length of buffers used to read inode tables, directory tables, and reading a file are calculated as: number of blocks * block size, and such plain multiplication is prone to overflowing (thus unsafe). Replace it by __builtin_mul_overflow, i.e. safe math. Signed-off-by: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
-rw-r--r--fs/squashfs/sqfs.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/fs/squashfs/sqfs.c b/fs/squashfs/sqfs.c
index b9314019b1b..8fac6c6c5a9 100644
--- a/fs/squashfs/sqfs.c
+++ b/fs/squashfs/sqfs.c
@@ -719,6 +719,7 @@ static int sqfs_read_inode_table(unsigned char **inode_table)
u32 src_len, dest_offset = 0;
unsigned long dest_len = 0;
bool compressed;
+ size_t buf_size;
table_size = get_unaligned_le64(&sblk->directory_table_start) -
get_unaligned_le64(&sblk->inode_table_start);
@@ -728,7 +729,10 @@ static int sqfs_read_inode_table(unsigned char **inode_table)
sblk->directory_table_start, &table_offset);
/* Allocate a proper sized buffer (itb) to store the inode table */
- itb = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz);
+ if (__builtin_mul_overflow(n_blks, ctxt.cur_dev->blksz, &buf_size))
+ return -EINVAL;
+
+ itb = malloc_cache_aligned(buf_size);
if (!itb)
return -ENOMEM;
@@ -806,6 +810,7 @@ static int sqfs_read_directory_table(unsigned char **dir_table, u32 **pos_list)
u32 src_len, dest_offset = 0;
unsigned long dest_len = 0;
bool compressed;
+ size_t buf_size;
*dir_table = NULL;
*pos_list = NULL;
@@ -818,7 +823,10 @@ static int sqfs_read_directory_table(unsigned char **dir_table, u32 **pos_list)
sblk->fragment_table_start, &table_offset);
/* Allocate a proper sized buffer (dtb) to store the directory table */
- dtb = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz);
+ if (__builtin_mul_overflow(n_blks, ctxt.cur_dev->blksz, &buf_size))
+ return -EINVAL;
+
+ dtb = malloc_cache_aligned(buf_size);
if (!dtb)
return -ENOMEM;
@@ -1369,6 +1377,7 @@ static int sqfs_read_nest(const char *filename, void *buf, loff_t offset,
unsigned long dest_len;
struct fs_dirent *dent;
unsigned char *ipos;
+ size_t buf_size;
*actread = 0;
@@ -1573,7 +1582,10 @@ static int sqfs_read_nest(const char *filename, void *buf, loff_t offset,
table_offset = frag_entry.start - (start * ctxt.cur_dev->blksz);
n_blks = DIV_ROUND_UP(table_size + table_offset, ctxt.cur_dev->blksz);
- fragment = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz);
+ if (__builtin_mul_overflow(n_blks, ctxt.cur_dev->blksz, &buf_size))
+ return -EINVAL;
+
+ fragment = malloc_cache_aligned(buf_size);
if (!fragment) {
ret = -ENOMEM;