Compare commits

...
6 Commits
Author SHA1 Message Date
Martin Matuska 673c1eae89 Release 3.5.3 2022-02-08 08:18:49 +01:00
Martin Matuška e346721205 Merge pull request #1493 from antekone/rar5_ossfuzz_30459
RAR5 reader: add more checks for invalid extraction parameters
2022-02-08 08:18:03 +01:00
Martin Matuška 05591dd516 Merge pull request #1491 from antekone/rar5_ossfuzz_30442
RAR5 reader: fix invalid memory access in some files
2022-02-08 00:32:14 +01:00
Martin Matuška bcc48ee860 Merge pull request #1492 from antekone/rar5_ossfuzz_30448
RAR5 reader: fixed out of bounds read in some files
2022-02-08 00:31:56 +01:00
Martin Matuska 9516eda33d archive_write_disk_posix: fix writing fflags broken in 8a1bd5c
The fixup list was erroneously assumed to be directories only.
Only in the case of critical file flags modification (e.g. SF_IMMUTABLE
on BSD systems), other file types (e.g. regular files or symbolic links)
may be added to the fixup list. We still need to verify that we are writing
to the correct file type, so compare the archive entry file type with
the file type of the file to be modified.

Fixes #1617
2022-02-08 00:30:50 +01:00
Martin Matuska 4f8ad2f107 Fix following symlinks when processing the fixup list
The previous fix in b41daecb5 was incomplete. Fixup entries are
given the original path without calling cleanup_pathname().
To make sure we don't follow a symlink, we must strip trailing
slashes from the path.

The fixup entries are always directories. Make sure we try to modify
only directories by providing O_DIRECTORY to open() (if supported)
and if it fails to check directory via lstat().

Fixes #1566
2022-02-08 00:30:43 +01:00
13 changed files with 326 additions and 86 deletions

No files matched your search

+1 -1
View File
@@ -18,7 +18,7 @@ endif()
# RelWithDebInfo : Release build with Debug Info
# MinSizeRel : Release Min Size build
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build Type" FORCE)
SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE)
ENDIF(NOT CMAKE_BUILD_TYPE)
# Set a value type to properly display CMAKE_BUILD_TYPE on GUI if the
# value type is "UNINITIALIZED".
+3
View File
@@ -887,6 +887,9 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_rar5_arm_filter_on_window_boundary.rar.uu \
libarchive/test/test_read_format_rar5_different_winsize_on_merge.rar.uu \
libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu \
libarchive/test/test_read_format_rar5_decode_number_out_of_bounds_read.rar.uu \
libarchive/test/test_read_format_rar5_window_buf_and_size_desync.rar.uu \
libarchive/test/test_read_format_rar5_bad_window_sz_in_mltarc_file.rar.uu \
libarchive/test/test_read_format_raw.bufr.uu \
libarchive/test/test_read_format_raw.data.gz.uu \
libarchive/test/test_read_format_raw.data.Z.uu \
+2
View File
@@ -1,3 +1,5 @@
Feb 08, 2022: libarchive 3.5.3 released
Aug 22, 2021: libarchive 3.5.2 released
Dec 26, 2020: libarchive 3.5.1 released
+1 -1
View File
@@ -1 +1 @@
3005003dev
3005003
+1 -1
View File
@@ -4,7 +4,7 @@ dnl First, define all of the version numbers up front.
dnl In particular, this allows the version macro to be used in AC_INIT
dnl These first two version numbers are updated automatically on each release.
m4_define([LIBARCHIVE_VERSION_S],[3.5.3dev])
m4_define([LIBARCHIVE_VERSION_S],[3.5.3])
m4_define([LIBARCHIVE_VERSION_N],[3005003])
dnl bsdtar and bsdcpio versioning tracks libarchive
+1 -1
View File
@@ -155,7 +155,7 @@ __LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
#define ARCHIVE_VERSION_ONLY_STRING "3.5.3dev"
#define ARCHIVE_VERSION_ONLY_STRING "3.5.3"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
+93 -52
View File
@@ -1012,7 +1012,16 @@ static int read_var_sized(struct archive_read* a, size_t* pvalue,
return ret;
}
static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) {
static int read_bits_32(struct archive_read* a, struct rar5* rar,
const uint8_t* p, uint32_t* value)
{
if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Premature end of stream during extraction of data (#1)");
return ARCHIVE_FATAL;
}
uint32_t bits = ((uint32_t) p[rar->bits.in_addr]) << 24;
bits |= p[rar->bits.in_addr + 1] << 16;
bits |= p[rar->bits.in_addr + 2] << 8;
@@ -1023,7 +1032,16 @@ static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) {
return ARCHIVE_OK;
}
static int read_bits_16(struct rar5* rar, const uint8_t* p, uint16_t* value) {
static int read_bits_16(struct archive_read* a, struct rar5* rar,
const uint8_t* p, uint16_t* value)
{
if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Premature end of stream during extraction of data (#2)");
return ARCHIVE_FATAL;
}
int bits = (int) ((uint32_t) p[rar->bits.in_addr]) << 16;
bits |= (int) p[rar->bits.in_addr + 1] << 8;
bits |= (int) p[rar->bits.in_addr + 2];
@@ -1039,8 +1057,8 @@ static void skip_bits(struct rar5* rar, int bits) {
}
/* n = up to 16 */
static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n,
int* value)
static int read_consume_bits(struct archive_read* a, struct rar5* rar,
const uint8_t* p, int n, int* value)
{
uint16_t v;
int ret, num;
@@ -1051,7 +1069,7 @@ static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n,
return ARCHIVE_FATAL;
}
ret = read_bits_16(rar, p, &v);
ret = read_bits_16(a, rar, p, &v);
if(ret != ARCHIVE_OK)
return ret;
@@ -1712,14 +1730,29 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
}
}
/* If we're currently switching volumes, ignore the new definition of
* window_size. */
if(rar->cstate.switch_multivolume == 0) {
/* Values up to 64M should fit into ssize_t on every
* architecture. */
rar->cstate.window_size = (ssize_t) window_size;
if(rar->cstate.window_size < (ssize_t) window_size &&
rar->cstate.window_buf)
{
/* If window_buf has been allocated before, reallocate it, so
* that its size will match new window_size. */
uint8_t* new_window_buf =
realloc(rar->cstate.window_buf, window_size);
if(!new_window_buf) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Not enough memory when trying to realloc the window "
"buffer.");
return ARCHIVE_FATAL;
}
rar->cstate.window_buf = new_window_buf;
}
/* Values up to 64M should fit into ssize_t on every
* architecture. */
rar->cstate.window_size = (ssize_t) window_size;
if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {
/* Solid files have to have the same window_size across
whole archive. Remember the window_size parameter
@@ -2425,13 +2458,13 @@ static int create_decode_tables(uint8_t* bit_length,
static int decode_number(struct archive_read* a, struct decode_table* table,
const uint8_t* p, uint16_t* num)
{
int i, bits, dist;
int i, bits, dist, ret;
uint16_t bitfield;
uint32_t pos;
struct rar5* rar = get_context(a);
if(ARCHIVE_OK != read_bits_16(rar, p, &bitfield)) {
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) {
return ret;
}
bitfield &= 0xfffe;
@@ -2537,14 +2570,6 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
for(i = 0; i < HUFF_TABLE_SIZE;) {
uint16_t num;
if((rar->bits.in_addr + 6) >= rar->cstate.cur_block_size) {
/* Truncated data, can't continue. */
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated data in huffman tables (#2)");
return ARCHIVE_FATAL;
}
ret = decode_number(a, &rar->cstate.bd, p, &num);
if(ret != ARCHIVE_OK) {
archive_set_error(&a->archive,
@@ -2561,8 +2586,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
/* 16..17: repeat previous code */
uint16_t n;
if(ARCHIVE_OK != read_bits_16(rar, p, &n))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
return ret;
if(num == 16) {
n >>= 13;
@@ -2590,8 +2615,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
/* other codes: fill with zeroes `n` times */
uint16_t n;
if(ARCHIVE_OK != read_bits_16(rar, p, &n))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
return ret;
if(num == 18) {
n >>= 13;
@@ -2707,22 +2732,22 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
}
/* Convenience function used during filter processing. */
static int parse_filter_data(struct rar5* rar, const uint8_t* p,
uint32_t* filter_data)
static int parse_filter_data(struct archive_read* a, struct rar5* rar,
const uint8_t* p, uint32_t* filter_data)
{
int i, bytes;
int i, bytes, ret;
uint32_t data = 0;
if(ARCHIVE_OK != read_consume_bits(rar, p, 2, &bytes))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes)))
return ret;
bytes++;
for(i = 0; i < bytes; i++) {
uint16_t byte;
if(ARCHIVE_OK != read_bits_16(rar, p, &byte)) {
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) {
return ret;
}
/* Cast to uint32_t will ensure the shift operation will not
@@ -2765,16 +2790,17 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
uint16_t filter_type;
struct filter_info* filt = NULL;
struct rar5* rar = get_context(ar);
int ret;
/* Read the parameters from the input stream. */
if(ARCHIVE_OK != parse_filter_data(rar, p, &block_start))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start)))
return ret;
if(ARCHIVE_OK != parse_filter_data(rar, p, &block_length))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length)))
return ret;
if(ARCHIVE_OK != read_bits_16(rar, p, &filter_type))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type)))
return ret;
filter_type >>= 13;
skip_bits(rar, 3);
@@ -2814,8 +2840,8 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
if(filter_type == FILTER_DELTA) {
int channels;
if(ARCHIVE_OK != read_consume_bits(rar, p, 5, &channels))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels)))
return ret;
filt->channels = channels + 1;
}
@@ -2823,10 +2849,11 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
return ARCHIVE_OK;
}
static int decode_code_length(struct rar5* rar, const uint8_t* p,
uint16_t code)
static int decode_code_length(struct archive_read* a, struct rar5* rar,
const uint8_t* p, uint16_t code)
{
int lbits, length = 2;
if(code < 8) {
lbits = 0;
length += code;
@@ -2838,7 +2865,7 @@ static int decode_code_length(struct rar5* rar, const uint8_t* p,
if(lbits > 0) {
int add;
if(ARCHIVE_OK != read_consume_bits(rar, p, lbits, &add))
if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add))
return -1;
length += add;
@@ -2933,7 +2960,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
continue;
} else if(num >= 262) {
uint16_t dist_slot;
int len = decode_code_length(rar, p, num - 262),
int len = decode_code_length(a, rar, p, num - 262),
dbits,
dist = 1;
@@ -2975,12 +3002,12 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
uint16_t low_dist;
if(dbits > 4) {
if(ARCHIVE_OK != read_bits_32(
rar, p, &add)) {
if(ARCHIVE_OK != (ret = read_bits_32(
a, rar, p, &add))) {
/* Return EOF if we
* can't read more
* data. */
return ARCHIVE_EOF;
return ret;
}
skip_bits(rar, dbits - 4);
@@ -3015,11 +3042,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
/* dbits is one of [0,1,2,3] */
int add;
if(ARCHIVE_OK != read_consume_bits(rar,
p, dbits, &add)) {
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar,
p, dbits, &add))) {
/* Return EOF if we can't read
* more data. */
return ARCHIVE_EOF;
return ret;
}
dist += add;
@@ -3076,7 +3103,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
return ARCHIVE_FATAL;
}
len = decode_code_length(rar, p, len_slot);
len = decode_code_length(a, rar, p, len_slot);
if (len == -1) {
return ARCHIVE_FATAL;
}
rar->cstate.last_len = len;
if(ARCHIVE_OK != copy_string(a, len, dist))
@@ -3600,6 +3631,16 @@ static int do_uncompress_file(struct archive_read* a) {
rar->cstate.initialized = 1;
}
/* Don't allow extraction if window_size is invalid. */
if(rar->cstate.window_size == 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid window size declaration in this file");
/* This should never happen in valid files. */
return ARCHIVE_FATAL;
}
if(rar->cstate.all_filters_applied == 1) {
/* We use while(1) here, but standard case allows for just 1
* iteration. The loop will iterate if process_block() didn't
+108 -21
View File
@@ -173,6 +173,7 @@ struct fixup_entry {
struct fixup_entry *next;
struct archive_acl acl;
mode_t mode;
__LA_MODE_T filetype;
int64_t atime;
int64_t birthtime;
int64_t mtime;
@@ -357,6 +358,7 @@ struct archive_write_disk {
static int la_opendirat(int, const char *);
static int la_mktemp(struct archive_write_disk *);
static int la_verify_filetype(mode_t, __LA_MODE_T);
static void fsobj_error(int *, struct archive_string *, int, const char *,
const char *);
static int check_symlinks_fsobj(char *, int *, struct archive_string *,
@@ -464,6 +466,39 @@ la_opendirat(int fd, const char *path) {
#endif
}
static int
la_verify_filetype(mode_t mode, __LA_MODE_T filetype) {
int ret = 0;
switch (filetype) {
case AE_IFREG:
ret = (S_ISREG(mode));
break;
case AE_IFDIR:
ret = (S_ISDIR(mode));
break;
case AE_IFLNK:
ret = (S_ISLNK(mode));
break;
case AE_IFSOCK:
ret = (S_ISSOCK(mode));
break;
case AE_IFCHR:
ret = (S_ISCHR(mode));
break;
case AE_IFBLK:
ret = (S_ISBLK(mode));
break;
case AE_IFIFO:
ret = (S_ISFIFO(mode));
break;
default:
break;
}
return (ret);
}
static int
lazy_stat(struct archive_write_disk *a)
{
@@ -822,6 +857,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
fe = current_fixup(a, archive_entry_pathname(entry));
if (fe == NULL)
return (ARCHIVE_FATAL);
fe->filetype = archive_entry_filetype(entry);
fe->fixup |= TODO_MODE_BASE;
fe->mode = a->mode;
}
@@ -832,6 +868,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
fe = current_fixup(a, archive_entry_pathname(entry));
if (fe == NULL)
return (ARCHIVE_FATAL);
fe->filetype = archive_entry_filetype(entry);
fe->mode = a->mode;
fe->fixup |= TODO_TIMES;
if (archive_entry_atime_is_set(entry)) {
@@ -865,6 +902,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
fe = current_fixup(a, archive_entry_pathname(entry));
if (fe == NULL)
return (ARCHIVE_FATAL);
fe->filetype = archive_entry_filetype(entry);
fe->fixup |= TODO_ACLS;
archive_acl_copy(&fe->acl, archive_entry_acl(entry));
}
@@ -877,6 +915,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
fe = current_fixup(a, archive_entry_pathname(entry));
if (fe == NULL)
return (ARCHIVE_FATAL);
fe->filetype = archive_entry_filetype(entry);
fe->mac_metadata = malloc(metadata_size);
if (fe->mac_metadata != NULL) {
memcpy(fe->mac_metadata, metadata,
@@ -891,6 +930,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
fe = current_fixup(a, archive_entry_pathname(entry));
if (fe == NULL)
return (ARCHIVE_FATAL);
fe->filetype = archive_entry_filetype(entry);
fe->fixup |= TODO_FFLAGS;
/* TODO: Complete this.. defer fflags from below. */
}
@@ -2462,7 +2502,8 @@ _archive_write_disk_close(struct archive *_a)
struct archive_write_disk *a = (struct archive_write_disk *)_a;
struct fixup_entry *next, *p;
struct stat st;
int fd, ret;
char *c;
int fd, ret, openflags;
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
@@ -2475,24 +2516,70 @@ _archive_write_disk_close(struct archive *_a)
while (p != NULL) {
fd = -1;
a->pst = NULL; /* Mark stat cache as out-of-date. */
if (p->fixup &
(TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) {
fd = open(p->name,
O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC);
if (fd == -1) {
/* If we cannot lstat, skip entry */
if (lstat(p->name, &st) != 0)
/* We must strip trailing slashes from the path to avoid
dereferencing symbolic links to directories */
c = p->name;
while (*c != '\0')
c++;
while (c != p->name && *(c - 1) == '/') {
c--;
*c = '\0';
}
if (p->fixup == 0)
goto skip_fixup_entry;
else {
/*
* We need to verify if the type of the file
* we are going to open matches the file type
* of the fixup entry.
*/
openflags = O_BINARY | O_NOFOLLOW | O_RDONLY
| O_CLOEXEC;
#if defined(O_DIRECTORY)
if (p->filetype == AE_IFDIR)
openflags |= O_DIRECTORY;
#endif
fd = open(p->name, openflags);
#if defined(O_DIRECTORY)
/*
* If we support O_DIRECTORY and open was
* successful we can skip the file type check
* for directories. For other file types
* we need to verify via fstat() or lstat()
*/
if (fd == -1 || p->filetype != AE_IFDIR) {
#if HAVE_FSTAT
if (fd > 0 && (
fstat(fd, &st) != 0 ||
la_verify_filetype(st.st_mode,
p->filetype) == 0)) {
goto skip_fixup_entry;
} else
#endif
if (lstat(p->name, &st) != 0 ||
la_verify_filetype(st.st_mode,
p->filetype) == 0) {
goto skip_fixup_entry;
/*
* If we deal with a symbolic link, mark
* it in the fixup mode to ensure no
* modifications are made to its target.
*/
if (S_ISLNK(st.st_mode)) {
p->mode &= ~S_IFMT;
p->mode |= S_IFLNK;
}
}
#else
#if HAVE_FSTAT
if (fd > 0 && (
fstat(fd, &st) != 0 ||
la_verify_filetype(st.st_mode,
p->filetype) == 0)) {
goto skip_fixup_entry;
} else
#endif
if (lstat(p->name, &st) != 0 ||
la_verify_filetype(st.st_mode,
p->filetype) == 0) {
goto skip_fixup_entry;
}
#endif
}
if (p->fixup & TODO_TIMES) {
set_times(a, fd, p->mode, p->name,
@@ -2504,14 +2591,13 @@ _archive_write_disk_close(struct archive *_a)
if (p->fixup & TODO_MODE_BASE) {
#ifdef HAVE_FCHMOD
if (fd >= 0)
fchmod(fd, p->mode);
fchmod(fd, p->mode & 07777);
else
#endif
#ifdef HAVE_LCHMOD
lchmod(p->name, p->mode);
lchmod(p->name, p->mode & 07777);
#else
if (!S_ISLNK(p->mode))
chmod(p->name, p->mode);
chmod(p->name, p->mode & 07777);
#endif
}
if (p->fixup & TODO_ACLS)
@@ -2664,7 +2750,7 @@ new_fixup(struct archive_write_disk *a, const char *pathname)
fe->next = a->fixup_list;
a->fixup_list = fe;
fe->fixup = 0;
fe->mode = 0;
fe->filetype = 0;
fe->name = strdup(pathname);
return (fe);
}
@@ -3787,6 +3873,7 @@ set_fflags(struct archive_write_disk *a)
le = current_fixup(a, a->name);
if (le == NULL)
return (ARCHIVE_FATAL);
le->filetype = archive_entry_filetype(a->entry);
le->fixup |= TODO_FFLAGS;
le->fflags_set = set;
/* Store the mode if it's not already there. */
+53
View File
@@ -1206,6 +1206,23 @@ DEFINE_TEST(test_read_format_rar5_different_window_size)
EPILOGUE();
}
DEFINE_TEST(test_read_format_rar5_window_buf_and_size_desync)
{
/* oss fuzz 30442 */
char buf[4096];
PROLOGUE("test_read_format_rar5_window_buf_and_size_desync.rar");
/* Return codes of those calls are ignored, because this sample file
* is invalid. However, the unpacker shouldn't produce any SIGSEGV
* errors during processing. */
(void) archive_read_next_header(a, &ae);
while(0 < archive_read_data(a, buf, 46)) {}
EPILOGUE();
}
DEFINE_TEST(test_read_format_rar5_arm_filter_on_window_boundary)
{
char buf[4096];
@@ -1271,3 +1288,39 @@ DEFINE_TEST(test_read_format_rar5_block_size_is_too_small)
EPILOGUE();
}
DEFINE_TEST(test_read_format_rar5_decode_number_out_of_bounds_read)
{
/* oss fuzz 30448 */
char buf[4096];
PROLOGUE("test_read_format_rar5_decode_number_out_of_bounds_read.rar");
/* Return codes of those calls are ignored, because this sample file
* is invalid. However, the unpacker shouldn't produce any SIGSEGV
* errors during processing. */
(void) archive_read_next_header(a, &ae);
while(0 < archive_read_data(a, buf, sizeof(buf))) {}
EPILOGUE();
}
DEFINE_TEST(test_read_format_rar5_bad_window_size_in_multiarchive_file)
{
/* oss fuzz 30459 */
char buf[4096];
PROLOGUE("test_read_format_rar5_bad_window_sz_in_mltarc_file.rar");
/* This file is damaged, so those functions should return failure.
* Additionally, SIGSEGV shouldn't be raised during execution
* of those functions. */
(void) archive_read_next_header(a, &ae);
while(0 < archive_read_data(a, buf, sizeof(buf))) {}
(void) archive_read_next_header(a, &ae);
while(0 < archive_read_data(a, buf, sizeof(buf))) {}
EPILOGUE();
}
@@ -0,0 +1,7 @@
begin 644 test_read_format_rar5_bad_window_size_in_multiarchive_file.rar
M4F%R(1H'`0`]/-[E`@$`_R`@1#[Z5P("`PL`("`@@"(`"?\@("#___\@("`@
M("`@("`@("`@4X`J]`,"YR(#$($@("`@``$@("`@@<L0("`@("`@("`@("`@
M("`@(""LCTJA`P$%`B`@`2!3@"KT`P+G(@,@("`@_P,!!B`@(/___R`@(('+
5$"`OX2`@[.SL[.S_("`@("`@("`@
`
end
@@ -0,0 +1,10 @@
begin 644 test_read_format_rar5_decode_number_out_of_bounds_read.rar
M4F%R(1H'`0!3@"KT`P+G(@(0("`@@`L!!"`@("`@(($D_[BJ2"!::7!)210V
M+0#ZF#)Q!`+>YPW_("`@("``_R````````````````````````````!__P``
M``````!T72`@/EW_(/\@("`@("`@("`@("`@("`@("`@("`@("`@(/\@("`@
M("`@("#_("`@("`@("`@("`@("`@("`@("`@("`@("#_("`@("`@("`@_R`@
M("`@("`@("`@("`@("`@("`@("`@("`@_R`@("`@("`@(/\@("`@("`@("`@
M("`@("`@("`@("`@("`@(/\@("`@("`@("#_("`@("`@("`@("`@("`@("`@
E("`@("`@("#_("`@("`@("`@_R`@("`@("`@("`@("`@("`@(```
`
end
@@ -0,0 +1,11 @@
begin 644 test_read_format_rar5_window_buf_and_size_desync.rar
M4F%R(1H'`0`]/-[E`@$`_P$`1#[Z5P("`PL``BXB"?\`!(@B@0`)6.-AF?_1
M^0DI&0GG(F%R(0<:)`!3@"KT`P+G(@O_X[\``#&``(?!!0$$[:L``$.M*E)A
M<B$`O<\>P0";/P1%``A*2DI*2DYQ<6TN9'%*2DI*2DI*``!D<F--``````"Z
MNC*ZNKJZNFYO=&%I;+JZNKJZNKJZOKJZ.KJZNKJZNKKZU@4%````0$!`0$!`
M0$!`0$!`0$!`0$#_________/T#`0$!`0$!`-UM`0$!`0$!`0$!`0$!`0$!`
M0$!`0'!,J+:O!IZ-WN4'@`!3*F0`````````````````````````````````
M``````````````#T`P)287(A&@<!`%.`*O0#`N<B`_,F@`'[__\``(`4`01S
J'`/H/O\H@?\D`#O9GIZ>GN<B"_]%``(``&1RGIZ>GIZ>8_^>GE/_``!.
`
end
+35 -9
View File
@@ -47,26 +47,50 @@ DEFINE_TEST(test_write_disk_fixup)
/*
* Create a file
*/
assertMakeFile("victim", 0600, "a");
assertMakeFile("file", 0600, "a");
/*
* Create a directory
*/
assertMakeDir("dir", 0700);
/*
* Create a directory and a symlink with the same name
*/
/* Directory: dir */
/* Directory: dir1 */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir");
archive_entry_set_mode(ae, AE_IFDIR | 0606);
archive_entry_copy_pathname(ae, "dir1/");
archive_entry_set_mode(ae, AE_IFDIR | 0555);
assertEqualIntA(ad, 0, archive_write_header(ad, ae));
assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
archive_entry_free(ae);
/* Symbolic Link: dir -> foo */
/* Directory: dir2 */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir2/");
archive_entry_set_mode(ae, AE_IFDIR | 0555);
assertEqualIntA(ad, 0, archive_write_header(ad, ae));
assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
archive_entry_free(ae);
/* Symbolic Link: dir1 -> dir */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir");
archive_entry_copy_pathname(ae, "dir1");
archive_entry_set_mode(ae, AE_IFLNK | 0777);
archive_entry_set_size(ae, 0);
archive_entry_copy_symlink(ae, "victim");
archive_entry_copy_symlink(ae, "dir");
assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
if (r >= ARCHIVE_WARN)
assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
archive_entry_free(ae);
/* Symbolic Link: dir2 -> file */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir2");
archive_entry_set_mode(ae, AE_IFLNK | 0777);
archive_entry_set_size(ae, 0);
archive_entry_copy_symlink(ae, "file");
assertEqualIntA(ad, 0, r = archive_write_header(ad, ae));
if (r >= ARCHIVE_WARN)
assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
@@ -75,7 +99,9 @@ DEFINE_TEST(test_write_disk_fixup)
assertEqualInt(ARCHIVE_OK, archive_write_free(ad));
/* Test the entries on disk. */
assertIsSymlink("dir", "victim", 0);
assertFileMode("victim", 0600);
assertIsSymlink("dir1", "dir", 0);
assertIsSymlink("dir2", "file", 0);
assertFileMode("dir", 0700);
assertFileMode("file", 0600);
#endif
}