If csize (and usize) are 0, like with a directory or other empty file
entry, then the functionionality to record file record information when
indexing the central directory and each associated file record will
neglect to store the `local_header_offset` or `local_header_size`.
That causes problems later after sorting the file records and then
checking for overlapping files.
CLAM-2884
| ... | ... |
@@ -717,17 +717,35 @@ static cl_error_t parse_local_file_header( |
| 717 | 717 |
zip += LOCAL_HEADER_elen; |
| 718 | 718 |
bytes_remaining -= LOCAL_HEADER_elen; |
| 719 | 719 |
|
| 720 |
- if (!csize) { /* FIXME: what's used for method0 files? csize or usize? Nothing in the specs, needs testing */
|
|
| 721 |
- cli_dbgmsg("cli_unzip: local header - skipping empty file\n");
|
|
| 722 |
- } else {
|
|
| 723 |
- if (bytes_remaining < csize) {
|
|
| 724 |
- cli_dbgmsg("cli_unzip: local header - stream out of file\n");
|
|
| 725 |
- status = CL_EPARSE; |
|
| 726 |
- goto done; |
|
| 727 |
- } |
|
| 720 |
+ if (bytes_remaining < csize) {
|
|
| 721 |
+ cli_dbgmsg("cli_unzip: local header - stream out of file\n");
|
|
| 722 |
+ status = CL_EPARSE; |
|
| 723 |
+ goto done; |
|
| 724 |
+ } |
|
| 728 | 725 |
|
| 726 |
+ if (NULL != record) {
|
|
| 729 | 727 |
/* Don't actually unzip if we're just collecting the file record information (offset, sizes) */ |
| 730 |
- if (NULL == record) {
|
|
| 728 |
+ if (NULL == original_filename) {
|
|
| 729 |
+ record->original_filename = NULL; |
|
| 730 |
+ } else {
|
|
| 731 |
+ record->original_filename = CLI_STRNDUP(original_filename, strlen(original_filename)); |
|
| 732 |
+ } |
|
| 733 |
+ record->local_header_offset = loff; |
|
| 734 |
+ record->local_header_size = zip - local_header; |
|
| 735 |
+ record->compressed_size = csize; |
|
| 736 |
+ record->uncompressed_size = usize; |
|
| 737 |
+ record->method = LOCAL_HEADER_method; |
|
| 738 |
+ record->flags = LOCAL_HEADER_flags; |
|
| 739 |
+ record->encrypted = (LOCAL_HEADER_flags & F_ENCR) ? 1 : 0; |
|
| 740 |
+ |
|
| 741 |
+ status = CL_SUCCESS; |
|
| 742 |
+ } else {
|
|
| 743 |
+ /* |
|
| 744 |
+ * Unzip or decompress & then unzip. |
|
| 745 |
+ */ |
|
| 746 |
+ if (!csize) { /* FIXME: what's used for method0 files? csize or usize? Nothing in the specs, needs testing */
|
|
| 747 |
+ cli_dbgmsg("cli_unzip: local header - skipping empty file\n");
|
|
| 748 |
+ } else {
|
|
| 731 | 749 |
zip = fmap_need_ptr_once(ctx->fmap, zip, csize); |
| 732 | 750 |
if (NULL == zip) {
|
| 733 | 751 |
cli_dbgmsg("cli_unzip: local header - data out of file\n");
|
| ... | ... |
@@ -751,27 +769,12 @@ static cl_error_t parse_local_file_header( |
| 751 | 751 |
goto done; |
| 752 | 752 |
} |
| 753 | 753 |
} |
| 754 |
- } else {
|
|
| 755 |
- if (NULL == original_filename) {
|
|
| 756 |
- record->original_filename = NULL; |
|
| 757 |
- } else {
|
|
| 758 |
- record->original_filename = CLI_STRNDUP(original_filename, strlen(original_filename)); |
|
| 759 |
- } |
|
| 760 |
- record->local_header_offset = loff; |
|
| 761 |
- record->local_header_size = zip - local_header; |
|
| 762 |
- record->compressed_size = csize; |
|
| 763 |
- record->uncompressed_size = usize; |
|
| 764 |
- record->method = LOCAL_HEADER_method; |
|
| 765 |
- record->flags = LOCAL_HEADER_flags; |
|
| 766 |
- record->encrypted = (LOCAL_HEADER_flags & F_ENCR) ? 1 : 0; |
|
| 767 |
- |
|
| 768 |
- status = CL_SUCCESS; |
|
| 769 | 754 |
} |
| 770 |
- |
|
| 771 |
- zip += csize; |
|
| 772 |
- bytes_remaining -= csize; |
|
| 773 | 755 |
} |
| 774 | 756 |
|
| 757 |
+ zip += csize; |
|
| 758 |
+ bytes_remaining -= csize; |
|
| 759 |
+ |
|
| 775 | 760 |
if (LOCAL_HEADER_flags & F_USEDD) {
|
| 776 | 761 |
if (bytes_remaining < 12) {
|
| 777 | 762 |
cli_dbgmsg("cli_unzip: local header - data desc out of file\n");
|
| ... | ... |
@@ -910,8 +913,8 @@ static cl_error_t parse_central_directory_file_header( |
| 910 | 910 |
|
| 911 | 911 |
central_header = fmap_need_off(ctx->fmap, central_file_header_offset, SIZEOF_CENTRAL_HEADER); |
| 912 | 912 |
if (NULL == central_header) {
|
| 913 |
- cli_dbgmsg("cli_unzip: central header - file header offset out of file\n");
|
|
| 914 |
- status = CL_EPARSE; |
|
| 913 |
+ cli_dbgmsg("cli_unzip: central header - reached end of central directory.\n");
|
|
| 914 |
+ status = CL_BREAK; |
|
| 915 | 915 |
goto done; |
| 916 | 916 |
} |
| 917 | 917 |
|
| ... | ... |
@@ -1310,7 +1313,8 @@ cl_error_t index_local_file_headers_within_bounds( |
| 1310 | 1310 |
index = *num_records; |
| 1311 | 1311 |
|
| 1312 | 1312 |
if (start_offset > fsize || end_offset > fsize || start_offset > end_offset) {
|
| 1313 |
- cli_errmsg("index_local_file_headers_within_bounds: Invalid offset arguments\n");
|
|
| 1313 |
+ cli_errmsg("index_local_file_headers_within_bounds: Invalid offset arguments: start_offset=%u, end_offset=%u, fsize=%u\n",
|
|
| 1314 |
+ start_offset, end_offset, fsize); |
|
| 1314 | 1315 |
status = CL_EPARSE; |
| 1315 | 1316 |
goto done; |
| 1316 | 1317 |
} |