Correctly handle cyclic directory structures
authorEric Biggers <ebiggers3@gmail.com>
Wed, 22 May 2013 04:04:31 +0000 (23:04 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Wed, 22 May 2013 04:04:31 +0000 (23:04 -0500)
NEWS
src/dentry.c

diff --git a/NEWS b/NEWS
index 71d306c..5cc48a9 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -43,7 +43,12 @@ Version 1.4.1:
        NTFS-3g capture now only warns about two conditions previously treated
        as errors.
 
-       Fixed a couple issues with using wimlib-imagex on UDF filesystems.
+       Fixed a couple issues with using wimlib-imagex on UDF filesystems on
+       Windows.
+
+       wimlib now correctly detects and returns an error when reading a WIM
+       image with a cyclic directory structure.  (Fun fact: such a WIM will
+       crash Microsoft's software.)
 
 Version 1.4.0:
        Added new "extract" and "update" subcommands to wimlib-imagex, along
index c62a694..5031719 100644 (file)
@@ -1906,6 +1906,7 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
        u64 cur_offset = dentry->subdir_offset;
        struct wim_dentry *child;
        struct wim_dentry *duplicate;
+       struct wim_dentry *parent;
        struct wim_dentry cur_child;
        int ret;
 
@@ -1918,6 +1919,18 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
        if (cur_offset == 0)
                return 0;
 
+       /* Check for cyclic directory structure */
+       for (parent = dentry->parent; !dentry_is_root(parent); parent = parent->parent)
+       {
+               if (unlikely(parent->subdir_offset == cur_offset)) {
+                       ERROR("Cyclic directory structure directed: children "
+                             "of \"%"TS"\" coincide with children of \"%"TS"\"",
+                             dentry_full_path(dentry),
+                             dentry_full_path(parent));
+                       return WIMLIB_ERR_INVALID_DENTRY;
+               }
+       }
+
        /* Find and read all the children of @dentry. */
        for (;;) {
 
@@ -1948,7 +1961,7 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
                cur_offset += dentry_total_length(child);
 
                duplicate = dentry_add_child(dentry, child);
-               if (duplicate) {
+               if (unlikely(duplicate)) {
                        const tchar *child_type, *duplicate_type;
                        child_type = dentry_get_file_type_string(child);
                        duplicate_type = dentry_get_file_type_string(duplicate);
@@ -1962,7 +1975,7 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
                        /* If there are children of this child, call this
                         * procedure recursively. */
                        if (child->subdir_offset != 0) {
-                               if (dentry_is_directory(child)) {
+                               if (likely(dentry_is_directory(child))) {
                                        ret = read_dentry_tree(metadata_resource,
                                                               metadata_resource_len,
                                                               child);