]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Support ARCHIVE_EXTRACT_SECURE_NODOTDOT on Windows 1590/head
authorJoerg Sonnenberger <joerg@bec.de>
Wed, 6 Oct 2021 22:24:30 +0000 (00:24 +0200)
committerJoerg Sonnenberger <joerg@bec.de>
Wed, 6 Oct 2021 22:54:15 +0000 (00:54 +0200)
libarchive/archive_write_disk_windows.c
libarchive/test/test_write_disk_secure746.c

index 0c600176cd54325b3c1452f1b84624bb73a1c4a1..0cfc92835ee3d0dfff24d34dee7de13ffc13bd44 100644 (file)
@@ -213,7 +213,7 @@ static int  check_symlinks(struct archive_write_disk *);
 static int     create_filesystem_object(struct archive_write_disk *);
 static struct fixup_entry *current_fixup(struct archive_write_disk *,
                    const wchar_t *pathname);
-static int     cleanup_pathname(struct archive_write_disk *);
+static int     cleanup_pathname(struct archive_write_disk *, wchar_t *);
 static int     create_dir(struct archive_write_disk *, wchar_t *);
 static int     create_parent_dir(struct archive_write_disk *, wchar_t *);
 static int     la_chmod(const wchar_t *, mode_t);
@@ -854,7 +854,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
         * dir restores; the dir restore logic otherwise gets messed
         * up by nonsense like "dir/.".
         */
-       ret = cleanup_pathname(a);
+       ret = cleanup_pathname(a, a->name);
        if (ret != ARCHIVE_OK)
                return (ret);
 
@@ -1671,9 +1671,22 @@ create_filesystem_object(struct archive_write_disk *a)
        /* Since link(2) and symlink(2) don't handle modes, we're done here. */
        linkname = archive_entry_hardlink_w(a->entry);
        if (linkname != NULL) {
-               wchar_t *linkfull, *namefull;
-
-               linkfull = __la_win_permissive_name_w(linkname);
+               wchar_t *linksanitized, *linkfull, *namefull;
+               size_t l = (wcslen(linkname) + 1) * sizeof(wchar_t);
+               linksanitized = malloc(l);
+               if (linksanitized == NULL) {
+                       archive_set_error(&a->archive, ENOMEM,
+                           "Can't allocate memory for hardlink target");
+                       return (-1);
+               }
+               memcpy(linksanitized, linkname, l);
+               r = cleanup_pathname(a, linksanitized);
+               if (r != ARCHIVE_OK) {
+                       free(linksanitized);
+                       return (r);
+               }
+               linkfull = __la_win_permissive_name_w(linksanitized);
+               free(linksanitized);
                namefull = __la_win_permissive_name_w(a->name);
                if (linkfull == NULL || namefull == NULL) {
                        errno = EINVAL;
@@ -2184,12 +2197,12 @@ guidword(wchar_t *p, int n)
  * set) any '..' in the path.
  */
 static int
-cleanup_pathname(struct archive_write_disk *a)
+cleanup_pathname(struct archive_write_disk *a, wchar_t *name)
 {
        wchar_t *dest, *src, *p, *top;
        wchar_t separator = L'\0';
 
-       p = a->name;
+       p = name;
        if (*p == L'\0') {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                    "Invalid empty pathname");
@@ -2201,7 +2214,7 @@ cleanup_pathname(struct archive_write_disk *a)
                if (*p == L'/')
                        *p = L'\\';
        }
-       p = a->name;
+       p = name;
 
        /* Skip leading "\\.\" or "\\?\" or "\\?\UNC\" or
         * "\\?\Volume{GUID}\"
index 5ce1fd9c4c434122885ad13deaa016b26ed27fa7..99cb882c059a2f0559379d246afa67c84dbd2ba7 100644 (file)
@@ -39,9 +39,6 @@ __FBSDID("$FreeBSD$");
  */
 DEFINE_TEST(test_write_disk_secure746a)
 {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-       skipping("archive_write_disk security checks not supported on Windows");
-#else
        struct archive *a;
        struct archive_entry *ae;
 
@@ -75,7 +72,6 @@ DEFINE_TEST(test_write_disk_secure746a)
 
        assertEqualIntA(a, ARCHIVE_FATAL, archive_write_close(a));
        archive_write_free(a);
-#endif
 }
 
 /*