summaryrefslogtreecommitdiff
path: root/bin/rdsquashfs/rdsquashfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/rdsquashfs/rdsquashfs.c')
-rw-r--r--bin/rdsquashfs/rdsquashfs.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/bin/rdsquashfs/rdsquashfs.c b/bin/rdsquashfs/rdsquashfs.c
index 47eaf94..a8dc4c9 100644
--- a/bin/rdsquashfs/rdsquashfs.c
+++ b/bin/rdsquashfs/rdsquashfs.c
@@ -6,6 +6,89 @@
*/
#include "rdsquashfs.h"
+static sqfs_tree_node_t *list_merge(sqfs_tree_node_t *lhs,
+ sqfs_tree_node_t *rhs)
+{
+ sqfs_tree_node_t *it, *head = NULL, **next_ptr = &head;
+
+ while (lhs != NULL && rhs != NULL) {
+ if (strcmp((const char *)lhs->name,
+ (const char *)rhs->name) <= 0) {
+ it = lhs;
+ lhs = lhs->next;
+ } else {
+ it = rhs;
+ rhs = rhs->next;
+ }
+
+ *next_ptr = it;
+ next_ptr = &it->next;
+ }
+
+ it = (lhs != NULL ? lhs : rhs);
+ *next_ptr = it;
+ return head;
+}
+
+static sqfs_tree_node_t *list_sort(sqfs_tree_node_t *head)
+{
+ sqfs_tree_node_t *it, *half, *prev;
+
+ it = half = prev = head;
+
+ while (it != NULL) {
+ prev = half;
+ half = half->next;
+ it = it->next;
+
+ if (it != NULL)
+ it = it->next;
+ }
+
+ if (half == NULL)
+ return head;
+
+ prev->next = NULL;
+
+ return list_merge(list_sort(head), list_sort(half));
+}
+
+static int tree_sort(sqfs_tree_node_t *root)
+{
+ sqfs_tree_node_t *it;
+
+ if (root->children == NULL)
+ return 0;
+
+ root->children = list_sort(root->children);
+
+ /*
+ XXX: not only an inconvenience but a security issue: e.g. we unpack a
+ SquashFS image that has a symlink pointing somewhere, and then a
+ sub-directory or file with the same name, the unpacker can be tricked
+ to follow the symlink and write anything, anywhere on the filesystem.
+ */
+ for (it = root->children; it->next != NULL; it = it->next) {
+ if (strcmp((const char *)it->name,
+ (const char *)it->next->name) == 0) {
+ char *path = sqfs_tree_node_get_path(it);
+
+ fprintf(stderr, "Entry '%s' found more than once!\n",
+ path);
+
+ sqfs_free(path);
+ return -1;
+ }
+ }
+
+ for (it = root->children; it != NULL; it = it->next) {
+ if (tree_sort(it))
+ return -1;
+ }
+
+ return 0;
+}
+
int main(int argc, char **argv)
{
sqfs_xattr_reader_t *xattr = NULL;
@@ -138,6 +221,9 @@ int main(int argc, char **argv)
break;
}
case OP_UNPACK:
+ if (tree_sort(n))
+ goto out;
+
if (opt.unpack_root != NULL) {
if (mkdir_p(opt.unpack_root))
goto out;