diff mbox series

Fix a squashfs crash when reading large directories

Message ID c1a5f939-9f5f-b566-8c8f-3a5aadc1aa05@snapit.group
State Deferred
Delegated to: Tom Rini
Headers show
Series Fix a squashfs crash when reading large directories | expand

Commit Message

Campbell Suter Nov. 22, 2020, 9:02 p.m. UTC
SquashFS encodes directories with more than 256 entries, with xattrs or
a few other things with a different type of inode than most directories.

This type of directory entry has an indexing feature to increase the
performance of filename lookups. When U-Boot's squashfs driver
calculates the length of such an inode, it incorrectly adds one to the
number of indexes which causes the length to be miscalculated, causing a
synchronous abort when reading the next inode.

This occurs for directories that satisfy all the following conditions:

* They have at least 257 entries, the size of their inodes add to >8K,
or they have extended attributes. 
* They are not the root directory (as there is no subsequent inode to
read), and are not the last child of the root directory.
* The length of the names of all the child files sum to a sufficent
value (I think this is the point where the child entries span multiple
metadata blocks, but I haven't confirmed it)

The following script generates a squashfs that was crashing when listed:

mkdir -p files/{a,b,c}         
pad=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
for i in {1..257}; do touch files/b/file-$(printf '%03d' $i)-$pad done
mksquashfs files result.squashfs
  
Signed-off-by: Campbell Suter <campbell@snapit.group>
---
  
 fs/squashfs/sqfs_inode.c | 4 ++-- 
 1 file changed, 2 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/fs/squashfs/sqfs_inode.c b/fs/squashfs/sqfs_inode.c
index 14d70cf678..e76ec7cbdf 100644
--- a/fs/squashfs/sqfs_inode.c
+++ b/fs/squashfs/sqfs_inode.c
@@ -49,7 +49,7 @@  int sqfs_inode_size(struct squashfs_base_inode *inode, u32 blk_size)
                        return sizeof(*ldir);
 
                di = ldir->index;
-               while (l < i_count + 1) {
+               while (l < i_count) {                   
                        sz = get_unaligned_le32(&di->size) + 1;
                        index_list_size += sz;          
                        di = (void *)di + sizeof(*di) + sz;
@@ -57,7 +57,7 @@  int sqfs_inode_size(struct squashfs_base_inode *inode, u32 blk_size)
                }
 
                return sizeof(*ldir) + index_list_size +
-                       (i_count + 1) * SQFS_DIR_INDEX_BASE_LENGTH;
+                       i_count * SQFS_DIR_INDEX_BASE_LENGTH;
        }
 
        case SQFS_LREG_TYPE: {