From: Joao Marcos Costa <joaomarcos.co...@bootlin.com>

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.co...@bootlin.com>
---
 fs/squashfs/sqfs.c | 18 +++++++++++++++---
 1 file 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;
-- 
2.47.0

Reply via email to