summaryrefslogtreecommitdiffstats
path: root/contrib/libarchive/libarchive/test
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libarchive/libarchive/test')
-rw-r--r--contrib/libarchive/libarchive/test/main.c25
-rw-r--r--contrib/libarchive/libarchive/test/test.h3
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_secure744.c190
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_secure745.c158
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_secure746.c258
5 files changed, 634 insertions, 0 deletions
diff --git a/contrib/libarchive/libarchive/test/main.c b/contrib/libarchive/libarchive/test/main.c
index cdb8538..7e411c3 100644
--- a/contrib/libarchive/libarchive/test/main.c
+++ b/contrib/libarchive/libarchive/test/main.c
@@ -1396,6 +1396,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)
diff --git a/contrib/libarchive/libarchive/test/test.h b/contrib/libarchive/libarchive/test/test.h
index 3b00bfb..8010ecd 100644
--- a/contrib/libarchive/libarchive/test/test.h
+++ b/contrib/libarchive/libarchive/test/test.h
@@ -176,6 +176,8 @@
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) \
@@ -239,6 +241,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/contrib/libarchive/libarchive/test/test_write_disk_secure744.c b/contrib/libarchive/libarchive/test/test_write_disk_secure744.c
new file mode 100644
index 0000000..008161d
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_write_disk_secure744.c
@@ -0,0 +1,190 @@
+/*-
+ * 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
+}
+/*-
+ * 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/contrib/libarchive/libarchive/test/test_write_disk_secure745.c b/contrib/libarchive/libarchive/test/test_write_disk_secure745.c
new file mode 100644
index 0000000..8694676
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_write_disk_secure745.c
@@ -0,0 +1,158 @@
+/*-
+ * 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, AE_IFLNK | 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);
+
+ assert(0 == archive_write_close(a));
+ archive_write_free(a);
+#endif
+}
+/*-
+ * 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, AE_IFLNK | 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);
+
+ assert(0 == archive_write_close(a));
+ archive_write_free(a);
+#endif
+}
diff --git a/contrib/libarchive/libarchive/test/test_write_disk_secure746.c b/contrib/libarchive/libarchive/test/test_write_disk_secure746.c
new file mode 100644
index 0000000..72df283
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_write_disk_secure746.c
@@ -0,0 +1,258 @@
+/*-
+ * 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, AE_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_FATAL, 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_set_mode(ae, AE_IFLNK | 0777);
+ archive_entry_copy_symlink(ae, "../target");
+ assertEqualIntA(a, ARCHIVE_OK, 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, AE_IFREG | 0777);
+ archive_entry_set_size(ae, 8);
+ archive_entry_copy_hardlink(ae, "symlink/foo");
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae));
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_write_data(a, "modified", 8));
+ archive_entry_free(ae);
+
+ /* Verify that target file contents are unchanged. */
+ assertTextFileContents("unmodified", "../target/foo");
+
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_write_close(a));
+ archive_write_free(a);
+#endif
+}
+/*-
+ * 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, AE_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_FATAL, 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_set_mode(ae, AE_IFLNK | 0777);
+ archive_entry_copy_symlink(ae, "../target");
+ assertEqualIntA(a, ARCHIVE_OK, 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, AE_IFREG | 0777);
+ archive_entry_set_size(ae, 8);
+ archive_entry_copy_hardlink(ae, "symlink/foo");
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae));
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_write_data(a, "modified", 8));
+ archive_entry_free(ae);
+
+ /* Verify that target file contents are unchanged. */
+ assertTextFileContents("unmodified", "../target/foo");
+
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_write_close(a));
+ archive_write_free(a);
+#endif
+}
OpenPOWER on IntegriCloud