Vendor changes (relevant to FreeBSD): - bugfixes, improvemens and optimizations in ACL code - NFSv4 ACLs can now be extracted from Solaris tar archives Security fixes: - cab reader: endless loop when parsing MSZIP signature (OSS-Fuzz 335) - LHA reader: heap-buffer-overflow in lha_read_file_header_1() (CVE-2017-5601) - LZ4 reader: null-pointer dereference in lz4_filter_read_legacy_stream() (OSS-Fuzz 453) - mtree reader: heap-buffer-overflow in detect_form() (OSS-Fuzz 421, 443) - WARC reader: heap-buffer-overflow in xstrpisotime() (OSS-Fuzz 382, 458) Memory leak fixes: - ACL support: free memory allocated by acl_get_qualifier() - disk writer: missing free in create_filesystem_object() - file reader: fd leak (Coverity 1016755) - gnutar writer: fix free in archive_write_gnutar_header() (Coverity 1016752) - iso 9660 reader: missing free in parse_file_info() (part. Coverity 1016754) - program reader: missing free in __archive_read_program() - program writer: missing free in __archive_write_program_free() - xar reader: missing free in xar_cleanup() - xar reader: missing frees in expat_xmlattr_setup() (Coverity 1229979-1229981) - xar writer: missing free in file_free() - zip reader: missing free in zip_read_locazip_read_local_file_header()
432 lines
11 KiB
C
432 lines
11 KiB
C
/*-
|
|
* Copyright (c) 2011 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 __LIBARCHIVE_TEST
|
|
#include "archive_string.h"
|
|
|
|
#define EXTENT 32
|
|
|
|
#define assertStringSizes(strlen, buflen, as) \
|
|
assertEqualInt(strlen, (as).length); \
|
|
assertEqualInt(buflen, (as).buffer_length);
|
|
|
|
#define assertExactString(strlen, buflen, data, as) \
|
|
do { \
|
|
assertStringSizes(strlen, buflen, as); \
|
|
assertEqualString(data, (as).s); \
|
|
} while (0)
|
|
|
|
#define assertNonNULLString(strlen, buflen, as) \
|
|
do { \
|
|
assertStringSizes(strlen, buflen, as); \
|
|
assert(NULL != (as).s); \
|
|
} while (0)
|
|
|
|
static void
|
|
test_archive_string_ensure(void)
|
|
{
|
|
struct archive_string s;
|
|
|
|
archive_string_init(&s);
|
|
assertExactString(0, 0, NULL, s);
|
|
|
|
/* single-extent allocation */
|
|
assert(&s == archive_string_ensure(&s, 5));
|
|
assertNonNULLString(0, EXTENT, s);
|
|
|
|
/* what happens around extent boundaries? */
|
|
assert(&s == archive_string_ensure(&s, EXTENT - 1));
|
|
assertNonNULLString(0, EXTENT, s);
|
|
|
|
assert(&s == archive_string_ensure(&s, EXTENT));
|
|
assertNonNULLString(0, EXTENT, s);
|
|
|
|
assert(&s == archive_string_ensure(&s, EXTENT + 1));
|
|
assertNonNULLString(0, 2 * EXTENT, s);
|
|
|
|
archive_string_free(&s);
|
|
}
|
|
|
|
static void
|
|
test_archive_strcat(void)
|
|
{
|
|
struct archive_string s;
|
|
|
|
archive_string_init(&s);
|
|
assertExactString(0, 0, NULL, s);
|
|
|
|
/* null target, empty source */
|
|
assert(&s == archive_strcat(&s, ""));
|
|
assertExactString(0, EXTENT, "", s);
|
|
|
|
/* empty target, empty source */
|
|
assert(&s == archive_strcat(&s, ""));
|
|
assertExactString(0, EXTENT, "", s);
|
|
|
|
/* empty target, non-empty source */
|
|
assert(&s == archive_strcat(&s, "fubar"));
|
|
assertExactString(5, EXTENT, "fubar", s);
|
|
|
|
/* non-empty target, non-empty source */
|
|
assert(&s == archive_strcat(&s, "baz"));
|
|
assertExactString(8, EXTENT, "fubarbaz", s);
|
|
|
|
archive_string_free(&s);
|
|
}
|
|
|
|
static void
|
|
test_archive_strappend_char(void)
|
|
{
|
|
struct archive_string s;
|
|
|
|
archive_string_init(&s);
|
|
assertExactString(0, 0, NULL, s);
|
|
|
|
/* null target */
|
|
archive_strappend_char(&s, 'X');
|
|
assertExactString(1, EXTENT, "X", s);
|
|
|
|
/* non-empty target */
|
|
archive_strappend_char(&s, 'Y');
|
|
assertExactString(2, EXTENT, "XY", s);
|
|
|
|
archive_string_free(&s);
|
|
}
|
|
|
|
/* archive_strnXXX() tests focus on length handling.
|
|
* other behaviors are tested by proxy through archive_strXXX()
|
|
*/
|
|
|
|
static void
|
|
test_archive_strncat(void)
|
|
{
|
|
struct archive_string s;
|
|
|
|
archive_string_init(&s);
|
|
assertExactString(0, 0, NULL, s);
|
|
|
|
/* perfect length */
|
|
assert(&s == archive_strncat(&s, "snafu", 5));
|
|
assertExactString(5, EXTENT, "snafu", s);
|
|
|
|
/* short read */
|
|
assert(&s == archive_strncat(&s, "barbazqux", 3));
|
|
assertExactString(8, EXTENT, "snafubar", s);
|
|
|
|
/* long read is ok too! */
|
|
assert(&s == archive_strncat(&s, "snafu", 8));
|
|
assertExactString(13, EXTENT, "snafubarsnafu", s);
|
|
|
|
archive_string_free(&s);
|
|
}
|
|
|
|
static void
|
|
test_archive_strncpy(void)
|
|
{
|
|
struct archive_string s;
|
|
|
|
archive_string_init(&s);
|
|
assertExactString(0, 0, NULL, s);
|
|
|
|
/* perfect length */
|
|
assert(&s == archive_strncpy(&s, "fubar", 5));
|
|
assertExactString(5, EXTENT, "fubar", s);
|
|
|
|
/* short read */
|
|
assert(&s == archive_strncpy(&s, "snafubar", 5));
|
|
assertExactString(5, EXTENT, "snafu", s);
|
|
|
|
/* long read is ok too! */
|
|
assert(&s == archive_strncpy(&s, "snafu", 8));
|
|
assertExactString(5, EXTENT, "snafu", s);
|
|
|
|
archive_string_free(&s);
|
|
}
|
|
|
|
static void
|
|
test_archive_strcpy(void)
|
|
{
|
|
struct archive_string s;
|
|
|
|
archive_string_init(&s);
|
|
assertExactString(0, 0, NULL, s);
|
|
|
|
/* null target */
|
|
assert(&s == archive_strcpy(&s, "snafu"));
|
|
assertExactString(5, EXTENT, "snafu", s);
|
|
|
|
/* dirty target */
|
|
assert(&s == archive_strcpy(&s, "foo"));
|
|
assertExactString(3, EXTENT, "foo", s);
|
|
|
|
/* dirty target, empty source */
|
|
assert(&s == archive_strcpy(&s, ""));
|
|
assertExactString(0, EXTENT, "", s);
|
|
|
|
archive_string_free(&s);
|
|
}
|
|
|
|
static void
|
|
test_archive_string_concat(void)
|
|
{
|
|
struct archive_string s, t, u, v;
|
|
|
|
archive_string_init(&s);
|
|
assertExactString(0, 0, NULL, s);
|
|
archive_string_init(&t);
|
|
assertExactString(0, 0, NULL, t);
|
|
archive_string_init(&u);
|
|
assertExactString(0, 0, NULL, u);
|
|
archive_string_init(&v);
|
|
assertExactString(0, 0, NULL, v);
|
|
|
|
/* null target, null source */
|
|
archive_string_concat(&t, &s);
|
|
assertExactString(0, 0, NULL, s);
|
|
assertExactString(0, EXTENT, "", t);
|
|
|
|
/* null target, empty source */
|
|
assert(&s == archive_strcpy(&s, ""));
|
|
archive_string_concat(&u, &s);
|
|
assertExactString(0, EXTENT, "", s);
|
|
assertExactString(0, EXTENT, "", u);
|
|
|
|
/* null target, non-empty source */
|
|
assert(&s == archive_strcpy(&s, "foo"));
|
|
archive_string_concat(&v, &s);
|
|
assertExactString(3, EXTENT, "foo", s);
|
|
assertExactString(3, EXTENT, "foo", v);
|
|
|
|
/* empty target, empty source */
|
|
assert(&s == archive_strcpy(&s, ""));
|
|
assert(&t == archive_strcpy(&t, ""));
|
|
archive_string_concat(&t, &s);
|
|
assertExactString(0, EXTENT, "", s);
|
|
assertExactString(0, EXTENT, "", t);
|
|
|
|
/* empty target, non-empty source */
|
|
assert(&s == archive_strcpy(&s, "snafu"));
|
|
assert(&t == archive_strcpy(&t, ""));
|
|
archive_string_concat(&t, &s);
|
|
assertExactString(5, EXTENT, "snafu", s);
|
|
assertExactString(5, EXTENT, "snafu", t);
|
|
|
|
archive_string_free(&v);
|
|
archive_string_free(&u);
|
|
archive_string_free(&t);
|
|
archive_string_free(&s);
|
|
}
|
|
|
|
static void
|
|
test_archive_string_copy(void)
|
|
{
|
|
struct archive_string s, t, u, v;
|
|
|
|
archive_string_init(&s);
|
|
assertExactString(0, 0, NULL, s);
|
|
archive_string_init(&t);
|
|
assertExactString(0, 0, NULL, t);
|
|
archive_string_init(&u);
|
|
assertExactString(0, 0, NULL, u);
|
|
archive_string_init(&v);
|
|
assertExactString(0, 0, NULL, v);
|
|
|
|
/* null target, null source */
|
|
archive_string_copy(&t, &s);
|
|
assertExactString(0, 0, NULL, s);
|
|
assertExactString(0, EXTENT, "", t);
|
|
|
|
/* null target, empty source */
|
|
archive_string_copy(&u, &t);
|
|
assertExactString(0, EXTENT, "", t);
|
|
assertExactString(0, EXTENT, "", u);
|
|
|
|
/* empty target, empty source */
|
|
archive_string_copy(&u, &t);
|
|
assertExactString(0, EXTENT, "", t);
|
|
assertExactString(0, EXTENT, "", u);
|
|
|
|
/* null target, non-empty source */
|
|
assert(NULL != archive_strcpy(&s, "snafubar"));
|
|
assertExactString(8, EXTENT, "snafubar", s);
|
|
|
|
archive_string_copy(&v, &s);
|
|
assertExactString(8, EXTENT, "snafubar", s);
|
|
assertExactString(8, EXTENT, "snafubar", v);
|
|
|
|
/* empty target, non-empty source */
|
|
assertExactString(0, EXTENT, "", t);
|
|
archive_string_copy(&t, &s);
|
|
assertExactString(8, EXTENT, "snafubar", s);
|
|
assertExactString(8, EXTENT, "snafubar", t);
|
|
|
|
/* non-empty target, non-empty source */
|
|
assert(NULL != archive_strcpy(&s, "fubar"));
|
|
assertExactString(5, EXTENT, "fubar", s);
|
|
|
|
archive_string_copy(&t, &s);
|
|
assertExactString(5, EXTENT, "fubar", s);
|
|
assertExactString(5, EXTENT, "fubar", t);
|
|
|
|
archive_string_free(&v);
|
|
archive_string_free(&u);
|
|
archive_string_free(&t);
|
|
archive_string_free(&s);
|
|
}
|
|
|
|
static void
|
|
test_archive_string_sprintf(void)
|
|
{
|
|
struct archive_string s;
|
|
#define S16 "0123456789abcdef"
|
|
#define S32 S16 S16
|
|
#define S64 S32 S32
|
|
#define S128 S64 S64
|
|
const char *s32 = S32;
|
|
const char *s33 = S32 "0";
|
|
const char *s64 = S64;
|
|
const char *s65 = S64 "0";
|
|
const char *s128 = S128;
|
|
const char *s129 = S128 "0";
|
|
#undef S16
|
|
#undef S32
|
|
#undef S64
|
|
#undef S128
|
|
|
|
archive_string_init(&s);
|
|
assertExactString(0, 0, NULL, s);
|
|
|
|
archive_string_sprintf(&s, "%s", "");
|
|
assertExactString(0, 2 * EXTENT, "", s);
|
|
|
|
archive_string_empty(&s);
|
|
archive_string_sprintf(&s, "%s", s32);
|
|
assertExactString(32, 2 * EXTENT, s32, s);
|
|
|
|
archive_string_empty(&s);
|
|
archive_string_sprintf(&s, "%s", s33);
|
|
assertExactString(33, 2 * EXTENT, s33, s);
|
|
|
|
archive_string_empty(&s);
|
|
archive_string_sprintf(&s, "%s", s64);
|
|
assertExactString(64, 4 * EXTENT, s64, s);
|
|
|
|
archive_string_empty(&s);
|
|
archive_string_sprintf(&s, "%s", s65);
|
|
assertExactString(65, 4 * EXTENT, s65, s);
|
|
|
|
archive_string_empty(&s);
|
|
archive_string_sprintf(&s, "%s", s128);
|
|
assertExactString(128, 8 * EXTENT, s128, s);
|
|
|
|
archive_string_empty(&s);
|
|
archive_string_sprintf(&s, "%s", s129);
|
|
assertExactString(129, 8 * EXTENT, s129, s);
|
|
|
|
archive_string_empty(&s);
|
|
archive_string_sprintf(&s, "%d", 1234567890);
|
|
assertExactString(10, 8 * EXTENT, "1234567890", s);
|
|
|
|
archive_string_free(&s);
|
|
}
|
|
|
|
DEFINE_TEST(test_archive_string)
|
|
{
|
|
test_archive_string_ensure();
|
|
test_archive_strcat();
|
|
test_archive_strappend_char();
|
|
test_archive_strncat();
|
|
test_archive_strncpy();
|
|
test_archive_strcpy();
|
|
test_archive_string_concat();
|
|
test_archive_string_copy();
|
|
test_archive_string_sprintf();
|
|
}
|
|
|
|
static const char *strings[] =
|
|
{
|
|
"dir/path",
|
|
"dir/path2",
|
|
"dir/path3",
|
|
"dir/path4",
|
|
"dir/path5",
|
|
"dir/path6",
|
|
"dir/path7",
|
|
"dir/path8",
|
|
"dir/path9",
|
|
"dir/subdir/path",
|
|
"dir/subdir/path2",
|
|
"dir/subdir/path3",
|
|
"dir/subdir/path4",
|
|
"dir/subdir/path5",
|
|
"dir/subdir/path6",
|
|
"dir/subdir/path7",
|
|
"dir/subdir/path8",
|
|
"dir/subdir/path9",
|
|
"dir2/path",
|
|
"dir2/path2",
|
|
"dir2/path3",
|
|
"dir2/path4",
|
|
"dir2/path5",
|
|
"dir2/path6",
|
|
"dir2/path7",
|
|
"dir2/path8",
|
|
"dir2/path9",
|
|
NULL
|
|
};
|
|
|
|
DEFINE_TEST(test_archive_string_sort)
|
|
{
|
|
unsigned int i, j, size;
|
|
char **test_strings, *tmp;
|
|
|
|
srand((unsigned int)time(NULL));
|
|
size = sizeof(strings) / sizeof(char *);
|
|
assert((test_strings = (char **)calloc(1, sizeof(strings))) != NULL);
|
|
for (i = 0; i < (size - 1); i++)
|
|
assert((test_strings[i] = strdup(strings[i])) != NULL);
|
|
|
|
/* Shuffle the test strings */
|
|
for (i = 0; i < (size - 1); i++)
|
|
{
|
|
j = rand() % ((size - 1) - i);
|
|
j += i;
|
|
tmp = test_strings[i];
|
|
test_strings[i] = test_strings[j];
|
|
test_strings[j] = tmp;
|
|
}
|
|
|
|
/* Sort and test */
|
|
assertEqualInt(ARCHIVE_OK, archive_utility_string_sort(test_strings));
|
|
for (i = 0; i < (size - 1); i++)
|
|
assertEqualString(test_strings[i], strings[i]);
|
|
|
|
for (i = 0; i < (size - 1); i++)
|
|
free(test_strings[i]);
|
|
free(test_strings);
|
|
}
|