ssize_t zipx_ppmd_read_compressed;
CPpmd8 ppmd8;
char ppmd8_valid;
+ char ppmd8_stream_failed;
struct archive_string_conv *sconv;
struct archive_string_conv *sconv_default;
/* Get the handle to current decompression context. */
struct archive_read *a = ((IByteIn*)p)->a;
struct zip *zip = (struct zip*) a->format->data;
+ ssize_t bytes_avail = 0;
/* Fetch next byte. */
- const uint8_t* data = __archive_read_ahead(a, 1, NULL);
+ const uint8_t* data = __archive_read_ahead(a, 1, &bytes_avail);
+ if(bytes_avail < 1) {
+ zip->ppmd8_stream_failed = 1;
+ return 0;
+ }
+
__archive_read_consume(a, 1);
/* Increment the counter. */
/* Create a new decompression context. */
__archive_ppmd8_functions.Ppmd8_Construct(&zip->ppmd8);
+ zip->ppmd8_stream_failed = 0;
/* Setup function pointers required by Ppmd8 decompressor. The
* 'ppmd_read' function will feed new bytes to the decompressor,
break;
}
+ /* This field is set by ppmd_read() when there was no more data
+ * to be read. */
+ if(zip->ppmd8_stream_failed) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated PPMd8 file body");
+ return (ARCHIVE_FATAL);
+ }
+
zip->uncompressed_buffer[consumed_bytes] = (uint8_t) sym;
++consumed_bytes;
} while(consumed_bytes < zip->uncompressed_buffer_size);
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
}
+
+DEFINE_TEST(test_read_format_zip_ppmd8_crash_1)
+{
+ const char *refname = "test_read_format_zip_ppmd8_crash_2.zipx";
+ struct archive *a;
+ struct archive_entry *ae;
+ char buf[64];
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 37));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+
+ /* The file `refname` is invalid in this case, so this call should fail.
+ * But it shouldn't crash. */
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buf, 64));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_format_zip_ppmd8_crash_2)
+{
+ const char *refname = "test_read_format_zip_ppmd8_crash_2.zipx";
+ struct archive *a;
+ struct archive_entry *ae;
+ char buf[64];
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 37));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+
+ /* The file `refname` is invalid in this case, so this call should fail.
+ * But it shouldn't crash. */
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buf, 64));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+}