1306941Sdelphij/*- 2306941Sdelphij * Copyright (c) 2003-2007,2016 Tim Kientzle 3306941Sdelphij * All rights reserved. 4306941Sdelphij * 5306941Sdelphij * Redistribution and use in source and binary forms, with or without 6306941Sdelphij * modification, are permitted provided that the following conditions 7306941Sdelphij * are met: 8306941Sdelphij * 1. Redistributions of source code must retain the above copyright 9306941Sdelphij * notice, this list of conditions and the following disclaimer. 10306941Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 11306941Sdelphij * notice, this list of conditions and the following disclaimer in the 12306941Sdelphij * documentation and/or other materials provided with the distribution. 13306941Sdelphij * 14306941Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15306941Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16306941Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17306941Sdelphij * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18306941Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19306941Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20306941Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21306941Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22306941Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23306941Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24306941Sdelphij */ 25306941Sdelphij#include "test.h" 26306941Sdelphij__FBSDID("$FreeBSD: releng/10.2/contrib/libarchive/libarchive/test/test_write_disk_secure746.c 306941 2016-10-10 07:18:54Z delphij $"); 27306941Sdelphij 28306941Sdelphij#define UMASK 022 29306941Sdelphij 30306941Sdelphij/* 31306941Sdelphij * Github Issue #746 describes a problem in which hardlink targets are 32306941Sdelphij * not adequately checked and can be used to modify entries outside of 33306941Sdelphij * the sandbox. 34306941Sdelphij */ 35306941Sdelphij 36306941Sdelphij/* 37306941Sdelphij * Verify that ARCHIVE_EXTRACT_SECURE_NODOTDOT disallows '..' in hardlink 38306941Sdelphij * targets. 39306941Sdelphij */ 40306941SdelphijDEFINE_TEST(test_write_disk_secure746a) 41306941Sdelphij{ 42306941Sdelphij#if defined(_WIN32) && !defined(__CYGWIN__) 43306941Sdelphij skipping("archive_write_disk security checks not supported on Windows"); 44306941Sdelphij#else 45306941Sdelphij struct archive *a; 46306941Sdelphij struct archive_entry *ae; 47306941Sdelphij 48306941Sdelphij /* Start with a known umask. */ 49306941Sdelphij assertUmask(UMASK); 50306941Sdelphij 51306941Sdelphij /* The target directory we're going to try to affect. */ 52306941Sdelphij assertMakeDir("target", 0700); 53306941Sdelphij assertMakeFile("target/foo", 0700, "unmodified"); 54306941Sdelphij 55306941Sdelphij /* The sandbox dir we're going to work within. */ 56306941Sdelphij assertMakeDir("sandbox", 0700); 57306941Sdelphij assertChdir("sandbox"); 58306941Sdelphij 59306941Sdelphij /* Create an archive_write_disk object. */ 60306941Sdelphij assert((a = archive_write_disk_new()) != NULL); 61306941Sdelphij archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_NODOTDOT); 62306941Sdelphij 63306941Sdelphij /* Attempt to hardlink to the target directory. */ 64306941Sdelphij assert((ae = archive_entry_new()) != NULL); 65306941Sdelphij archive_entry_copy_pathname(ae, "bar"); 66306941Sdelphij archive_entry_set_mode(ae, AE_IFREG | 0777); 67306941Sdelphij archive_entry_set_size(ae, 8); 68306941Sdelphij archive_entry_copy_hardlink(ae, "../target/foo"); 69306941Sdelphij assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae)); 70306941Sdelphij assertEqualInt(ARCHIVE_FATAL, archive_write_data(a, "modified", 8)); 71306941Sdelphij archive_entry_free(ae); 72306941Sdelphij 73306941Sdelphij /* Verify that target file contents are unchanged. */ 74306941Sdelphij assertTextFileContents("unmodified", "../target/foo"); 75306941Sdelphij#endif 76306941Sdelphij} 77306941Sdelphij 78306941Sdelphij/* 79306941Sdelphij * Verify that ARCHIVE_EXTRACT_SECURE_NOSYMLINK disallows symlinks in hardlink 80306941Sdelphij * targets. 81306941Sdelphij */ 82306941SdelphijDEFINE_TEST(test_write_disk_secure746b) 83306941Sdelphij{ 84306941Sdelphij#if defined(_WIN32) && !defined(__CYGWIN__) 85306941Sdelphij skipping("archive_write_disk security checks not supported on Windows"); 86306941Sdelphij#else 87306941Sdelphij struct archive *a; 88306941Sdelphij struct archive_entry *ae; 89306941Sdelphij 90306941Sdelphij /* Start with a known umask. */ 91306941Sdelphij assertUmask(UMASK); 92306941Sdelphij 93306941Sdelphij /* The target directory we're going to try to affect. */ 94306941Sdelphij assertMakeDir("target", 0700); 95306941Sdelphij assertMakeFile("target/foo", 0700, "unmodified"); 96306941Sdelphij 97306941Sdelphij /* The sandbox dir we're going to work within. */ 98306941Sdelphij assertMakeDir("sandbox", 0700); 99306941Sdelphij assertChdir("sandbox"); 100306941Sdelphij 101306941Sdelphij /* Create an archive_write_disk object. */ 102306941Sdelphij assert((a = archive_write_disk_new()) != NULL); 103306941Sdelphij archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS); 104306941Sdelphij 105306941Sdelphij /* Create a symlink to the target directory. */ 106306941Sdelphij assert((ae = archive_entry_new()) != NULL); 107306941Sdelphij archive_entry_copy_pathname(ae, "symlink"); 108306941Sdelphij archive_entry_set_mode(ae, AE_IFLNK | 0777); 109306941Sdelphij archive_entry_copy_symlink(ae, "../target"); 110306941Sdelphij assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); 111306941Sdelphij archive_entry_free(ae); 112306941Sdelphij 113306941Sdelphij /* Attempt to hardlink to the target directory via the symlink. */ 114306941Sdelphij assert((ae = archive_entry_new()) != NULL); 115306941Sdelphij archive_entry_copy_pathname(ae, "bar"); 116306941Sdelphij archive_entry_set_mode(ae, AE_IFREG | 0777); 117306941Sdelphij archive_entry_set_size(ae, 8); 118306941Sdelphij archive_entry_copy_hardlink(ae, "symlink/foo"); 119306941Sdelphij assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae)); 120306941Sdelphij assertEqualIntA(a, ARCHIVE_FATAL, archive_write_data(a, "modified", 8)); 121306941Sdelphij archive_entry_free(ae); 122306941Sdelphij 123306941Sdelphij /* Verify that target file contents are unchanged. */ 124306941Sdelphij assertTextFileContents("unmodified", "../target/foo"); 125306941Sdelphij 126306941Sdelphij assertEqualIntA(a, ARCHIVE_FATAL, archive_write_close(a)); 127306941Sdelphij archive_write_free(a); 128306941Sdelphij#endif 129306941Sdelphij} 130