pure.h (60213B)
1 // pure.h - C99 interface: 2 3 #ifndef PURE_H 4 #define PURE_H 5 6 #include <assert.h> 7 #include <stdint.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <stdio.h> 11 12 #include "pure_constants.h" 13 #include "pure_errors.h" 14 #include "pure_signatures.h" 15 #include "pure_routines.h" 16 17 #include "zlib.h" 18 19 typedef struct pure_ctx { 20 uint64_t flags; 21 uint64_t depth; 22 uint64_t files; 23 uint64_t archives; 24 uint64_t size; 25 uint64_t compressed_size; 26 uint64_t uncompressed_size; 27 } pure_ctx; 28 29 typedef struct pure_zip_lfh { 30 uint64_t offset; 31 uint64_t length; 32 uint64_t version_minimum; 33 uint64_t general_purpose_bit_flag; 34 uint64_t compression_method; 35 uint64_t last_mod_file_time; 36 uint64_t last_mod_file_date; 37 uint64_t crc32; 38 uint64_t compressed_size; 39 uint64_t uncompressed_size; 40 uint8_t* file_name; 41 uint64_t file_name_length; 42 uint8_t* extra_field; 43 uint64_t extra_field_length; 44 uint8_t zip64; 45 } pure_zip_lfh; 46 47 typedef struct pure_zip_ddr { 48 uint64_t offset; 49 uint64_t length; 50 uint64_t crc32; 51 uint64_t compressed_size; 52 uint64_t uncompressed_size; 53 uint8_t zip64; 54 } pure_zip_ddr; 55 56 typedef struct pure_zip_cdh { 57 uint64_t offset; 58 uint64_t length; 59 uint64_t version_made; 60 uint64_t version_minimum; 61 uint64_t general_purpose_bit_flag; 62 uint64_t compression_method; 63 uint64_t last_mod_file_time; 64 uint64_t last_mod_file_date; 65 uint64_t crc32; 66 uint64_t compressed_size; 67 uint64_t uncompressed_size; 68 uint8_t* file_name; 69 uint64_t file_name_length; 70 uint8_t* extra_field; 71 uint64_t extra_field_length; 72 uint8_t* file_comment; 73 uint64_t file_comment_length; 74 uint64_t disk; 75 uint64_t internal_file_attributes; 76 uint64_t external_file_attributes; 77 uint64_t relative_offset; 78 uint64_t unix_mode; 79 uint8_t directory; 80 uint8_t zip64; 81 } pure_zip_cdh; 82 83 typedef struct pure_zip_eocdr_64 { 84 uint64_t offset; 85 uint64_t length; 86 uint64_t version_made; 87 uint64_t version_minimum; 88 uint64_t disk; 89 uint64_t cd_disk; 90 uint64_t cd_disk_records; 91 uint64_t cd_records; 92 uint64_t cd_size; 93 uint64_t cd_offset; 94 uint8_t* extensible_data_sector; 95 uint64_t extensible_data_sector_length; 96 } pure_zip_eocdr_64; 97 98 typedef struct pure_zip_eocdl_64 { 99 uint64_t offset; 100 uint64_t length; 101 uint64_t disk; 102 uint64_t eocdr_64_offset; 103 uint64_t disks; 104 } pure_zip_eocdl_64; 105 106 typedef struct pure_zip_eocdr { 107 uint64_t offset; 108 uint64_t length; 109 uint64_t disk; 110 uint64_t cd_disk; 111 uint64_t cd_disk_records; 112 uint64_t cd_records; 113 uint64_t cd_size; 114 uint64_t cd_offset; 115 uint8_t* comment; 116 uint64_t comment_length; 117 uint8_t zip64; 118 } pure_zip_eocdr; 119 120 int pure_zip_crc32( 121 const uint8_t* buffer, 122 const uint64_t size, 123 uint64_t* result 124 ) { 125 assert(SIZE_MAX >= UINT32_MAX); 126 assert(size <= SIZE_MAX); 127 assert(*result == 0); 128 unsigned long checksum = crc32_z(0UL, Z_NULL, 0); 129 checksum = crc32_z(checksum, buffer, (size_t) size); 130 *result = (uint64_t) checksum; 131 return 0; 132 } 133 134 void pure_zip_debug_lfh(const pure_zip_lfh* header) { 135 printf("LOCAL FILE HEADER:\n"); 136 printf( 137 "offset=%llu length=%llu\n", 138 header->offset, 139 header->length 140 ); 141 printf( 142 "general_purpose_bit_flag=%llu version_minimum=%llu\n", 143 header->general_purpose_bit_flag, 144 header->version_minimum 145 ); 146 printf( 147 "compression_method=%llu last_mod_file_time=%llu last_mod_file_date=%llu\n", 148 header->compression_method, 149 header->last_mod_file_time, 150 header->last_mod_file_date 151 ); 152 printf( 153 "crc32=%llu compressed_size=%llu uncompressed_size=%llu\n", 154 header->crc32, 155 header->compressed_size, 156 header->uncompressed_size 157 ); 158 printf("file_name=\""); 159 fwrite(header->file_name, 1, header->file_name_length, stdout); 160 printf("\"\n"); 161 printf( 162 "file_name_length=%llu extra_field_length=%llu\n", 163 header->file_name_length, 164 header->extra_field_length 165 ); 166 printf("\n"); 167 } 168 169 void pure_zip_debug_ddr(const pure_zip_ddr* header) { 170 printf("DATA DESCRIPTOR RECORD:\n"); 171 printf( 172 "offset=%llu length=%llu\n", 173 header->offset, 174 header->length 175 ); 176 printf( 177 "crc32=%llu compressed_size=%llu uncompressed_size=%llu\n", 178 header->crc32, 179 header->compressed_size, 180 header->uncompressed_size 181 ); 182 printf("\n"); 183 } 184 185 void pure_zip_debug_cdh(const pure_zip_cdh* header) { 186 printf("CENTRAL DIRECTORY HEADER:\n"); 187 printf( 188 "offset=%llu length=%llu\n", 189 header->offset, 190 header->length 191 ); 192 printf( 193 "general_purpose_bit_flag=%llu version_minimum=%llu version_made=%llu\n", 194 header->general_purpose_bit_flag, 195 header->version_minimum, 196 header->version_made 197 ); 198 printf( 199 "compression_method=%llu last_mod_file_time=%llu last_mod_file_date=%llu\n", 200 header->compression_method, 201 header->last_mod_file_time, 202 header->last_mod_file_date 203 ); 204 printf( 205 "crc32=%llu compressed_size=%llu uncompressed_size=%llu\n", 206 header->crc32, 207 header->compressed_size, 208 header->uncompressed_size 209 ); 210 printf("file_name=\""); 211 fwrite(header->file_name, 1, header->file_name_length, stdout); 212 printf("\"\n"); 213 printf( 214 "file_name_length=%llu extra_field_length=%llu file_comment_length=%llu\n", 215 header->file_name_length, 216 header->extra_field_length, 217 header->file_comment_length 218 ); 219 printf("file_comment=\""); 220 fwrite(header->file_comment, 1, header->file_comment_length, stdout); 221 printf("\"\n"); 222 printf( 223 "internal_file_attributes=%llu external_file_attributes=%llu\n", 224 header->internal_file_attributes, 225 header->external_file_attributes 226 ); 227 printf( 228 "disk=%llu relative_offset=%llu\n", 229 header->disk, 230 header->relative_offset 231 ); 232 printf( 233 "unix_mode=%llu directory=%u zip64=%u\n", 234 header->unix_mode, 235 header->directory, 236 header->zip64 237 ); 238 printf("\n"); 239 } 240 241 void pure_zip_debug_eocdl_64(const pure_zip_eocdl_64* header) { 242 printf("ZIP64 END OF CENTRAL DIRECTORY LOCATOR:\n"); 243 printf("offset=%llu\n", header->offset); 244 printf("length=%llu\n", header->length); 245 printf("disk=%llu\n", header->disk); 246 printf("eocdr_64_offset=%llu\n", header->eocdr_64_offset); 247 printf("disks=%llu\n", header->disks); 248 printf("\n"); 249 } 250 251 void pure_zip_debug_eocdr_64(const pure_zip_eocdr_64* header) { 252 printf("ZIP64 END OF CENTRAL DIRECTORY RECORD:\n"); 253 printf("offset=%llu\n", header->offset); 254 printf("length=%llu\n", header->length); 255 printf("version_made=%llu\n", header->version_made); 256 printf("version_minimum=%llu\n", header->version_minimum); 257 printf("disk=%llu\n", header->disk); 258 printf("cd_disk=%llu\n", header->cd_disk); 259 printf("cd_disk_records=%llu\n", header->cd_disk_records); 260 printf("cd_records=%llu\n", header->cd_records); 261 printf("cd_size=%llu\n", header->cd_size); 262 printf("cd_offset=%llu\n", header->cd_offset); 263 printf( 264 "extensible_data_sector_length=%llu\n", 265 header->extensible_data_sector_length 266 ); 267 printf("\n"); 268 } 269 270 void pure_zip_debug_eocdr(const pure_zip_eocdr* header) { 271 printf("END OF CENTRAL DIRECTORY RECORD:\n"); 272 printf("offset=%llu\n", header->offset); 273 printf("length=%llu\n", header->length); 274 printf("disk=%llu\n", header->disk); 275 printf("cd_disk=%llu\n", header->cd_disk); 276 printf("cd_disk_records=%llu\n", header->cd_disk_records); 277 printf("cd_records=%llu\n", header->cd_records); 278 printf("cd_size=%llu\n", header->cd_size); 279 printf("cd_offset=%llu\n", header->cd_offset); 280 printf("comment=\""); 281 fwrite(header->comment, 1, header->comment_length, stdout); 282 printf("\"\n"); 283 printf("comment_length=%llu\n", header->comment_length); 284 printf("\n"); 285 } 286 287 int pure_zip_verify_compression_ratio( 288 const uint64_t compressed_size, 289 const uint64_t uncompressed_size 290 ) { 291 // Here, compressed size and uncompressed size could relate to the respective 292 // sizes of an individual file or the sum of the sizes across an archive. 293 // 294 // We do not use only a ratio limit to detect dangerous compression ratios, 295 // since an extreme ratio can be mitigated by a negligible uncompressed size. 296 // 297 // Instead, we calculate a score that combines the ratio and uncompressed size 298 // and then compare this score against a limit. The higher the ratio and the 299 // larger the uncompressed size, the more dangerous the file or archive. 300 // 301 // Conversely, a file or archive with high ratio but negligible uncompressed 302 // size is less likely to be dangerous, since while it may have high power, 303 // this power is multiplied by less weight. 304 if (compressed_size == 0) return 0; // Prevent divide-by-zero. 305 if (uncompressed_size < PURE_ZIP_COMPRESSION_RATIO_SIZE_MIN) return 0; 306 const uint64_t ratio = uncompressed_size / compressed_size; 307 const uint64_t score = ratio * uncompressed_size; 308 if (score > PURE_ZIP_COMPRESSION_RATIO_SCORE_MAX) { 309 return PURE_E_ZIP_BOMB_RATIO; 310 } 311 return 0; 312 } 313 314 int pure_zip_verify_compression_method(const uint64_t value) { 315 if (value == PURE_ZIP_COMPRESSION_METHOD_NONE) return 0; 316 if (value == PURE_ZIP_COMPRESSION_METHOD_DEFLATE) return 0; 317 // CVE-2016-9844: 318 // Defend vulnerable implementations against overflow when the two-byte 319 // compression method in the central directory file header exceeds 999. 320 // https://bugs.launchpad.net/ubuntu/+source/unzip/+bug/1643750 321 if (value > 999) return PURE_E_ZIP_COMPRESSION_METHOD_DANGEROUS; 322 if (value == 99) return PURE_E_ZIP_COMPRESSION_METHOD_ENCRYPTED; 323 return PURE_E_ZIP_COMPRESSION_METHOD_UNSUPPORTED; 324 } 325 326 int pure_zip_verify_compression_method_sizes( 327 const uint64_t compression_method, 328 const uint64_t compressed_size, 329 const uint64_t uncompressed_size 330 ) { 331 { 332 int error = pure_zip_verify_compression_method(compression_method); 333 if (error) return error; 334 } 335 if (compression_method == 0 && compressed_size != uncompressed_size) { 336 return PURE_E_ZIP_STORED_COMPRESSION_SIZE_MISMATCH; 337 } 338 // CVE-2018-18384: 339 // Defend vulnerable implementations against buffer overflow. 340 // https://bugzilla.suse.com/show_bug.cgi?id=1110194 341 if ( 342 uncompressed_size > 0 && 343 compressed_size > uncompressed_size && 344 compressed_size / uncompressed_size >= 2 345 ) { 346 return PURE_E_ZIP_DANGEROUS_NEGATIVE_COMPRESSION_RATIO; 347 } 348 return 0; 349 } 350 351 int pure_zip_verify_date(const uint64_t value) { 352 /* 353 An MS-DOS date is a packed 16-bit (2 bytes) value in which bits in the value 354 represent the day, month, and year: 355 356 Bits: 0-4 5-8 9-15 357 Unit: Day Month Year 358 Range: 1-31 1-12 Relative to 1980 359 */ 360 if (value > PURE_16_BIT_MAX) return PURE_E_ZIP_DATE_OVERFLOW; 361 uint64_t y = (value >> 9) + 1980; 362 uint64_t m = (value >> 5) & 15; 363 uint64_t d = value & 31; 364 // 7 bits supports up to 127 years, or 2107 (1980 + 127). 365 // However, years after 2099 are not correctly handled by some software: 366 if (y > 2099) return PURE_E_ZIP_DATE_YEAR_OVERFLOW; 367 if (m > 12) return PURE_E_ZIP_DATE_MONTH_OVERFLOW; 368 if (d > 31) return PURE_E_ZIP_DATE_DAY_OVERFLOW; 369 return 0; 370 } 371 372 int pure_zip_verify_directory(const pure_zip_cdh* header) { 373 assert(header->directory == 0 || header->directory == 1); 374 if (header->directory) { 375 if (header->compressed_size > 0) return PURE_E_ZIP_DIRECTORY_COMPRESSED; 376 if (header->uncompressed_size > 0) return PURE_E_ZIP_DIRECTORY_UNCOMPRESSED; 377 } 378 return 0; 379 } 380 381 int pure_zip_verify_disk(const uint64_t value) { 382 if (value != 0) return PURE_E_ZIP_MULTIPLE_DISKS; 383 return 0; 384 } 385 386 int pure_zip_verify_extra_field( 387 const uint8_t* extra_field, 388 const uint64_t extra_field_length, 389 const uint8_t* file_name, 390 const uint64_t file_name_length 391 ) { 392 if (extra_field_length > PURE_ZIP_EXTRA_FIELD_MAX) { 393 return PURE_E_ZIP_EXTRA_FIELD_MAX; 394 } 395 // The extra field contains a variety of optional data such as OS-specific 396 // attributes. It is divided into chunks, each with a 16-bit ID code and a 397 // 16-bit length. 398 if (extra_field_length != 0 && extra_field_length < 4) { 399 return PURE_E_ZIP_EXTRA_FIELD_MIN; 400 } 401 // Check extra field attribute sizes, and specifically the unicode path: 402 uint64_t offset = 0; 403 while (offset + 2 + 2 <= extra_field_length) { 404 const uint16_t id = pure_u16(extra_field + offset + 0); 405 const uint16_t size = pure_u16(extra_field + offset + 2); 406 if (offset + 2 + 2 + size > extra_field_length) { 407 return PURE_E_ZIP_EXTRA_FIELD_ATTRIBUTE_OVERFLOW; 408 } 409 if (id == 0x7075) { 410 // We expect at least a 1-byte version followed by a 4-byte crc32: 411 if (size < 1 + 4) return PURE_E_ZIP_EXTRA_FIELD_UNICODE_PATH_OVERFLOW; 412 assert(offset + 2 + 2 + 1 <= extra_field_length); 413 uint8_t version = extra_field[offset + 2 + 2]; 414 if (version != 1) return PURE_E_ZIP_EXTRA_FIELD_UNICODE_PATH_VERSION; 415 // We require the unicode path to match the central directory file even if 416 // the crc32 of the non-unicode path is different. Otherwise, an attacker 417 // could present an alternative extension to bypass content inspection. 418 const uint8_t* unicode_path = extra_field + offset + 2 + 2 + 1 + 4; 419 const uint64_t unicode_path_length = size - 1 - 4; 420 if ( 421 unicode_path_length != file_name_length || 422 memcmp(unicode_path, file_name, (size_t) file_name_length) 423 ) { 424 return PURE_E_ZIP_EXTRA_FIELD_UNICODE_PATH_DIFF; 425 } 426 } 427 offset += 4; 428 offset += size; 429 } 430 if (offset > extra_field_length) return PURE_E_ZIP_EXTRA_FIELD_OVERFLOW; 431 if (offset < extra_field_length) { 432 if (pure_zeroes(extra_field, offset, extra_field_length)) { 433 return PURE_E_ZIP_EXTRA_FIELD_UNDERFLOW_ZEROED; 434 } else { 435 return PURE_E_ZIP_EXTRA_FIELD_UNDERFLOW_BUFFER_BLEED; 436 } 437 } 438 return 0; 439 } 440 441 int pure_zip_verify_file_name( 442 const uint8_t* file_name, 443 const uint64_t file_name_length 444 ) { 445 // A "file name" in this context is a path name with multiple components. 446 // The file name length may be 0 if the archiver input came from stdin. 447 448 // CVE-2018-1000035: 449 // Heap-based buffer overflow in password protected ZIP archives. 450 // https://sec-consult.com/en/blog/advisories/ 451 // multiple-vulnerabilities-in-infozip-unzip/index.html 452 // We want to defend vulnerable implementations against PATH_MAX allocation 453 // bugs, e.g. malloc(N * PATH_MAX) where the assumption is that user data 454 // cannot exceed PATH_MAX. 455 if (file_name_length > PURE_PATH_MAX) return PURE_E_ZIP_FILE_NAME_LENGTH; 456 457 // CVE-2003-0282 (aka "JELMER"): 458 // Some zip implementations filter control characters amongst others. 459 // This behavior can be exploited to mask ".." in a directory traversal. 460 // https://www.securityfocus.com/archive/1/321090 461 if (pure_path_control_characters(file_name, file_name_length)) { 462 return PURE_E_ZIP_FILE_NAME_CONTROL_CHARACTERS; 463 } 464 if (pure_path_drive(file_name, file_name_length)) { 465 return PURE_E_ZIP_FILE_NAME_TRAVERSAL_DRIVE_PATH; 466 } 467 if (pure_path_relative(file_name, file_name_length)) { 468 return PURE_E_ZIP_FILE_NAME_TRAVERSAL_RELATIVE_PATH; 469 } 470 if (pure_path_double_dots(file_name, file_name_length)) { 471 return PURE_E_ZIP_FILE_NAME_TRAVERSAL_DOUBLE_DOTS; 472 } 473 if (pure_path_component_overflow(file_name, file_name_length)) { 474 return PURE_E_ZIP_FILE_NAME_COMPONENT_OVERFLOW; 475 } 476 // All slashes must be forward according to the APPNOTE.TXT specification: 477 for (uint64_t index = 0; index < file_name_length; index++) { 478 if (file_name[index] == PURE_BACKSLASH) { 479 return PURE_E_ZIP_FILE_NAME_BACKSLASH; 480 } 481 } 482 return 0; 483 } 484 485 int pure_zip_verify_flags(const uint64_t value) { 486 if (value > PURE_16_BIT_MAX) return PURE_E_ZIP_FLAG_OVERFLOW; 487 if (value & (1 << 0)) return PURE_E_ZIP_FLAG_TRADITIONAL_ENCRYPTION; 488 if (value & (1 << 4)) return PURE_E_ZIP_FLAG_ENHANCED_DEFLATE; 489 if (value & (1 << 5)) return PURE_E_ZIP_FLAG_COMPRESSED_PATCHED_DATA; 490 if (value & (1 << 6)) return PURE_E_ZIP_FLAG_STRONG_ENCRYPTION; 491 if (value & (1 << 7)) return PURE_E_ZIP_FLAG_UNUSED_BIT_7; 492 if (value & (1 << 8)) return PURE_E_ZIP_FLAG_UNUSED_BIT_8; 493 if (value & (1 << 9)) return PURE_E_ZIP_FLAG_UNUSED_BIT_9; 494 if (value & (1 << 10)) return PURE_E_ZIP_FLAG_UNUSED_BIT_10; 495 if (value & (1 << 12)) return PURE_E_ZIP_FLAG_ENHANCED_COMPRESSION; 496 if (value & (1 << 13)) return PURE_E_ZIP_FLAG_MASKED_LOCAL_HEADERS; 497 if (value & (1 << 14)) return PURE_E_ZIP_FLAG_RESERVED_BIT_14; 498 if (value & (1 << 15)) return PURE_E_ZIP_FLAG_RESERVED_BIT_15; 499 return 0; 500 } 501 502 int pure_zip_verify_string( 503 const uint8_t* string, 504 const uint64_t string_length, 505 const uint64_t utf8 506 ) { 507 if (string_length > PURE_ZIP_STRING_MAX) return PURE_E_ZIP_STRING_MAX; 508 for (uint64_t index = 0; index < string_length; index++) { 509 if (string[index] == 0) return PURE_E_ZIP_STRING_NULL_BYTE; 510 } 511 if (utf8) { 512 // TO DO: Verify that UTF-8 encoding is valid: 513 // Some systems such as macOS never bother to set bit 11 to indicate UTF-8. 514 // We therefore always attempt UTF-8 and fallback to CP437 only on error. 515 // If the string must be UTF-8 then reject the string as invalid. 516 } 517 return 0; 518 } 519 520 int pure_zip_verify_symlink( 521 const pure_zip_cdh* cdh, 522 const pure_zip_lfh* lfh, 523 const uint8_t* buffer 524 ) { 525 if ((cdh->unix_mode & PURE_UNIX_MODE_MASK) != PURE_UNIX_MODE_LNK) return 0; 526 if (cdh->compression_method != 0) return PURE_E_ZIP_SYMLINK_COMPRESSED; 527 assert(cdh->relative_offset == lfh->offset); 528 assert(!pure_overflow(cdh->relative_offset, lfh->length, cdh->offset)); 529 const uint8_t* symlink = buffer + cdh->relative_offset + lfh->length; 530 const uint64_t symlink_length = cdh->compressed_size; 531 // Check for PATH_MAX overflow: 532 if (symlink_length > PURE_PATH_MAX) return PURE_E_ZIP_SYMLINK_LENGTH; 533 // Check for control characters used to mask a directory traversal: 534 if (pure_path_control_characters(symlink, symlink_length)) { 535 return PURE_E_ZIP_SYMLINK_CONTROL_CHARACTERS; 536 } 537 // Check for a directory traversal: 538 if (pure_path_drive(symlink, symlink_length)) { 539 return PURE_E_ZIP_SYMLINK_TRAVERSAL_DRIVE_PATH; 540 } 541 if (pure_path_relative(symlink, symlink_length)) { 542 return PURE_E_ZIP_SYMLINK_TRAVERSAL_RELATIVE_PATH; 543 } 544 if (pure_path_double_dots(symlink, symlink_length)) { 545 return PURE_E_ZIP_SYMLINK_TRAVERSAL_DOUBLE_DOTS; 546 } 547 // Check for path component overflow: 548 if (pure_path_component_overflow(symlink, symlink_length)) { 549 return PURE_E_ZIP_SYMLINK_COMPONENT_OVERFLOW; 550 } 551 return 0; 552 } 553 554 int pure_zip_verify_unix_mode(const uint64_t value) { 555 if (value > PURE_16_BIT_MAX) return PURE_E_ZIP_UNIX_MODE_OVERFLOW; 556 // Detect dangerous file types: 557 if ((value & PURE_UNIX_MODE_MASK) == PURE_UNIX_MODE_BLK) { 558 return PURE_E_ZIP_UNIX_MODE_BLOCK_DEVICE; 559 } 560 if ((value & PURE_UNIX_MODE_MASK) == PURE_UNIX_MODE_CHR) { 561 return PURE_E_ZIP_UNIX_MODE_CHARACTER_DEVICE; 562 } 563 if ((value & PURE_UNIX_MODE_MASK) == PURE_UNIX_MODE_FIFO) { 564 return PURE_E_ZIP_UNIX_MODE_FIFO; 565 } 566 if ((value & PURE_UNIX_MODE_MASK) == PURE_UNIX_MODE_SOCK) { 567 return PURE_E_ZIP_UNIX_MODE_SOCKET; 568 } 569 // Detect dangerous permissions: 570 // CVE-2005-0602 571 // https://marc.info/?l=bugtraq&m=110960796331943&w=2 572 // 01000: 573 if (value & 512) return PURE_E_ZIP_UNIX_MODE_PERMISSIONS_STICKY; 574 // 02000: 575 if (value & 1024) return PURE_E_ZIP_UNIX_MODE_PERMISSIONS_SETGID; 576 // 04000: 577 if (value & 2048) return PURE_E_ZIP_UNIX_MODE_PERMISSIONS_SETUID; 578 return 0; 579 } 580 581 int pure_zip_verify_time(const uint64_t value) { 582 /* 583 An MS-DOS time is a packed 16-bit (2 bytes) value in which bits in the value 584 represent the hour, minute, and second: 585 586 Bits: 0-4 5-10 11-15 587 Unit: Second Minute Hour 588 Range: 0-59 0-59 0-23 589 */ 590 if (value > PURE_16_BIT_MAX) return PURE_E_ZIP_TIME_OVERFLOW; 591 uint64_t h = (value >> 11); 592 uint64_t m = (value >> 5) & 63; 593 uint64_t s = (value & 31) * 2; 594 if (h > 23) return PURE_E_ZIP_TIME_HOUR_OVERFLOW; 595 if (m > 59) return PURE_E_ZIP_TIME_MINUTE_OVERFLOW; 596 if (s > 59) return PURE_E_ZIP_TIME_SECOND_OVERFLOW; 597 return 0; 598 } 599 600 int pure_zip_verify_lfh(const pure_zip_lfh* header) { 601 assert( 602 header->length == ( 603 PURE_ZIP_LFH_MIN + 604 header->file_name_length + 605 header->extra_field_length 606 ) 607 ); 608 { 609 int error = pure_zip_verify_flags(header->general_purpose_bit_flag); 610 if (error) return error; 611 } 612 { 613 int error = pure_zip_verify_compression_method_sizes( 614 header->compression_method, 615 header->compressed_size, 616 header->uncompressed_size 617 ); 618 if (error) return error; 619 } 620 { 621 int error = pure_zip_verify_date(header->last_mod_file_date); 622 if (error) return error; 623 } 624 { 625 int error = pure_zip_verify_time(header->last_mod_file_time); 626 if (error) return error; 627 } 628 { 629 int error = pure_zip_verify_file_name( 630 header->file_name, 631 header->file_name_length 632 ); 633 if (error) return error; 634 } 635 { 636 int error = pure_zip_verify_string( 637 header->file_name, 638 header->file_name_length, 639 header->general_purpose_bit_flag & PURE_ZIP_FLAG_UTF8 640 ); 641 if (error) return error; 642 } 643 { 644 int error = pure_zip_verify_extra_field( 645 header->extra_field, 646 header->extra_field_length, 647 header->file_name, 648 header->file_name_length 649 ); 650 if (error) return error; 651 } 652 assert(header->zip64 == 0 || header->zip64 == 1); 653 return 0; 654 } 655 656 int pure_zip_verify_cdh(const pure_zip_cdh* header) { 657 assert( 658 header->length == ( 659 PURE_ZIP_CDH_MIN + 660 header->file_name_length + 661 header->extra_field_length + 662 header->file_comment_length 663 ) 664 ); 665 { 666 int error = pure_zip_verify_flags(header->general_purpose_bit_flag); 667 if (error) return error; 668 } 669 { 670 int error = pure_zip_verify_compression_method_sizes( 671 header->compression_method, 672 header->compressed_size, 673 header->uncompressed_size 674 ); 675 if (error) return error; 676 } 677 // An LFH may have a zero compressed size with a non-zero uncompressed size 678 // because the actual sizes may be in the DDR, but a CDH cannot be ex nihilo. 679 // We cross-check the DDR against the CDH, so this check applies to the DDR: 680 if (header->compressed_size == 0 && header->uncompressed_size != 0) { 681 return PURE_E_ZIP_EX_NIHILO; 682 } 683 { 684 int error = pure_zip_verify_date(header->last_mod_file_date); 685 if (error) return error; 686 } 687 { 688 int error = pure_zip_verify_time(header->last_mod_file_time); 689 if (error) return error; 690 } 691 { 692 int error = pure_zip_verify_file_name( 693 header->file_name, 694 header->file_name_length 695 ); 696 if (error) return error; 697 } 698 { 699 int error = pure_zip_verify_string( 700 header->file_name, 701 header->file_name_length, 702 header->general_purpose_bit_flag & PURE_ZIP_FLAG_UTF8 703 ); 704 if (error) return error; 705 } 706 { 707 int error = pure_zip_verify_extra_field( 708 header->extra_field, 709 header->extra_field_length, 710 header->file_name, 711 header->file_name_length 712 ); 713 if (error) return error; 714 } 715 { 716 int error = pure_zip_verify_string( 717 header->file_comment, 718 header->file_comment_length, 719 header->general_purpose_bit_flag & PURE_ZIP_FLAG_UTF8 720 ); 721 if (error) return error; 722 } 723 { 724 int error = pure_zip_verify_disk(header->disk); 725 if (error) return error; 726 } 727 { 728 int error = pure_zip_verify_unix_mode(header->unix_mode); 729 if (error) return error; 730 } 731 { 732 int error = pure_zip_verify_directory(header); 733 if (error) return error; 734 } 735 assert(header->zip64 == 0 || header->zip64 == 1); 736 return 0; 737 } 738 739 int pure_zip_decode_eief_64( 740 const uint8_t* extra_field, 741 const uint64_t length, 742 uint64_t* compressed_size, 743 uint64_t* uncompressed_size, 744 uint64_t* relative_offset, 745 uint64_t* disk, 746 uint8_t* zip64, 747 uint8_t lfh 748 ) { 749 assert( 750 *compressed_size == PURE_32_BIT_MAX || 751 *uncompressed_size == PURE_32_BIT_MAX || 752 *relative_offset == PURE_32_BIT_MAX || 753 *disk == PURE_16_BIT_MAX 754 ); 755 assert(*zip64 == 0); 756 assert(lfh == 0 || lfh == 1); 757 if (length > PURE_ZIP_EXTRA_FIELD_MAX) return PURE_E_ZIP_EXTRA_FIELD_MAX; 758 if (length != 0 && length < 4) return PURE_E_ZIP_EXTRA_FIELD_MIN; 759 uint64_t offset = 0; 760 while (offset + 4 <= length) { 761 const uint16_t id = pure_u16(extra_field + offset + 0); 762 const uint16_t size = pure_u16(extra_field + offset + 2); 763 offset += 4; 764 if (offset + size > length) { 765 return PURE_E_ZIP_EXTRA_FIELD_ATTRIBUTE_OVERFLOW; 766 } 767 if (id == 0x0001) { 768 *zip64 = 1; 769 uint64_t index = 0; 770 if (*uncompressed_size == PURE_32_BIT_MAX) { 771 if ((index += 8) > size) return PURE_E_ZIP_EIEF_64_UNCOMPRESSED_SIZE; 772 *uncompressed_size = pure_u64(extra_field + offset + index - 8); 773 } 774 if (*compressed_size == PURE_32_BIT_MAX) { 775 if ((index += 8) > size) return PURE_E_ZIP_EIEF_64_COMPRESSED_SIZE; 776 *compressed_size = pure_u64(extra_field + offset + index - 8); 777 } 778 if (*relative_offset == PURE_32_BIT_MAX) { 779 if ((index += 8) > size) return PURE_E_ZIP_EIEF_64_RELATIVE_OFFSET; 780 *relative_offset = pure_u64(extra_field + offset + index - 8); 781 } 782 if (*disk == PURE_16_BIT_MAX) { 783 if ((index += 4) > size) return PURE_E_ZIP_EIEF_64_DISK; 784 *disk = pure_u32(extra_field + offset + index - 4); 785 } 786 assert(offset + size <= length); 787 if (index < size) { 788 if (pure_zeroes(extra_field, offset + index, offset + size)) { 789 return PURE_E_ZIP_EIEF_64_UNDERFLOW_ZEROED; 790 } else { 791 return PURE_E_ZIP_EIEF_64_UNDERFLOW_BUFFER_BLEED; 792 } 793 } 794 // The EIEF in an LFH must include both uncompressed and compressed size: 795 if (lfh && index != 16) return PURE_E_ZIP_EIEF_64_LFH; 796 assert(index == size); 797 return 0; 798 } 799 offset += size; 800 } 801 assert(offset <= length); 802 return 0; 803 } 804 805 int pure_zip_decode_lfh( 806 const uint8_t* buffer, 807 const uint64_t size, 808 const uint64_t offset, 809 pure_zip_lfh* header 810 ) { 811 assert(offset < size); 812 if (pure_overflow(offset, PURE_ZIP_LFH_MIN, size)) { 813 return PURE_E_ZIP_LFH_OVERFLOW; 814 } 815 if (!pure_eq(buffer, size, offset, PURE_S_ZIP_LFH, PURE_L_ZIP_LFH)) { 816 return PURE_E_ZIP_LFH_SIGNATURE; 817 } 818 header->offset = offset; 819 assert(PURE_L_ZIP_LFH == 4); 820 header->version_minimum = pure_u16(buffer + offset + 4); 821 header->general_purpose_bit_flag = pure_u16(buffer + offset + 6); 822 header->compression_method = pure_u16(buffer + offset + 8); 823 header->last_mod_file_time = pure_u16(buffer + offset + 10); 824 header->last_mod_file_date = pure_u16(buffer + offset + 12); 825 header->crc32 = pure_u32(buffer + offset + 14); 826 header->compressed_size = pure_u32(buffer + offset + 18); 827 header->uncompressed_size = pure_u32(buffer + offset + 22); 828 header->file_name_length = pure_u16(buffer + offset + 26); 829 header->extra_field_length = pure_u16(buffer + offset + 28); 830 assert(PURE_ZIP_LFH_MIN == 30); 831 header->length = PURE_ZIP_LFH_MIN; 832 header->file_name = (uint8_t*) (buffer + header->offset + header->length); 833 header->length += header->file_name_length; 834 if (pure_overflow(header->offset, header->length, size)) { 835 return PURE_E_ZIP_LFH_FILE_NAME_OVERFLOW; 836 } 837 header->extra_field = (uint8_t*) (buffer + header->offset + header->length); 838 header->length += header->extra_field_length; 839 if (pure_overflow(header->offset, header->length, size)) { 840 return PURE_E_ZIP_LFH_EXTRA_FIELD_OVERFLOW; 841 } 842 // ZIP64: 843 header->zip64 = 0; 844 if ( 845 header->compressed_size == PURE_32_BIT_MAX || 846 header->uncompressed_size == PURE_32_BIT_MAX 847 ) { 848 uint64_t relative_offset = 0; 849 uint64_t disk = 0; 850 int error = pure_zip_decode_eief_64( 851 header->extra_field, 852 header->extra_field_length, 853 &header->compressed_size, 854 &header->uncompressed_size, 855 &relative_offset, 856 &disk, 857 &header->zip64, 858 1 859 ); 860 if (error) return error; 861 } 862 { 863 int error = pure_zip_verify_lfh(header); 864 if (error) return error; 865 } 866 return 0; 867 } 868 869 int pure_zip_decode_ddr( 870 const uint8_t* buffer, 871 const uint64_t size, 872 uint64_t offset, 873 pure_zip_ddr* header 874 ) { 875 assert(offset < size); 876 assert(header->zip64 == 0 || header->zip64 == 1); 877 const uint64_t min = header->zip64 ? PURE_ZIP_DDR_64_MIN : PURE_ZIP_DDR_MIN; 878 // The DDR signature is optional but we expect at least 4 bytes regardless: 879 if (pure_overflow(offset, PURE_L_ZIP_DDR, size)) { 880 return PURE_E_ZIP_DDR_OVERFLOW; 881 } 882 if (pure_eq(buffer, size, offset, PURE_S_ZIP_DDR, PURE_L_ZIP_DDR)) { 883 header->offset = offset; 884 header->length = PURE_L_ZIP_DDR + min; 885 offset += PURE_L_ZIP_DDR; 886 } else { 887 header->offset = offset; 888 header->length = min; 889 } 890 if (pure_overflow(offset, min, size)) return PURE_E_ZIP_DDR_OVERFLOW; 891 if (header->zip64) { 892 assert(min == 4 + 8 + 8); 893 header->crc32 = pure_u32(buffer + offset + 0); 894 header->compressed_size = pure_u64(buffer + offset + 4); 895 header->uncompressed_size = pure_u64(buffer + offset + 12); 896 } else { 897 assert(min == 4 + 4 + 4); 898 header->crc32 = pure_u32(buffer + offset + 0); 899 header->compressed_size = pure_u32(buffer + offset + 4); 900 header->uncompressed_size = pure_u32(buffer + offset + 8); 901 } 902 return 0; 903 } 904 905 int pure_zip_decode_cdh( 906 const uint8_t* buffer, 907 const uint64_t size, 908 const uint64_t offset, 909 pure_zip_cdh* header 910 ) { 911 assert(offset < size); 912 if (pure_overflow(offset, PURE_ZIP_CDH_MIN, size)) { 913 return PURE_E_ZIP_CDH_OVERFLOW; 914 } 915 if (!pure_eq(buffer, size, offset, PURE_S_ZIP_CDH, PURE_L_ZIP_CDH)) { 916 return PURE_E_ZIP_CDH_SIGNATURE; 917 } 918 header->offset = offset; 919 assert(PURE_L_ZIP_CDH == 4); 920 header->version_made = pure_u16(buffer + offset + 4); 921 header->version_minimum = pure_u16(buffer + offset + 6); 922 header->general_purpose_bit_flag = pure_u16(buffer + offset + 8); 923 header->compression_method = pure_u16(buffer + offset + 10); 924 header->last_mod_file_time = pure_u16(buffer + offset + 12); 925 header->last_mod_file_date = pure_u16(buffer + offset + 14); 926 header->crc32 = pure_u32(buffer + offset + 16); 927 header->compressed_size = pure_u32(buffer + offset + 20); 928 header->uncompressed_size = pure_u32(buffer + offset + 24); 929 header->file_name_length = pure_u16(buffer + offset + 28); 930 header->extra_field_length = pure_u16(buffer + offset + 30); 931 header->file_comment_length = pure_u16(buffer + offset + 32); 932 header->disk = pure_u16(buffer + offset + 34); 933 header->internal_file_attributes = pure_u16(buffer + offset + 36); 934 header->external_file_attributes = pure_u32(buffer + offset + 38); 935 header->relative_offset = pure_u32(buffer + offset + 42); 936 assert(PURE_ZIP_CDH_MIN == 46); 937 header->length = PURE_ZIP_CDH_MIN; 938 header->file_name = (uint8_t*) (buffer + header->offset + header->length); 939 header->length += header->file_name_length; 940 if (pure_overflow(header->offset, header->length, size)) { 941 return PURE_E_ZIP_CDH_FILE_NAME_OVERFLOW; 942 } 943 header->extra_field = (uint8_t*) (buffer + header->offset + header->length); 944 header->length += header->extra_field_length; 945 if (pure_overflow(header->offset, header->length, size)) { 946 return PURE_E_ZIP_CDH_EXTRA_FIELD_OVERFLOW; 947 } 948 header->file_comment = (uint8_t*) (buffer + header->offset + header->length); 949 header->length += header->file_comment_length; 950 if (pure_overflow(header->offset, header->length, size)) { 951 return PURE_E_ZIP_CDH_FILE_COMMENT_OVERFLOW; 952 } 953 header->unix_mode = 0; 954 if ((header->version_made >> 8) == PURE_ZIP_VERSION_MADE_UNIX) { 955 header->unix_mode = header->external_file_attributes >> 16; 956 } 957 header->directory = ( 958 (header->unix_mode & PURE_UNIX_MODE_MASK) == PURE_UNIX_MODE_DIR || 959 (header->external_file_attributes & 0x0010) || 960 ( 961 header->file_name_length > 0 && 962 header->file_name[header->file_name_length - 1] == PURE_FORWARD_SLASH 963 ) 964 ); 965 // ZIP64: 966 header->zip64 = 0; 967 if ( 968 header->compressed_size == PURE_32_BIT_MAX || 969 header->uncompressed_size == PURE_32_BIT_MAX || 970 header->relative_offset == PURE_32_BIT_MAX || 971 header->disk == PURE_16_BIT_MAX 972 ) { 973 int error = pure_zip_decode_eief_64( 974 header->extra_field, 975 header->extra_field_length, 976 &header->compressed_size, 977 &header->uncompressed_size, 978 &header->relative_offset, 979 &header->disk, 980 &header->zip64, 981 0 982 ); 983 if (error) return error; 984 } 985 // These are critical checks and must not be moved to pure_zip_verify_cdh(): 986 if (header->relative_offset > size) { 987 return PURE_E_ZIP_CDH_RELATIVE_OFFSET_OVERFLOW; 988 } 989 if (header->relative_offset > offset) { 990 return PURE_E_ZIP_CDH_RELATIVE_OFFSET_OVERLAP; 991 } 992 { 993 int error = pure_zip_verify_cdh(header); 994 if (error) return error; 995 } 996 return 0; 997 } 998 999 int pure_zip_decode_eocdl_64( 1000 const uint8_t* buffer, 1001 const uint64_t size, 1002 const uint64_t offset, 1003 pure_zip_eocdl_64* header 1004 ) { 1005 assert(offset < size); 1006 if (pure_overflow(offset, PURE_ZIP_EOCDL_64, size)) { 1007 return PURE_E_ZIP_EOCDL_64_OVERFLOW; 1008 } 1009 if ( 1010 !pure_eq(buffer, size, offset, PURE_S_ZIP_EOCDL_64, PURE_L_ZIP_EOCDL_64) 1011 ) { 1012 return PURE_E_ZIP_EOCDL_64_SIGNATURE; 1013 } 1014 header->offset = offset; 1015 assert(PURE_L_ZIP_EOCDL_64 == 4); 1016 header->disk = pure_u32(buffer + offset + 4); 1017 header->eocdr_64_offset = pure_u64(buffer + offset + 8); 1018 header->disks = pure_u32(buffer + offset + 16); 1019 assert(PURE_ZIP_EOCDL_64 == 20); 1020 header->length = PURE_ZIP_EOCDL_64; 1021 if (header->disk != 0) return PURE_E_ZIP_EOCDL_64_DISK; 1022 if ( 1023 pure_overflow( 1024 header->eocdr_64_offset, 1025 PURE_ZIP_EOCDR_64_MIN, 1026 header->offset 1027 ) 1028 ) { 1029 return PURE_E_ZIP_EOCDR_EOCDL_64_OVERFLOW; 1030 } 1031 if (header->disks != 0 && header->disks != 1) { 1032 return PURE_E_ZIP_EOCDL_64_DISKS; 1033 } 1034 return 0; 1035 } 1036 1037 int pure_zip_decode_eocdr_64( 1038 const uint8_t* buffer, 1039 const uint64_t size, 1040 const uint64_t offset, 1041 pure_zip_eocdr_64* header 1042 ) { 1043 assert(offset < size); 1044 if (pure_overflow(offset, PURE_ZIP_EOCDR_64_MIN, size)) { 1045 return PURE_E_ZIP_EOCDR_64_OVERFLOW; 1046 } 1047 if ( 1048 !pure_eq(buffer, size, offset, PURE_S_ZIP_EOCDR_64, PURE_L_ZIP_EOCDR_64) 1049 ) { 1050 return PURE_E_ZIP_EOCDR_64_SIGNATURE; 1051 } 1052 header->offset = offset; 1053 assert(PURE_L_ZIP_EOCDR_64 == 4); 1054 // The value stored in "size of zip64 end of central directory record" is the 1055 // size of the remaining record and excludes the leading 12 bytes: 1056 // size_remaining = PURE_ZIP_EOCDR_64_MIN + extensible_data_sector_length - 12 1057 // extensible_data_sector_length = size_remaining - PURE_ZIP_EOCDR_64_MIN + 12 1058 header->extensible_data_sector_length = ( 1059 pure_u64(buffer + offset + 4) - (PURE_ZIP_EOCDR_64_MIN - 12) 1060 ); 1061 header->version_made = pure_u16(buffer + offset + 12); 1062 header->version_minimum = pure_u16(buffer + offset + 14); 1063 header->disk = pure_u32(buffer + offset + 16); 1064 header->cd_disk = pure_u32(buffer + offset + 20); 1065 header->cd_disk_records = pure_u64(buffer + offset + 24); 1066 header->cd_records = pure_u64(buffer + offset + 32); 1067 header->cd_size = pure_u64(buffer + offset + 40); 1068 header->cd_offset = pure_u64(buffer + offset + 48); 1069 assert(PURE_ZIP_EOCDR_64_MIN == 56); 1070 header->length = PURE_ZIP_EOCDR_64_MIN; 1071 header->extensible_data_sector = ( 1072 (uint8_t*) (buffer + header->offset + header->length) 1073 ); 1074 header->length += header->extensible_data_sector_length; 1075 return 0; 1076 } 1077 1078 int pure_zip_decode_eocdr_64_inherit( 1079 pure_zip_eocdr* a, 1080 const pure_zip_eocdr_64* b 1081 ) { 1082 // Inherit only those values that are maxed out in the EOCDR: 1083 if (a->disk == PURE_16_BIT_MAX) a->disk = b->disk; 1084 if (a->cd_disk == PURE_16_BIT_MAX) a->cd_disk = b->cd_disk; 1085 if (a->cd_disk_records == PURE_16_BIT_MAX) { 1086 a->cd_disk_records = b->cd_disk_records; 1087 } 1088 if (a->cd_records == PURE_16_BIT_MAX) a->cd_records = b->cd_records; 1089 if (a->cd_size == PURE_32_BIT_MAX) a->cd_size = b->cd_size; 1090 if (a->cd_offset == PURE_32_BIT_MAX) a->cd_offset = b->cd_offset; 1091 // Verify that all values are now in agreement between the EOCDR and EOCDR_64: 1092 if (a->disk != b->disk) return PURE_E_ZIP_DIFF_EOCDR_DISK; 1093 if (a->cd_disk != b->cd_disk) return PURE_E_ZIP_DIFF_EOCDR_CD_DISK; 1094 if (a->cd_disk_records != b->cd_disk_records) { 1095 return PURE_E_ZIP_DIFF_EOCDR_CD_DISK_RECORDS; 1096 } 1097 if (a->cd_records != b->cd_records) return PURE_E_ZIP_DIFF_EOCDR_CD_RECORDS; 1098 if (a->cd_size != b->cd_size) return PURE_E_ZIP_DIFF_EOCDR_CD_SIZE; 1099 if (a->cd_offset != b->cd_offset) return PURE_E_ZIP_DIFF_EOCDR_CD_OFFSET; 1100 return 0; 1101 } 1102 1103 int pure_zip_decode_eocdr_64_upgrade( 1104 const uint8_t* buffer, 1105 const uint64_t size, 1106 pure_zip_eocdr* header 1107 ) { 1108 header->zip64 = 0; 1109 if ( 1110 header->disk != PURE_16_BIT_MAX && 1111 header->cd_disk != PURE_16_BIT_MAX && 1112 header->cd_disk_records != PURE_16_BIT_MAX && 1113 header->cd_records != PURE_16_BIT_MAX && 1114 header->cd_size != PURE_32_BIT_MAX && 1115 header->cd_offset != PURE_32_BIT_MAX 1116 ) { 1117 return 0; 1118 } 1119 pure_zip_eocdl_64 eocdl_64; 1120 pure_zip_eocdr_64 eocdr_64; 1121 if (header->offset < PURE_ZIP_EOCDL_64) { 1122 return PURE_E_ZIP_EOCDL_64_NEGATIVE_OFFSET; 1123 } 1124 assert(header->offset >= PURE_ZIP_EOCDL_64); 1125 { 1126 int error = pure_zip_decode_eocdl_64( 1127 buffer, 1128 size, 1129 header->offset - PURE_ZIP_EOCDL_64, 1130 &eocdl_64 1131 ); 1132 // A header field may actually be FFFF or FFFFFFFF without any Zip64 format: 1133 if (error == PURE_E_ZIP_EOCDL_64_SIGNATURE) return 0; 1134 if (error) return error; 1135 } 1136 assert(!pure_overflow(eocdl_64.offset, eocdl_64.length, header->offset)); 1137 assert(eocdl_64.offset + eocdl_64.length == header->offset); 1138 assert( 1139 !pure_overflow( 1140 eocdl_64.eocdr_64_offset, 1141 PURE_ZIP_EOCDR_64_MIN, 1142 eocdl_64.offset 1143 ) 1144 ); 1145 { 1146 int error = pure_zip_decode_eocdr_64( 1147 buffer, 1148 size, 1149 eocdl_64.eocdr_64_offset, 1150 &eocdr_64 1151 ); 1152 if (error) return error; 1153 } 1154 const uint64_t eocdl_offset = eocdr_64.offset + eocdr_64.length; 1155 assert(eocdl_offset > eocdr_64.offset); 1156 if (eocdl_offset > eocdl_64.offset) return PURE_E_ZIP_EOCDR_EOCDL_64_OVERFLOW; 1157 if (eocdl_offset < eocdl_64.offset) { 1158 assert(eocdl_64.offset <= size); 1159 if (pure_zeroes(buffer, eocdl_offset, eocdl_64.offset)) { 1160 return PURE_E_ZIP_EOCDR_EOCDL_64_UNDERFLOW_ZEROED; 1161 } else { 1162 return PURE_E_ZIP_EOCDR_EOCDL_64_UNDERFLOW_BUFFER_BLEED; 1163 } 1164 } 1165 assert(!pure_overflow(eocdr_64.offset, eocdr_64.length, eocdl_64.offset)); 1166 assert(eocdr_64.offset + eocdr_64.length == eocdl_64.offset); 1167 { 1168 int error = pure_zip_decode_eocdr_64_inherit(header, &eocdr_64); 1169 if (error) return error; 1170 } 1171 header->zip64 = 1; 1172 header->offset = eocdr_64.offset; 1173 header->length = eocdr_64.length + eocdl_64.length + header->length; 1174 return 0; 1175 } 1176 1177 int pure_zip_decode_eocdr( 1178 const uint8_t* buffer, 1179 const uint64_t size, 1180 const uint64_t offset, 1181 pure_zip_eocdr* header 1182 ) { 1183 assert(offset < size); 1184 if (pure_overflow(offset, PURE_ZIP_EOCDR_MIN, size)) { 1185 return PURE_E_ZIP_EOCDR_OVERFLOW; 1186 } 1187 if (!pure_eq(buffer, size, offset, PURE_S_ZIP_EOCDR, PURE_L_ZIP_EOCDR)) { 1188 return PURE_E_ZIP_EOCDR_SIGNATURE; 1189 } 1190 // We consider header->offset to start at EOCDR_64 or EOCDR. 1191 // We consider header->length to include EOCDR_64, EOCDL_64 and EOCDR. 1192 header->offset = offset; 1193 assert(PURE_L_ZIP_EOCDR == 4); 1194 header->disk = pure_u16(buffer + offset + 4); 1195 header->cd_disk = pure_u16(buffer + offset + 6); 1196 header->cd_disk_records = pure_u16(buffer + offset + 8); 1197 header->cd_records = pure_u16(buffer + offset + 10); 1198 header->cd_size = pure_u32(buffer + offset + 12); 1199 header->cd_offset = pure_u32(buffer + offset + 16); 1200 header->comment_length = pure_u16(buffer + offset + 20); 1201 assert(PURE_ZIP_EOCDR_MIN == 22); 1202 header->length = PURE_ZIP_EOCDR_MIN; 1203 header->comment = (uint8_t*) (buffer + header->offset + header->length); 1204 header->length += header->comment_length; 1205 if (pure_overflow(header->offset, header->length, size)) { 1206 return PURE_E_ZIP_EOCDR_COMMENT_OVERFLOW; 1207 } 1208 { 1209 // If we find an EOCDR_64 and EOCDL_64, we modify header->(offset, length): 1210 const uint64_t length = PURE_ZIP_EOCDR_MIN + header->comment_length; 1211 assert(header->length == length); 1212 int error = pure_zip_decode_eocdr_64_upgrade(buffer, size, header); 1213 if (error) return error; 1214 assert(header->zip64 == 0 || header->zip64 == 1); 1215 if (header->zip64) { 1216 const uint64_t length_64 = PURE_ZIP_EOCDR_64_MIN + PURE_ZIP_EOCDL_64; 1217 assert(header->offset <= offset - length_64); 1218 assert(header->length >= length + length_64); 1219 } else { 1220 assert(header->offset == offset); 1221 assert(header->length == length); 1222 } 1223 } 1224 if (header->cd_size < header->cd_records * PURE_ZIP_CDH_MIN) { 1225 return PURE_E_ZIP_EOCDR_SIZE_OVERFLOW; 1226 } 1227 if (header->cd_size > 0 && header->cd_records == 0) { 1228 return PURE_E_ZIP_EOCDR_SIZE_UNDERFLOW; 1229 } 1230 if (pure_overflow(header->cd_offset, header->cd_size, header->offset)) { 1231 return PURE_E_ZIP_CD_EOCDR_OVERFLOW; 1232 } 1233 if (header->disk != 0 || header->cd_disk != 0) { 1234 return PURE_E_ZIP_MULTIPLE_DISKS; 1235 } 1236 if (header->cd_disk_records != header->cd_records) { 1237 return PURE_E_ZIP_EOCDR_RECORDS; 1238 } 1239 { 1240 int error = pure_zip_verify_string( 1241 header->comment, 1242 header->comment_length, 1243 // The EOCDR has no General Purpose Bit Flag with which to indicate UTF-8. 1244 // Therefore, the comment encoding must always be CP437: 1245 0 1246 ); 1247 if (error) return error; 1248 } 1249 uint64_t suffix_offset = header->offset + header->length; 1250 if (suffix_offset < size) { 1251 if (pure_zeroes(buffer, suffix_offset, size)) { 1252 return PURE_E_ZIP_APPENDED_DATA_ZEROED; 1253 } else { 1254 return PURE_E_ZIP_APPENDED_DATA_BUFFER_BLEED; 1255 } 1256 } 1257 return 0; 1258 } 1259 1260 // Compare LFH against CDH taking Data Descriptor Record into account: 1261 int pure_zip_diff_cld( 1262 const uint64_t cdh_value, 1263 const uint64_t lfh_value, 1264 const pure_zip_lfh* lfh 1265 ) { 1266 // LFH matches CDH: 1267 if (lfh_value == cdh_value) return 0; 1268 // LFH delegates value to Data Descriptor: 1269 if ((lfh->general_purpose_bit_flag & (1 << 3)) && lfh_value == 0) return 0; 1270 // LFH diverges from CDH: 1271 return 1; 1272 } 1273 1274 // Compare DDR against CDH: 1275 int pure_zip_diff_cdh_ddr(const pure_zip_cdh* cdh, const pure_zip_ddr* ddr) { 1276 if (ddr->crc32 != cdh->crc32) { 1277 return PURE_E_ZIP_DIFF_DDR_CRC32; 1278 } 1279 if (ddr->compressed_size != cdh->compressed_size) { 1280 return PURE_E_ZIP_DIFF_DDR_COMPRESSED_SIZE; 1281 } 1282 if (ddr->uncompressed_size != cdh->uncompressed_size) { 1283 return PURE_E_ZIP_DIFF_DDR_UNCOMPRESSED_SIZE; 1284 } 1285 return 0; 1286 } 1287 1288 // Compare LFH against CDH: 1289 int pure_zip_diff_cdh_lfh(const pure_zip_cdh* cdh, const pure_zip_lfh* lfh) { 1290 if (lfh->general_purpose_bit_flag != cdh->general_purpose_bit_flag) { 1291 return PURE_E_ZIP_DIFF_LFH_GENERAL_PURPOSE_BIT_FLAG; 1292 } 1293 if (lfh->compression_method != cdh->compression_method) { 1294 return PURE_E_ZIP_DIFF_LFH_COMPRESSION_METHOD; 1295 } 1296 if (lfh->last_mod_file_time != cdh->last_mod_file_time) { 1297 return PURE_E_ZIP_DIFF_LFH_LAST_MOD_FILE_TIME; 1298 } 1299 if (lfh->last_mod_file_date != cdh->last_mod_file_date) { 1300 return PURE_E_ZIP_DIFF_LFH_LAST_MOD_FILE_DATE; 1301 } 1302 if (pure_zip_diff_cld(cdh->crc32, lfh->crc32, lfh)) { 1303 return PURE_E_ZIP_DIFF_LFH_CRC32; 1304 } 1305 if (pure_zip_diff_cld(cdh->compressed_size, lfh->compressed_size, lfh)) { 1306 return PURE_E_ZIP_DIFF_LFH_COMPRESSED_SIZE; 1307 } 1308 if (pure_zip_diff_cld(cdh->uncompressed_size, lfh->uncompressed_size, lfh)) { 1309 return PURE_E_ZIP_DIFF_LFH_UNCOMPRESSED_SIZE; 1310 } 1311 if (lfh->file_name_length != cdh->file_name_length) { 1312 return PURE_E_ZIP_DIFF_LFH_FILE_NAME_LENGTH; 1313 } 1314 // We assume decode_lfh() and decode_cdh() have already checked for overflow: 1315 if (memcmp(lfh->file_name, cdh->file_name, (size_t) cdh->file_name_length)) { 1316 return PURE_E_ZIP_DIFF_LFH_FILE_NAME; 1317 } 1318 return 0; 1319 } 1320 1321 // Compare LFH against DDR: 1322 int pure_zip_diff_ddr_lfh(const pure_zip_ddr* ddr, const pure_zip_lfh* lfh) { 1323 if (lfh->crc32 != 0 && lfh->crc32 != ddr->crc32) { 1324 return PURE_E_ZIP_DIFF_LFH_DDR_CRC32; 1325 } 1326 if ( 1327 lfh->compressed_size != 0 && 1328 lfh->compressed_size != ddr->compressed_size 1329 ) { 1330 return PURE_E_ZIP_DIFF_LFH_DDR_COMPRESSED_SIZE; 1331 } 1332 if ( 1333 lfh->uncompressed_size != 0 && 1334 lfh->uncompressed_size != ddr->uncompressed_size 1335 ) { 1336 return PURE_E_ZIP_DIFF_LFH_DDR_UNCOMPRESSED_SIZE; 1337 } 1338 return 0; 1339 } 1340 1341 int pure_zip_inflate_raw( 1342 const uint8_t* compressed, 1343 const uint64_t compressed_size, 1344 const uint8_t* uncompressed, 1345 const uint64_t uncompressed_size 1346 ) { 1347 if (uncompressed_size == 0) return 0; 1348 z_stream z; 1349 z.zalloc = Z_NULL; 1350 z.zfree = Z_NULL; 1351 z.opaque = Z_NULL; 1352 z.avail_in = 0; 1353 z.avail_out = 0; 1354 z.next_in = Z_NULL; 1355 z.next_out = Z_NULL; 1356 // We indicate raw inflate to zlib by setting window_bits to negative: 1357 // We further allow for the greatest possible compression window size (15). 1358 int window_bits = -15; 1359 { 1360 int error = inflateInit2(&z, window_bits); 1361 if (error != Z_OK) return PURE_E_ZIP_INFLATE; 1362 } 1363 // TO DO: Switch to streaming zlib inflate to support larger file sizes. 1364 assert(sizeof(z.avail_in) >= 4); 1365 assert(sizeof(z.avail_out) >= 4); 1366 assert(compressed_size <= UINT32_MAX); 1367 assert(uncompressed_size <= UINT32_MAX); 1368 z.avail_in = (unsigned int) compressed_size; 1369 z.avail_out = (unsigned int) uncompressed_size; 1370 z.next_in = (uint8_t*) compressed; 1371 z.next_out = (uint8_t*) uncompressed; 1372 int error = inflate(&z, Z_FINISH); 1373 (void) inflateEnd(&z); 1374 if (error == Z_STREAM_END) { 1375 if (z.avail_in > 0) return PURE_E_ZIP_INFLATE_COMPRESSED_UNDERFLOW; 1376 if (z.avail_out > 0) return PURE_E_ZIP_INFLATE_UNCOMPRESSED_UNDERFLOW; 1377 assert(z.total_in == compressed_size); 1378 assert(z.total_out == uncompressed_size); 1379 return 0; 1380 } else { 1381 if (error == Z_NEED_DICT) return PURE_E_ZIP_INFLATE_DICTIONARY; 1382 if (error == Z_STREAM_ERROR) return PURE_E_ZIP_INFLATE_STREAM; 1383 if (error == Z_DATA_ERROR) return PURE_E_ZIP_INFLATE_DATA; 1384 if (error == Z_MEM_ERROR) return PURE_E_ZIP_INFLATE_MEMORY; 1385 if (error == Z_BUF_ERROR) { 1386 // If avail_out and avail_in are both zero then it is likely an output 1387 // overflow since the input stream has more chance of terminating first. 1388 // We therefore check avail_out first since we cannot further distinguish. 1389 if (!z.avail_out) return PURE_E_ZIP_BOMB_INFLATE_UNCOMPRESSED_OVERFLOW; 1390 if (!z.avail_in) return PURE_E_ZIP_BOMB_INFLATE_COMPRESSED_OVERFLOW; 1391 } 1392 return PURE_E_ZIP_INFLATE; 1393 } 1394 } 1395 1396 int pure_zip_locate_eocdr( 1397 const uint8_t* buffer, 1398 const uint64_t size, 1399 uint64_t* offset 1400 ) { 1401 assert(*offset == 0); 1402 if (size < PURE_ZIP_EOCDR_MIN) return PURE_E_ZIP_TOO_SMALL; 1403 int64_t index = size - PURE_ZIP_EOCDR_MIN; 1404 // The EOCDR can be at most EOCDR_MIN plus a variable length comment. 1405 // The variable length of the comment can be at most a 16-bit integer. 1406 // Assuming no garbage after the EOCDR, our maximum search distance is: 1407 int64_t floor = size - PURE_ZIP_EOCDR_MIN - PURE_ZIP_EOCDR_COMMENT_MAX; 1408 if (index < 0) index = 0; 1409 if (floor < 0) floor = 0; 1410 assert(!pure_overflow((uint64_t) index, PURE_L_ZIP_EOCDR, size)); 1411 assert(PURE_L_ZIP_EOCDR == 4); 1412 assert(sizeof(PURE_S_ZIP_EOCDR) == 4); 1413 while (index >= floor) { 1414 if ( 1415 buffer[index + 0] == PURE_S_ZIP_EOCDR[0] && 1416 buffer[index + 1] == PURE_S_ZIP_EOCDR[1] && 1417 buffer[index + 2] == PURE_S_ZIP_EOCDR[2] && 1418 buffer[index + 3] == PURE_S_ZIP_EOCDR[3] 1419 ) { 1420 assert(size >= PURE_ZIP_EOCDR_MIN); 1421 assert(!pure_overflow((uint64_t) index, 4, size)); 1422 *offset = (uint64_t) index; 1423 return 0; 1424 } 1425 index--; 1426 } 1427 return PURE_E_ZIP_EOCDR_NOT_FOUND; 1428 } 1429 1430 int pure_zip_locate_first_lfh( 1431 const uint8_t* buffer, 1432 const uint64_t size, 1433 const pure_zip_eocdr* eocdr, 1434 uint64_t* offset 1435 ) { 1436 assert(size >= 8); 1437 assert(*offset == 0); 1438 // We expect a Local File Header or End Of Central Directory Record signature: 1439 // TO DO: Test empty file OK. 1440 // TO DO: Test non-empty file OK. 1441 const uint8_t* string = eocdr->cd_records ? PURE_S_ZIP_LFH : PURE_S_ZIP_EOCDR; 1442 const uint64_t string_size = PURE_L_ZIP_LFH; 1443 assert(PURE_L_ZIP_EOCDR == PURE_L_ZIP_LFH); 1444 if (pure_eq(buffer, size, 0, string, string_size)) { 1445 *offset = 0; 1446 return 0; 1447 } 1448 // A spanned/split archive may be preceded by a special spanning signature: 1449 // See APPNOTE 8.5.3 and 8.5.4. 1450 // TO DO: Test spanned file OK (empty, non-empty). 1451 // TO DO: Test split file OK (empty, non-empty). 1452 if ( 1453 pure_eq(buffer, size, 0, PURE_S_ZIP_SPAN, PURE_L_ZIP_SPAN) || 1454 pure_eq(buffer, size, 0, PURE_S_ZIP_TEMP, PURE_L_ZIP_TEMP) 1455 ) { 1456 assert(PURE_L_ZIP_TEMP == PURE_L_ZIP_SPAN); 1457 if (pure_eq(buffer, size, PURE_L_ZIP_SPAN, string, string_size)) { 1458 *offset = PURE_L_ZIP_SPAN; 1459 return 0; 1460 } 1461 } 1462 uint64_t prepended_data_size = 0; 1463 int error = pure_search( 1464 buffer, // buffer 1465 size, // buffer_size 1466 0, // search_offset 1467 PURE_ZIP_PREPENDED_DATA_SEARCH_MAX, // search_size 1468 string, // string 1469 string_size, // string_size 1470 &prepended_data_size // offset 1471 ); 1472 // We could not find any end to the prepended data: 1473 if (error) return PURE_E_ZIP_PREPENDED_DATA; 1474 assert(prepended_data_size != 0); 1475 assert(prepended_data_size <= size); 1476 if (pure_zeroes(buffer, 0, prepended_data_size)) { 1477 return PURE_E_ZIP_PREPENDED_DATA_ZEROED; 1478 } else { 1479 return PURE_E_ZIP_PREPENDED_DATA_BUFFER_BLEED; 1480 } 1481 } 1482 1483 // Forward declaration required by pure_zip_data(): 1484 int pure_zip_meta_data( 1485 pure_ctx* ctx, 1486 const uint8_t* buffer, 1487 const uint64_t size 1488 ); 1489 1490 int pure_zip_data( 1491 pure_ctx* ctx, 1492 const uint8_t* buffer, 1493 const pure_zip_cdh* cdh, 1494 const pure_zip_lfh* lfh, 1495 uint8_t** data, 1496 uint64_t* data_size 1497 ) { 1498 if (cdh->directory) { 1499 assert(cdh->compressed_size == 0); 1500 assert(cdh->uncompressed_size == 0); 1501 return 0; 1502 } 1503 if (cdh->uncompressed_size == 0) { 1504 if (cdh->compressed_size == 0) return 0; 1505 if ( 1506 cdh->compressed_size == 2 && 1507 cdh->compression_method == PURE_ZIP_COMPRESSION_METHOD_DEFLATE && 1508 buffer[cdh->relative_offset + lfh->length + 0] == 3 && 1509 buffer[cdh->relative_offset + lfh->length + 1] == 0 1510 ) { 1511 return 0; 1512 } 1513 return PURE_E_ZIP_AD_NIHILO; 1514 } 1515 assert(cdh->compressed_size > 0); 1516 assert(cdh->compressed_size <= SIZE_MAX); 1517 assert(cdh->uncompressed_size > 0); 1518 assert(cdh->uncompressed_size <= SIZE_MAX); 1519 // We verify the compression ratio here, after first checking for LFH overlap: 1520 // We do this to return PURE_E_ZIP_BOMB_FIFIELD before PURE_E_ZIP_BOMB_RATIO. 1521 if ( 1522 pure_overflow(ctx->compressed_size, cdh->compressed_size, UINT64_MAX) || 1523 pure_overflow(ctx->uncompressed_size, cdh->uncompressed_size, UINT64_MAX) 1524 ) { 1525 return PURE_E_UINT64_OVERFLOW; 1526 } 1527 ctx->compressed_size += cdh->compressed_size; 1528 ctx->uncompressed_size += cdh->uncompressed_size; 1529 { 1530 int error = pure_zip_verify_compression_ratio( 1531 ctx->compressed_size, 1532 ctx->uncompressed_size 1533 ); 1534 if (error) return error; 1535 } 1536 uint8_t* raw = NULL; 1537 if (cdh->compression_method == PURE_ZIP_COMPRESSION_METHOD_DEFLATE) { 1538 { 1539 int error = pure_realloc(data, data_size, cdh->uncompressed_size); 1540 if (error) return error; 1541 } 1542 assert(*data != NULL); 1543 assert(*data_size >= cdh->uncompressed_size); 1544 { 1545 int error = pure_zip_inflate_raw( 1546 buffer + cdh->relative_offset + lfh->length, // compressed 1547 cdh->compressed_size, // compressed_size 1548 *data, // uncompressed 1549 cdh->uncompressed_size // uncompressed_size 1550 ); 1551 if (error) return error; 1552 } 1553 raw = *data; 1554 } else { 1555 assert(cdh->compression_method == PURE_ZIP_COMPRESSION_METHOD_NONE); 1556 raw = (uint8_t*) (buffer + cdh->relative_offset + lfh->length); 1557 } 1558 assert(raw != NULL); 1559 { 1560 uint64_t checksum = 0; 1561 int error = pure_zip_crc32(raw, cdh->uncompressed_size, &checksum); 1562 if (error) return error; 1563 if (checksum != cdh->crc32) return PURE_E_ZIP_CRC32; 1564 } 1565 // TO DO: Check for common ZIP extensions in addition to PK signature. 1566 if (pure_eq(raw, cdh->uncompressed_size, 0, PURE_S_ZIP_PK, PURE_L_ZIP_PK)) { 1567 int error = pure_zip_meta_data(ctx, raw, cdh->uncompressed_size); 1568 if (error) return error; 1569 } else { 1570 if ((++ctx->files) > PURE_FILES_MAX) return PURE_E_ZIP_BOMB_FILES; 1571 } 1572 return 0; 1573 } 1574 1575 int pure_zip_meta( 1576 pure_ctx* ctx, 1577 const uint8_t* buffer, 1578 const uint64_t size, 1579 uint8_t** data, 1580 uint64_t* data_size 1581 ) { 1582 // Update and check context against limits: 1583 if ((++ctx->depth) > PURE_DEPTH_MAX) return PURE_E_ZIP_BOMB_DEPTH; 1584 if ((++ctx->files) > PURE_FILES_MAX) return PURE_E_ZIP_BOMB_FILES; 1585 if ((++ctx->archives) > PURE_ARCHIVES_MAX) return PURE_E_ZIP_BOMB_ARCHIVES; 1586 if (pure_overflow(ctx->size, size, UINT64_MAX)) return PURE_E_UINT64_OVERFLOW; 1587 if ((ctx->size += size) > PURE_SIZE_MAX) return PURE_E_SIZE_MAX; 1588 1589 // A zip file must contain at least an end of central directory record: 1590 if (size < PURE_ZIP_EOCDR_MIN) return PURE_E_ZIP_TOO_SMALL; 1591 1592 // ZIP64: 1593 if (size > 4294967295) return PURE_E_ZIP_SIZE_4GB; 1594 1595 // Malicious archive signatures (almost certainly when masquerading as a ZIP): 1596 if (pure_eq(buffer, size, 0, PURE_S_RAR, PURE_L_RAR)) return PURE_E_ZIP_RAR; 1597 if (pure_eq(buffer, size, 0, PURE_S_TAR, PURE_L_TAR)) return PURE_E_ZIP_TAR; 1598 if (pure_eq(buffer, size, 0, PURE_S_XAR, PURE_L_XAR)) return PURE_E_ZIP_XAR; 1599 1600 // Locate and decode end of central directory record: 1601 uint64_t eocdr_offset = 0; 1602 pure_zip_eocdr eocdr; 1603 { 1604 int error = pure_zip_locate_eocdr(buffer, size, &eocdr_offset); 1605 if (error) return error; 1606 } 1607 { 1608 int error = pure_zip_decode_eocdr(buffer, size, eocdr_offset, &eocdr); 1609 if (error) return error; 1610 } 1611 1612 // Locate the offset of the first local file header: 1613 uint64_t lfh_offset = 0; 1614 { 1615 int error = pure_zip_locate_first_lfh(buffer, size, &eocdr, &lfh_offset); 1616 if (error) return error; 1617 assert(lfh_offset == 0 || lfh_offset == PURE_L_ZIP_SPAN); 1618 } 1619 1620 // Compare central directory headers with local file headers: 1621 pure_zip_cdh cdh; 1622 pure_zip_lfh lfh; 1623 pure_zip_ddr ddr; 1624 pure_zip_cdh cdh_p; 1625 pure_zip_lfh lfh_p; 1626 uint64_t cdh_offset = eocdr.cd_offset; 1627 uint64_t cdh_record = 0; 1628 while (cdh_record < eocdr.cd_records) { 1629 // Central Directory Header: 1630 { 1631 int error = pure_zip_decode_cdh(buffer, size, cdh_offset, &cdh); 1632 if (error) return error; 1633 } 1634 if (lfh_offset > cdh.relative_offset) { 1635 if ( 1636 cdh.directory && cdh.relative_offset == 0 && 1637 cdh.crc32 == 0 && cdh.compressed_size == 0 && cdh.uncompressed_size == 0 1638 ) { 1639 return PURE_E_ZIP_DIRECTORY_HAS_NO_LFH; 1640 } 1641 return PURE_E_ZIP_BOMB_FIFIELD; 1642 } 1643 if (lfh_offset < cdh.relative_offset) { 1644 assert(cdh.relative_offset <= size); 1645 if (pure_zeroes(buffer, lfh_offset, cdh.relative_offset)) { 1646 return PURE_E_ZIP_LFH_UNDERFLOW_ZEROED; 1647 } else { 1648 return PURE_E_ZIP_LFH_UNDERFLOW_BUFFER_BLEED; 1649 } 1650 } 1651 // Local File Header: 1652 { 1653 assert(cdh.relative_offset == lfh_offset); 1654 int error = pure_zip_decode_lfh(buffer, size, cdh.relative_offset, &lfh); 1655 if (error) return error; 1656 } 1657 { 1658 int error = pure_zip_diff_cdh_lfh(&cdh, &lfh); 1659 if (error) return error; 1660 } 1661 { 1662 int error = pure_zip_verify_symlink(&cdh, &lfh, buffer); 1663 if (error) return error; 1664 } 1665 assert(lfh.length >= PURE_ZIP_LFH_MIN); 1666 lfh_offset += lfh.length; 1667 // File Data (compressed or uncompressed): 1668 if (pure_overflow(lfh_offset, cdh.compressed_size, UINT64_MAX)) { 1669 return PURE_E_UINT64_OVERFLOW; 1670 } 1671 lfh_offset += cdh.compressed_size; 1672 if (lfh_offset > size) return PURE_E_ZIP_LFH_DATA_OVERFLOW; 1673 // Data Descriptor Record (optional): 1674 if (lfh.general_purpose_bit_flag & (1 << 3)) { 1675 { 1676 ddr.zip64 = lfh.zip64; 1677 int error = pure_zip_decode_ddr(buffer, size, lfh_offset, &ddr); 1678 if (error) return error; 1679 } 1680 { 1681 int error = pure_zip_diff_cdh_ddr(&cdh, &ddr); 1682 if (error) return error; 1683 } 1684 { 1685 int error = pure_zip_diff_ddr_lfh(&ddr, &lfh); 1686 if (error) return error; 1687 } 1688 lfh_offset += ddr.length; 1689 } 1690 if (lfh_offset > eocdr.cd_offset) return PURE_E_ZIP_LF_OVERFLOW; 1691 // We descend into the data only after checking for LFH overlap above: 1692 // We can therefore descend only after decoding at least two entries. 1693 if (cdh_record > 0) { 1694 int error = pure_zip_data(ctx, buffer, &cdh_p, &lfh_p, data, data_size); 1695 if (error) return error; 1696 } 1697 // Shallow copy the CDH and LFH to descend next time around the loop: 1698 cdh_p = cdh; 1699 lfh_p = lfh; 1700 assert(cdh.length >= PURE_ZIP_CDH_MIN); 1701 cdh_offset += cdh.length; 1702 cdh_record++; 1703 } 1704 // Descend into the previous CDH and LFH: 1705 if (cdh_record > 0) { 1706 int error = pure_zip_data(ctx, buffer, &cdh_p, &lfh_p, data, data_size); 1707 if (error) return error; 1708 } 1709 if (lfh_offset > eocdr.cd_offset) return PURE_E_ZIP_LF_OVERFLOW; 1710 if (lfh_offset < eocdr.cd_offset) { 1711 assert(eocdr.cd_offset <= size); 1712 if (pure_zeroes(buffer, lfh_offset, eocdr.cd_offset)) { 1713 return PURE_E_ZIP_LF_UNDERFLOW_ZEROED; 1714 } else { 1715 return PURE_E_ZIP_LF_UNDERFLOW_BUFFER_BLEED; 1716 } 1717 } 1718 uint64_t cdh_offset_expected = eocdr.cd_offset + eocdr.cd_size; 1719 if (cdh_offset > cdh_offset_expected) return PURE_E_ZIP_CD_OVERFLOW; 1720 if (cdh_offset < cdh_offset_expected) { 1721 assert(cdh_offset_expected <= size); 1722 if (pure_zeroes(buffer, cdh_offset, cdh_offset_expected)) { 1723 return PURE_E_ZIP_CD_UNDERFLOW_ZEROED; 1724 } else { 1725 return PURE_E_ZIP_CD_UNDERFLOW_BUFFER_BLEED; 1726 } 1727 } 1728 if (cdh_offset < eocdr.offset) { 1729 assert(eocdr.offset <= size); 1730 if (pure_zeroes(buffer, cdh_offset, eocdr.offset)) { 1731 return PURE_E_ZIP_CD_EOCDR_UNDERFLOW_ZEROED; 1732 } else { 1733 return PURE_E_ZIP_CD_EOCDR_UNDERFLOW_BUFFER_BLEED; 1734 } 1735 } 1736 assert(cdh_offset == eocdr.offset); 1737 assert(cdh_offset + eocdr.length == size); 1738 assert(ctx->depth > 0); 1739 ctx->depth--; 1740 return PURE_E_OK; 1741 } 1742 1743 int pure_zip_meta_data( 1744 pure_ctx* ctx, 1745 const uint8_t* buffer, 1746 const uint64_t size 1747 ) { 1748 uint8_t* data = NULL; 1749 uint64_t data_size = 0; 1750 int error = pure_zip_meta(ctx, buffer, size, &data, &data_size); 1751 pure_free(&data, &data_size); 1752 assert(data == NULL); 1753 assert(data_size == 0); 1754 return error; 1755 } 1756 1757 int pure_zip( 1758 const uint8_t* buffer, // Zip file buffer 1759 const uint64_t size, // Size of zip file buffer in bytes 1760 const uint64_t flags // Bit flags (optional) 1761 ) { 1762 // SPEC: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT 1763 1764 // Further, as per ISO/IEC 21320-1:2015, we disable support for: 1765 // * multiple disks 1766 // * encryption and archive headers 1767 // * encryption mechanisms 1768 // * compression methods other than 0 or 8 1769 // * ZIP64 version 2 (and we also disable ZIP64 version 1) 1770 // * unused and reserved flags 1771 1772 // Contrary to ISO/IEC 21320-1:2015, we do not require: 1773 // * `version needed to extract` to be at most 45 (too many false positives) 1774 // * bit 11 (UTF-8) when a string byte exceeds 0x7F (this could also be CP437) 1775 pure_ctx ctx; 1776 ctx.flags = flags; 1777 ctx.depth = 0; 1778 ctx.files = 0; 1779 ctx.archives = 0; 1780 ctx.size = 0; 1781 ctx.compressed_size = 0; 1782 ctx.uncompressed_size = 0; 1783 return pure_zip_meta_data(&ctx, buffer, size); 1784 } 1785 1786 int pure_zip_bomb(const int error) { 1787 if (error == PURE_E_ZIP_BOMB_ARCHIVES) return 1; 1788 if (error == PURE_E_ZIP_BOMB_DEPTH) return 1; 1789 if (error == PURE_E_ZIP_BOMB_FILES) return 1; 1790 if (error == PURE_E_ZIP_BOMB_FIFIELD) return 1; 1791 if (error == PURE_E_ZIP_BOMB_RATIO) return 1; 1792 if (error == PURE_E_ZIP_BOMB_INFLATE_COMPRESSED_OVERFLOW) return 1; 1793 if (error == PURE_E_ZIP_BOMB_INFLATE_UNCOMPRESSED_OVERFLOW) return 1; 1794 return 0; 1795 } 1796 1797 const char* pure_error_code(const int error) { 1798 assert(error >= 0); 1799 assert(error < PURE_E_ENUM_LENGTH); 1800 if (error < 0 || error >= PURE_E_ENUM_LENGTH) return ""; 1801 return PURE_E_CODES[error]; 1802 } 1803 1804 const char* pure_error_string(const int error) { 1805 assert(error >= 0); 1806 assert(error < PURE_E_ENUM_LENGTH); 1807 if (error < 0 || error >= PURE_E_ENUM_LENGTH) return ""; 1808 return PURE_E_STRINGS[error]; 1809 } 1810 1811 #endif /* PURE_H */