]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
fs/squashfs: fix dirs->entry leaks on sqfs_search_dir() error paths
authorAllan ELKAIM <allan.elkaim@gmail.com>
Mon, 13 Jul 2026 14:22:47 +0000 (16:22 +0200)
committerTom Rini <trini@konsulko.com>
Sat, 25 Jul 2026 00:39:29 +0000 (18:39 -0600)
Several error paths in sqfs_search_dir() return through 'goto out'
while a directory entry obtained from sqfs_readdir_nest() is still
held, leaking dirs->entry: the inode lookup failure, the symlink
nesting limit check, every allocation/tokenization failure during
symlink resolution, and the case where readdir aborts after an
entry was already read.

Instead of freeing dirs->entry at each error site, centralize the
cleanup at the 'out' label: on error, no valid entry may be handed
back to the caller, so it can be freed unconditionally there. On
success, dirs->entry is already NULL: it is freed at the end of
each token iteration and before recursing into a symlink target,
and the root directory path never allocates it.

Explicit frees remain only where a success path needs them:
between reads in the readdir loop, at the end of each token
iteration, and before the recursive call. The now-redundant frees
on individual error paths are removed.

Suggested-by: Richard Genoud <richard.genoud@bootlin.com>
Signed-off-by: Allan ELKAIM <allan.elkaim@gmail.com>
fs/squashfs/sqfs.c

index af32d008e30dd8e3d659f2e79650b41b57e81d4c..471ea7d9df80b008d7c8f6ff83963b4fb4f12db8 100644 (file)
@@ -547,8 +547,10 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
                /* Get reference to inode in the inode table */
                table = sqfs_find_inode(dirs->inode_table, new_inode_number,
                                        sblk->inodes, sblk->block_size);
-               if (!table)
-                       return -EINVAL;
+               if (!table) {
+                       ret = -EINVAL;
+                       goto out;
+               }
                dir = (struct squashfs_dir_inode *)table;
 
                /* Check for symbolic link and inode type sanity */
@@ -617,8 +619,6 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
                        goto out;
                } else if (!sqfs_is_dir(get_unaligned_le16(&dir->inode_type))) {
                        printf("** Cannot find directory. **\n");
-                       free(dirs->entry);
-                       dirs->entry = NULL;
                        ret = -EINVAL;
                        goto out;
                }
@@ -630,8 +630,6 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
                /* Get dir. offset into the directory table */
                offset = sqfs_dir_offset(table, m_list, m_count);
                if (offset < 0) {
-                       free(dirs->entry);
-                       dirs->entry = NULL;
                        ret = offset;
                        goto out;
                }
@@ -644,8 +642,6 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
                /* Check for empty directory */
                if (sqfs_is_empty_dir(table)) {
                        printf("Empty directory.\n");
-                       free(dirs->entry);
-                       dirs->entry = NULL;
                        ret = SQFS_EMPTY_DIR;
                        goto out;
                }
@@ -660,8 +656,6 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
 
        offset = sqfs_dir_offset(table, m_list, m_count);
        if (offset < 0) {
-               free(dirs->entry);
-               dirs->entry = NULL;
                ret = offset;
                goto out;
        }
@@ -673,6 +667,10 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
                memcpy(&dirs->i_ldir, ldir, sizeof(*ldir));
 
 out:
+       if (ret < 0) {
+               free(dirs->entry);
+               dirs->entry = NULL;
+       }
        free(res);
        free(rem);
        free(path);