diff options
Diffstat (limited to 'archivers/libarchive/files/libarchive/test/test_read_disk_directory_traversals.c')
-rw-r--r-- | archivers/libarchive/files/libarchive/test/test_read_disk_directory_traversals.c | 299 |
1 files changed, 286 insertions, 13 deletions
diff --git a/archivers/libarchive/files/libarchive/test/test_read_disk_directory_traversals.c b/archivers/libarchive/files/libarchive/test/test_read_disk_directory_traversals.c index 705b3d989cd..7dd19157d4d 100644 --- a/archivers/libarchive/files/libarchive/test/test_read_disk_directory_traversals.c +++ b/archivers/libarchive/files/libarchive/test/test_read_disk_directory_traversals.c @@ -40,7 +40,30 @@ atimeIsUpdated(void) { const char *fn = "fs_noatime"; struct stat st; - +#if defined(_WIN32) && !defined(CYGWIN) + char *buff = NULL; + char *ptr; + int r; + + r = systemf("fsutil behavior query disableLastAccess > query_atime"); + if (r == 0) { + buff = slurpfile(NULL, "query_atime"); + if (buff != NULL) { + ptr = buff; + while(*ptr != '\0' && !isdigit(*ptr)) { + ptr++; + } + if (*ptr == '0') { + free(buff); + return(1); + } else if (*ptr == '1' || *ptr == '2') { + free(buff); + return(0); + } + free(buff); + } + } +#endif if (!assertMakeFile(fn, 0666, "a")) return (0); if (!assertUtimes(fn, 1, 0, 1, 0)) @@ -570,13 +593,13 @@ test_symlink_hybrid(void) assertMakeDir("h", 0755); assertChdir("h"); assertMakeDir("d1", 0755); - assertMakeSymlink("ld1", "d1"); + assertMakeSymlink("ld1", "d1", 1); assertMakeFile("d1/file1", 0644, "d1/file1"); assertMakeFile("d1/file2", 0644, "d1/file2"); - assertMakeSymlink("d1/link1", "file1"); - assertMakeSymlink("d1/linkX", "fileX"); - assertMakeSymlink("link2", "d1/file2"); - assertMakeSymlink("linkY", "d1/fileY"); + assertMakeSymlink("d1/link1", "file1", 0); + assertMakeSymlink("d1/linkX", "fileX", 0); + assertMakeSymlink("link2", "d1/file2", 0); + assertMakeSymlink("linkY", "d1/fileY", 0); assertChdir(".."); assert((ae = archive_entry_new()) != NULL); @@ -727,13 +750,13 @@ test_symlink_logical(void) assertMakeDir("l", 0755); assertChdir("l"); assertMakeDir("d1", 0755); - assertMakeSymlink("ld1", "d1"); + assertMakeSymlink("ld1", "d1", 1); assertMakeFile("d1/file1", 0644, "d1/file1"); assertMakeFile("d1/file2", 0644, "d1/file2"); - assertMakeSymlink("d1/link1", "file1"); - assertMakeSymlink("d1/linkX", "fileX"); - assertMakeSymlink("link2", "d1/file2"); - assertMakeSymlink("linkY", "d1/fileY"); + assertMakeSymlink("d1/link1", "file1", 0); + assertMakeSymlink("d1/linkX", "fileX", 0); + assertMakeSymlink("link2", "d1/file2", 0); + assertMakeSymlink("linkY", "d1/fileY", 0); assertChdir(".."); /* Note: this test uses archive_read_next_header() @@ -961,8 +984,8 @@ test_symlink_logical_loop(void) assertMakeDir("d1/d2/d3", 0755); assertMakeDir("d2", 0755); assertMakeFile("d2/file1", 0644, "d2/file1"); - assertMakeSymlink("d1/d2/ld1", "../../d1"); - assertMakeSymlink("d1/d2/ld2", "../../d2"); + assertMakeSymlink("d1/d2/ld1", "../../d1", 1); + assertMakeSymlink("d1/d2/ld2", "../../d2", 1); assertChdir(".."); assert((ae = archive_entry_new()) != NULL); @@ -1567,6 +1590,254 @@ test_nodump(void) archive_entry_free(ae); } +static void +test_parent(void) +{ + struct archive *a; + struct archive_entry *ae; + const void *p; + size_t size; + int64_t offset; + int file_count; + int match_count; + int r; + + assertMakeDir("lock", 0311); + assertMakeDir("lock/dir1", 0755); + assertMakeFile("lock/dir1/f1", 0644, "0123456789"); + assertMakeDir("lock/lock2", 0311); + assertMakeDir("lock/lock2/dir1", 0755); + assertMakeFile("lock/lock2/dir1/f1", 0644, "0123456789"); + + assert((ae = archive_entry_new()) != NULL); + assert((a = archive_read_disk_new()) != NULL); + + /* + * Test1: Traverse lock/dir1 as . + */ + assertChdir("lock/dir1"); + + failure("Directory traversals should work as well"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, ".")); + + file_count = 2; + match_count = 0; + while (file_count--) { + archive_entry_clear(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + if (strcmp(archive_entry_pathname(ae), ".") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + ++match_count; + } else if (strcmp(archive_entry_pathname(ae), "./f1") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + assertEqualInt(ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 0); + assertEqualInt((int)offset, 10); + ++match_count; + } + if (archive_read_disk_can_descend(a)) { + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_descend(a)); + } + } + failure("Did not match expected filenames"); + assertEqualInt(match_count, 2); + /* + * There is no entry. This will however fail if the directory traverse + * tries to ascend past the initial directory, since it lacks permission + * to do so. + */ + failure("There should be no entry and no error"); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + + assertChdir("../.."); + + /* + * Test2: Traverse lock/dir1 directly + */ + failure("Directory traversals should work as well"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "lock/dir1")); + + file_count = 2; + match_count = 0; + while (file_count--) { + archive_entry_clear(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + if (strcmp(archive_entry_pathname(ae), "lock/dir1") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + ++match_count; + } else if (strcmp(archive_entry_pathname(ae), "lock/dir1/f1") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + assertEqualInt(ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 0); + assertEqualInt((int)offset, 10); + ++match_count; + } + if (archive_read_disk_can_descend(a)) { + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_descend(a)); + } + } + failure("Did not match expected filenames"); + assertEqualInt(match_count, 2); + /* + * There is no entry. This will however fail if the directory traverse + * tries to ascend past the initial directory, since it lacks permission + * to do so. + */ + failure("There should be no entry and no error"); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + + /* + * Test3: Traverse lock/dir1/. + */ + failure("Directory traversals should work as well"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "lock/dir1/.")); + + file_count = 2; + match_count = 0; + while (file_count--) { + archive_entry_clear(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); + if (strcmp(archive_entry_pathname(ae), "lock/dir1/.") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); + ++match_count; + } else if (strcmp(archive_entry_pathname(ae), "lock/dir1/./f1") == 0) { + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + assertEqualInt(ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, &offset)); + assertEqualInt((int)size, 0); + assertEqualInt((int)offset, 10); + ++match_count; + } + if (archive_read_disk_can_descend(a)) { + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_descend(a)); + } + } + failure("Did not match expected filenames"); + assertEqualInt(match_count, 2); + /* + * There is no entry. This will however fail if the directory traverse + * tries to ascend past the initial directory, since it lacks permission + * to do so. + */ + failure("There should be no entry and no error"); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae)); + + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + + /* + * Test4: Traverse lock/lock2/dir1 from inside lock. + * + * This test is expected to fail on platforms with no O_EXEC or + * equivalent (e.g. O_PATH on Linux or O_SEARCH on SunOS), because + * the current traversal code can't handle the case where it can't + * obtain an open fd for the initial current directory. We need to + * check that condition here, because if O_EXEC _does_ exist, we don't + * want to overlook any failure. + */ + assertChdir("lock"); + + failure("Directory traversals should work as well"); + assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "lock2/dir1")); + + archive_entry_clear(ae); + r = archive_read_next_header2(a, ae); + if (r == ARCHIVE_FAILED) { +#if defined(O_PATH) || defined(O_SEARCH) || defined(O_EXEC) + assertEqualIntA(a, ARCHIVE_OK, r); +#endif + /* Close the disk object. */ + archive_read_close(a); + } else { + file_count = 2; + match_count = 0; + while (file_count--) { + if (file_count == 0) + assertEqualIntA(a, ARCHIVE_OK, + archive_read_next_header2(a, ae)); + if (strcmp(archive_entry_pathname(ae), + "lock2/dir1") == 0) { + assertEqualInt(archive_entry_filetype(ae), + AE_IFDIR); + ++match_count; + } else if (strcmp(archive_entry_pathname(ae), + "lock2/dir1/f1") == 0) { + assertEqualInt(archive_entry_filetype(ae), + AE_IFREG); + assertEqualInt(archive_entry_size(ae), 10); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_data_block(a, &p, &size, + &offset)); + assertEqualInt((int)size, 10); + assertEqualInt((int)offset, 0); + assertEqualMem(p, "0123456789", 10); + assertEqualInt(ARCHIVE_EOF, + archive_read_data_block(a, &p, &size, + &offset)); + assertEqualInt((int)size, 0); + assertEqualInt((int)offset, 10); + ++match_count; + } + if (archive_read_disk_can_descend(a)) { + /* Descend into the current object */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_descend(a)); + } + } + failure("Did not match expected filenames"); + assertEqualInt(match_count, 2); + /* + * There is no entry. This will however fail if the directory + * traverse tries to ascend past the initial directory, since + * it lacks permission to do so. + */ + failure("There should be no entry and no error"); + assertEqualIntA(a, ARCHIVE_EOF, + archive_read_next_header2(a, ae)); + + /* Close the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + } + + assertChdir(".."); + + /* Destroy the disk object. */ + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + archive_entry_free(ae); +} + DEFINE_TEST(test_read_disk_directory_traversals) { /* Basic test. */ @@ -1583,4 +1854,6 @@ DEFINE_TEST(test_read_disk_directory_traversals) test_callbacks(); /* Test nodump. */ test_nodump(); + /* Test parent overshoot. */ + test_parent(); } |