]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Test cases for Github Issue #744, #745, and #746.
authorTim Kientzle <kientzle@gmail.com>
Wed, 10 Aug 2016 01:31:36 +0000 (21:31 -0400)
committerTim Kientzle <kientzle@gmail.com>
Wed, 10 Aug 2016 01:31:36 +0000 (21:31 -0400)
Makefile.am
libarchive/test/CMakeLists.txt
libarchive/test/main.c
libarchive/test/test.h
libarchive/test/test_write_disk_secure744.c [new file with mode: 0644]
libarchive/test/test_write_disk_secure745.c [new file with mode: 0644]
libarchive/test/test_write_disk_secure746.c [new file with mode: 0644]

index d26eac1bbb8369076be028d98384bfda1cafb6d2..1d67f9cda42de5070f958e55f02aba73b584c3dc 100644 (file)
@@ -509,6 +509,9 @@ libarchive_test_SOURCES= \
        libarchive/test/test_write_disk_no_hfs_compression.c \
        libarchive/test/test_write_disk_perms.c \
        libarchive/test/test_write_disk_secure.c \
+       libarchive/test/test_write_disk_secure744.c \
+       libarchive/test/test_write_disk_secure745.c \
+       libarchive/test/test_write_disk_secure746.c \
        libarchive/test/test_write_disk_sparse.c \
        libarchive/test/test_write_disk_symlink.c \
        libarchive/test/test_write_disk_times.c \
index 124aa3a8b1bae86db1c5fec5023ea1942fc35fbf..f50c0780b5d72dd37afe6d0aa79ada4043d23a3e 100644 (file)
@@ -198,6 +198,9 @@ IF(ENABLE_TEST)
     test_write_disk_no_hfs_compression.c
     test_write_disk_perms.c
     test_write_disk_secure.c
+    test_write_disk_secure744.c
+    test_write_disk_secure745.c
+    test_write_disk_secure746.c
     test_write_disk_sparse.c
     test_write_disk_symlink.c
     test_write_disk_times.c
index 7c266857be905845298fe481c29e6d4953cb6127..9fa26fbf8640be1b61d88506e1851287d2141c7a 100644 (file)
@@ -1440,6 +1440,31 @@ assertion_file_size(const char *file, int line, const char *pathname, long size)
        return (0);
 }
 
+/* Verify mode of 'pathname'. */
+int
+assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode)
+{
+       int mode;
+       int r;
+
+       assertion_count(file, line);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       failure_start(file, line, "assertFileMode not yet implemented for Windows");
+#else
+       {
+               struct stat st;
+               r = lstat(pathname, &st);
+               mode = (int)(st.st_mode & 0777);
+       }
+       if (r == 0 && mode == expected_mode)
+                       return (1);
+       failure_start(file, line, "File %s has mode %o, expected %o",
+           pathname, mode, expected_mode);
+#endif
+       failure_finish(NULL);
+       return (0);
+}
+
 /* Assert that 'pathname' is a dir.  If mode >= 0, verify that too. */
 int
 assertion_is_dir(const char *file, int line, const char *pathname, int mode)
index 1117d6a77760324ee41a958b19e68f14268fb561..2fe09ff169b7fc88b417403529165975686aedcb 100644 (file)
   assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks)
 #define assertFileSize(pathname, size)  \
   assertion_file_size(__FILE__, __LINE__, pathname, size)
+#define assertFileMode(pathname, mode)  \
+  assertion_file_mode(__FILE__, __LINE__, pathname, mode)
 #define assertTextFileContents(text, pathname) \
   assertion_text_file_contents(__FILE__, __LINE__, text, pathname)
 #define assertFileContainsLinesAnyOrder(pathname, lines)       \
@@ -246,6 +248,7 @@ int assertion_file_mtime_recent(const char *, int, const char *);
 int assertion_file_nlinks(const char *, int, const char *, int);
 int assertion_file_not_exists(const char *, int, const char *);
 int assertion_file_size(const char *, int, const char *, long);
+int assertion_file_mode(const char *, int, const char *, int);
 int assertion_is_dir(const char *, int, const char *, int);
 int assertion_is_hardlink(const char *, int, const char *, const char *);
 int assertion_is_not_hardlink(const char *, int, const char *, const char *);
diff --git a/libarchive/test/test_write_disk_secure744.c b/libarchive/test/test_write_disk_secure744.c
new file mode 100644 (file)
index 0000000..08c725e
--- /dev/null
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2003-2007,2016 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+#define UMASK 022
+
+/*
+ * Github Issue #744 describes a bug in the sandboxing code that
+ * causes very long pathnames to not get checked for symlinks.
+ */
+
+DEFINE_TEST(test_write_disk_secure744)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       skipping("archive_write_disk security checks not supported on Windows");
+#else
+       struct archive *a;
+       struct archive_entry *ae;
+       size_t buff_size = 8192;
+       char *buff = malloc(buff_size);
+       char *p = buff;
+       int n = 0;
+       int t;
+
+       assert(buff != NULL);
+
+       /* Start with a known umask. */
+       assertUmask(UMASK);
+
+       /* Create an archive_write_disk object. */
+       assert((a = archive_write_disk_new()) != NULL);
+       archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS);
+
+       while (p + 500 < buff + buff_size) {
+               memset(p, 'x', 100);
+               p += 100;
+               p[0] = '\0';
+
+               buff[0] = ((n / 1000) % 10) + '0';
+               buff[1] = ((n / 100) % 10)+ '0';
+               buff[2] = ((n / 10) % 10)+ '0';
+               buff[3] = ((n / 1) % 10)+ '0';
+               buff[4] = '_';
+               ++n;
+
+               /* Create a symlink pointing to the testworkdir */
+               assert((ae = archive_entry_new()) != NULL);
+               archive_entry_copy_pathname(ae, buff);
+               archive_entry_set_mode(ae, S_IFREG | 0777);
+               archive_entry_copy_symlink(ae, testworkdir);
+               assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+               archive_entry_free(ae);
+
+               *p++ = '/';
+               sprintf(p, "target%d", n);
+
+               /* Try to create a file through the symlink, should fail. */
+               assert((ae = archive_entry_new()) != NULL);
+               archive_entry_copy_pathname(ae, buff);
+               archive_entry_set_mode(ae, S_IFDIR | 0777);
+
+               t = archive_write_header(a, ae);
+               archive_entry_free(ae);
+               failure("Attempt to create target%d via %d-character symlink should have failed", n, (int)strlen(buff));
+               if(!assertEqualInt(ARCHIVE_FAILED, t)) {
+                       break;
+               }
+       }
+       archive_free(a);
+       free(buff);
+#endif
+}
diff --git a/libarchive/test/test_write_disk_secure745.c b/libarchive/test/test_write_disk_secure745.c
new file mode 100644 (file)
index 0000000..fa6939b
--- /dev/null
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2003-2007,2016 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+#define UMASK 022
+
+/*
+ * Github Issue #745 describes a bug in the sandboxing code that
+ * allows one to use a symlink to edit the permissions on a file or
+ * directory outside of the sandbox.
+ */
+
+DEFINE_TEST(test_write_disk_secure745)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       skipping("archive_write_disk security checks not supported on Windows");
+#else
+       struct archive *a;
+       struct archive_entry *ae;
+
+       /* Start with a known umask. */
+       assertUmask(UMASK);
+
+       /* Create an archive_write_disk object. */
+       assert((a = archive_write_disk_new()) != NULL);
+       archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS);
+
+       /* The target dir:  The one we're going to try to change permission on */
+       assertMakeDir("target", 0700);
+
+       /* The sandbox dir we're going to run inside of. */
+       assertMakeDir("sandbox", 0700);
+       assertChdir("sandbox");
+
+       /* Create a symlink pointing to the target directory */
+       assert((ae = archive_entry_new()) != NULL);
+       archive_entry_copy_pathname(ae, "sym");
+       archive_entry_set_mode(ae, S_IFREG | 0777);
+       archive_entry_copy_symlink(ae, "../target");
+       assert(0 == archive_write_header(a, ae));
+       archive_entry_free(ae);
+
+       /* Try to alter the target dir through the symlink; this should fail. */
+       assert((ae = archive_entry_new()) != NULL);
+       archive_entry_copy_pathname(ae, "sym");
+       archive_entry_set_mode(ae, S_IFDIR | 0777);
+       assert(0 == archive_write_header(a, ae));
+       archive_entry_free(ae);
+
+       /* Permission of target dir should not have changed. */
+       assertFileMode("../target", 0700);
+#endif
+}
diff --git a/libarchive/test/test_write_disk_secure746.c b/libarchive/test/test_write_disk_secure746.c
new file mode 100644 (file)
index 0000000..0daf1b0
--- /dev/null
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 2003-2007,2016 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+#define UMASK 022
+
+/*
+ * Github Issue #746 describes a problem in which hardlink targets are
+ * not adequately checked and can be used to modify entries outside of
+ * the sandbox.
+ */
+
+/*
+ * Verify that ARCHIVE_EXTRACT_SECURE_NODOTDOT disallows '..' in hardlink
+ * targets.
+ */
+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;
+
+       /* Start with a known umask. */
+       assertUmask(UMASK);
+
+       /* The target directory we're going to try to affect. */
+       assertMakeDir("target", 0700);
+       assertMakeFile("target/foo", 0700, "unmodified");
+
+       /* The sandbox dir we're going to work within. */
+       assertMakeDir("sandbox", 0700);
+       assertChdir("sandbox");
+
+       /* Create an archive_write_disk object. */
+       assert((a = archive_write_disk_new()) != NULL);
+       archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_NODOTDOT);
+
+       /* Attempt to hardlink to the target directory. */
+       assert((ae = archive_entry_new()) != NULL);
+       archive_entry_copy_pathname(ae, "bar");
+       archive_entry_set_mode(ae, S_IFREG | 0777);
+       archive_entry_set_size(ae, 8);
+       archive_entry_copy_hardlink(ae, "../target/foo");
+       assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
+       assertEqualInt(ARCHIVE_FAILED, archive_write_data(a, "modified", 8));
+       archive_entry_free(ae);
+
+       /* Verify that target file contents are unchanged. */
+       assertTextFileContents("unmodified", "../target/foo");
+#endif
+}
+
+/*
+ * Verify that ARCHIVE_EXTRACT_SECURE_NOSYMLINK disallows symlinks in hardlink
+ * targets.
+ */
+DEFINE_TEST(test_write_disk_secure746b)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       skipping("archive_write_disk security checks not supported on Windows");
+#else
+       struct archive *a;
+       struct archive_entry *ae;
+
+       /* Start with a known umask. */
+       assertUmask(UMASK);
+
+       /* The target directory we're going to try to affect. */
+       assertMakeDir("target", 0700);
+       assertMakeFile("target/foo", 0700, "unmodified");
+
+       /* The sandbox dir we're going to work within. */
+       assertMakeDir("sandbox", 0700);
+       assertChdir("sandbox");
+
+       /* Create an archive_write_disk object. */
+       assert((a = archive_write_disk_new()) != NULL);
+       archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS);
+
+       /* Create a symlink to the target directory. */
+       assert((ae = archive_entry_new()) != NULL);
+       archive_entry_copy_pathname(ae, "symlink");
+       archive_entry_copy_symlink(ae, "../target");
+       assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
+       archive_entry_free(ae);
+
+       /* Attempt to hardlink to the target directory via the symlink. */
+       assert((ae = archive_entry_new()) != NULL);
+       archive_entry_copy_pathname(ae, "bar");
+       archive_entry_set_mode(ae, S_IFREG | 0777);
+       archive_entry_set_size(ae, 8);
+       archive_entry_copy_hardlink(ae, "symlink/foo");
+       assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
+       assertEqualInt(ARCHIVE_FAILED, archive_write_data(a, "modified", 8));
+       archive_entry_free(ae);
+
+       /* Verify that target file contents are unchanged. */
+       assertTextFileContents("unmodified", "../target/foo");
+#endif
+}