diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-08-22 16:33:36 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-08-22 18:24:26 +0200 |
commit | 8b16efb80d9a863641a0a7395204df038feeb56c (patch) | |
tree | 611e5a85b6fd545b8320ca9db12366e4b574e7e9 /lib/sqfs | |
parent | 8e7311da64b262a8f6a2fbf5119eba8c3e37dfd6 (diff) |
deserialize_tree: filter out directory loops
The tree deserializer does a recursive depth-first search to populate
the directory tree, moving back and forth between the directory listing
containing the inode references and the inode table pointing to the
list of child inodes. It is completely unaware of hard links and creates
duplicate nodes instead.
It is possible to create a malicious SquashFS image that contains a
directory that contains as child a reference to its own inode. This
can also be done transitively (i.e. directory contains its own parent
or grand parent), leading to infinite recursion (actually finite, since
it terminates once all stack memory is exhausted).
This commit adds a simple check to see if a node has the same inode
number as any of its would-be parents. If it does, the node is discarded
and a warning message is emitted.
Other cases with arbitrary layers of indirection could be constructed
as well (e.g. dir 'a' contains hard link to 'b' and 'b' one back to 'a'),
but the sub hierarchies are always expanded, this check should catch that
too.
Reported-by: Zachary Dremann <dremann@gmail.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs')
-rw-r--r-- | lib/sqfs/deserialize_fstree.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/lib/sqfs/deserialize_fstree.c b/lib/sqfs/deserialize_fstree.c index f758a61..050a1df 100644 --- a/lib/sqfs/deserialize_fstree.c +++ b/lib/sqfs/deserialize_fstree.c @@ -65,6 +65,18 @@ static int restore_xattr(xattr_reader_t *xr, fstree_t *fs, tree_node_t *node, return xattr_reader_restore_node(xr, fs, node, idx); } +static bool node_would_be_own_parent(tree_node_t *root, tree_node_t *n) +{ + while (root != NULL) { + if (root->inode_num == n->inode_num) + return true; + + root = root->parent; + } + + return false; +} + static int fill_dir(meta_reader_t *ir, meta_reader_t *dr, tree_node_t *root, sqfs_super_t *super, id_table_t *idtbl, fstree_t *fs, xattr_reader_t *xr, int flags) @@ -128,6 +140,16 @@ static int fill_dir(meta_reader_t *ir, meta_reader_t *dr, tree_node_t *root, return -1; } + if (node_would_be_own_parent(root, n)) { + fputs("WARNING: Found a directory that " + "contains itself, skipping loop back " + "reference!\n", stderr); + free(n); + free(ent); + free(inode); + continue; + } + if (flags & RDTREE_READ_XATTR) { if (restore_xattr(xr, fs, n, inode)) { free(n); |