uint8_t solid : 1; /* Is this a solid stream? */
uint8_t service : 1; /* Is this file a service data? */
uint8_t eof : 1; /* Did we finish unpacking the file? */
+ uint8_t dir : 1; /* Is this file entry a directory? */
/* Optional time fields. */
uint64_t e_mtime;
size_t name_size = 0;
uint64_t unpacked_size;
uint32_t mtime = 0, crc = 0;
- int c_method = 0, c_version = 0, is_dir;
+ int c_method = 0, c_version = 0;
char name_utf8_buf[MAX_NAME_IN_BYTES];
const uint8_t* p;
return ARCHIVE_FATAL;
}
- is_dir = (int) (file_flags & DIRECTORY);
+ rar->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);
if(!read_var_sized(a, &file_attr, NULL))
return ARCHIVE_EOF;
c_method = (int) (compression_info >> 7) & 0x7;
c_version = (int) (compression_info & 0x3f);
- rar->cstate.window_size = is_dir ?
+ rar->cstate.window_size = (rar->file.dir > 0) ?
0 :
g_unpack_window_size << ((compression_info >> 10) & 15);
rar->cstate.method = c_method;
rar->cstate.window_mask = 0;
free(rar->cstate.window_buf);
-
free(rar->cstate.filtered_buf);
- rar->cstate.window_buf = calloc(1, rar->cstate.window_size);
- rar->cstate.filtered_buf = calloc(1, rar->cstate.window_size);
+ if(rar->cstate.window_size > 0) {
+ rar->cstate.window_buf = calloc(1, rar->cstate.window_size);
+ rar->cstate.filtered_buf = calloc(1, rar->cstate.window_size);
+ } else {
+ rar->cstate.window_buf = NULL;
+ rar->cstate.filtered_buf = NULL;
+ }
rar->cstate.write_ptr = 0;
rar->cstate.last_write_ptr = 0;
int ret;
struct rar5* rar = get_context(a);
+ if(rar->file.dir > 0) {
+ /* Don't process any data if this file entry was declared
+ * as a directory. This is needed, because entries marked as
+ * directory doesn't have any dictionary buffer allocated, so
+ * it's impossible to perform any decompression. */
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Can't decompress an entry marked as a directory");
+ return ARCHIVE_FAILED;
+ }
+
if(!rar->skip_mode && (rar->cstate.last_write_ptr > rar->file.unpacked_size)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Unpacker has written too many bytes");
struct rar5* rar = get_context(a);
free(rar->cstate.window_buf);
-
free(rar->cstate.filtered_buf);
free(rar->vol.push_buf);
assertA(0 == archive_read_next_header(a, &ae));
/* This archive is invalid. However, processing it shouldn't cause any
* buffer overflow errors during reading rar5 tables. */
- assertA(0 == archive_read_data(a, buf, sizeof(buf)));
- assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+ assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
+
+ /* This test only cares about not returning success here. */
+ assertA(ARCHIVE_OK != archive_read_next_header(a, &ae));
EPILOGUE();
}
assertA(0 == archive_read_next_header(a, &ae));
/* This archive is invalid. However, processing it shouldn't cause any
* errors related to undefined operations when using -fsanitize. */
- assertA(ARCHIVE_FATAL == archive_read_data(a, buf, sizeof(buf)));
- assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+ assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
+
+ /* This test only cares about not returning success here. */
+ assertA(ARCHIVE_OK != archive_read_next_header(a, &ae));
EPILOGUE();
}
PROLOGUE("test_read_format_rar5_leftshift2.rar");
assertA(0 == archive_read_next_header(a, &ae));
+
/* This archive is invalid. However, processing it shouldn't cause any
* errors related to undefined operations when using -fsanitize. */
- assertA(ARCHIVE_FATAL == archive_read_data(a, buf, sizeof(buf)));
- assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+ assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
+
+ /* This test only cares about not returning success here. */
+ assertA(ARCHIVE_OK != archive_read_next_header(a, &ae));
EPILOGUE();
}
PROLOGUE("test_read_format_rar5_truncated_huff.rar");
assertA(0 == archive_read_next_header(a, &ae));
+
/* This archive is invalid. However, processing it shouldn't cause any
* errors related to undefined operations when using -fsanitize. */
- assertA(ARCHIVE_FATAL == archive_read_data(a, buf, sizeof(buf)));
- assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
+ assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
+
+ /* This test only cares about not returning success here. */
+ assertA(ARCHIVE_OK != archive_read_next_header(a, &ae));
EPILOGUE();
}
PROLOGUE("test_read_format_rar5_invalid_dict_reference.rar");
assertA(0 == archive_read_next_header(a, &ae));
+
/* This archive is invalid. However, processing it shouldn't cause any
* errors related to buffer underflow when using -fsanitize. */
- assertA(ARCHIVE_FATAL == archive_read_data(a, buf, sizeof(buf)));
- assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+ assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
+
+ /* This test only cares about not returning success here. */
+ assertA(ARCHIVE_OK != archive_read_next_header(a, &ae));
EPILOGUE();
}
PROLOGUE("test_read_format_rar5_distance_overflow.rar");
assertA(0 == archive_read_next_header(a, &ae));
+
/* This archive is invalid. However, processing it shouldn't cause any
* errors related to variable overflows when using -fsanitize. */
- assertA(ARCHIVE_FATAL == archive_read_data(a, buf, sizeof(buf)));
- assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+ assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
+
+ /* This test only cares about not returning success here. */
+ assertA(ARCHIVE_OK != archive_read_next_header(a, &ae));
+
+ EPILOGUE();
+}
+
+DEFINE_TEST(test_read_format_rar5_nonempty_dir_stream)
+{
+ uint8_t buf[16];
+
+ PROLOGUE("test_read_format_rar5_nonempty_dir_stream.rar");
+
+ assertA(0 == archive_read_next_header(a, &ae));
+
+ /* This archive is invalid. However, processing it shouldn't cause any
+ * errors related to buffer overflows when using -fsanitize. */
+ assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
+
+ /* This test only cares about not returning success here. */
+ assertA(ARCHIVE_OK != archive_read_next_header(a, &ae));
EPILOGUE();
}