| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,6 +16,7 @@ | |||
| 16 | 16 | #include "base/files/file.h" | |
| 17 | 17 | #include "base/files/file_util.h" | |
| 18 | 18 | #include "base/functional/bind.h" | |
| 19 | + #include "base/i18n/i18n_constants.h" | ||
| 19 | 20 | #include "base/i18n/icu_string_conversions.h" | |
| 20 | 21 | #include "base/logging.h" | |
| 21 | 22 | #include "base/numerics/safe_conversions.h" | |
@@ -307,25 +308,63 @@ bool ZipReader::OpenEntry() { | |||
| 307 | 308 | DCHECK(path_in_zip[info.size_filename] == '\0'); | |
| 308 | 309 | entry_.path_in_original_encoding = path_in_zip.data(); | |
| 309 | 310 | ||
| 311 | + const char* const configured_encoding = | ||
| 312 | + encoding_.empty() ? base::kCodepageUTF8 : encoding_.c_str(); | ||
| 313 | + const char* entry_path_encoding = configured_encoding; | ||
| 314 | + bool physical_path_is_directory = false; | ||
| 315 | + bool physical_path_is_unsafe = false; | ||
| 316 | + | ||
| 317 | + // If an Info-ZIP Unicode Path Extra Field is present, the physical Central | ||
| 318 | + // Directory path is about to be overridden. Decode and normalize it now into | ||
| 319 | + // `entry_.physical_path` so consumers (e.g. Safe Browsing) can still see the | ||
| 320 | + // name that other tools (e.g. Windows Explorer) would use for extraction. | ||
| 310 | 321 | if (info.size_utf8_filename > 0) { | |
| 322 | + std::u16string physical_path_in_utf16; | ||
| 323 | + if (!base::CodepageToUTF16(entry_.path_in_original_encoding, | ||
| 324 | + configured_encoding, | ||
| 325 | + base::OnStringConversionError::SUBSTITUTE, | ||
| 326 | + &physical_path_in_utf16)) { | ||
| 327 | + LOG(ERROR) << "Cannot convert path from encoding " << configured_encoding; | ||
| 328 | + return false; | ||
| 329 | + } | ||
| 330 | + // Normalize() stores the normalized result in entry_.path; copy it before | ||
| 331 | + // applying the Unicode Path Extra Field below. | ||
| 332 | + Normalize(physical_path_in_utf16); | ||
| 333 | + entry_.physical_path = entry_.path; | ||
| 334 | + physical_path_is_directory = entry_.is_directory; | ||
| 335 | + physical_path_is_unsafe = entry_.is_unsafe; | ||
| 336 | + | ||
| 311 | 337 | // Use the Info-ZIP Unicode Path Extra Field if present. | |
| 312 | 338 | DCHECK(info.utf8_filename[info.size_utf8_filename] == '\0'); | |
| 313 | 339 | entry_.path_in_original_encoding = info.utf8_filename; | |
| 340 | + entry_path_encoding = base::kCodepageUTF8; | ||
| 314 | 341 | } | |
| 315 | 342 | ||
| 316 | 343 | // Convert path from original encoding to Unicode. | |
| 317 | 344 | std::u16string path_in_utf16; | |
| 318 | - const char* const encoding = encoding_.empty() ? "UTF-8" : encoding_.c_str(); | ||
| 319 | - if (!base::CodepageToUTF16(entry_.path_in_original_encoding, encoding, | ||
| 345 | + if (!base::CodepageToUTF16(entry_.path_in_original_encoding, | ||
| 346 | + entry_path_encoding, | ||
| 320 | 347 | base::OnStringConversionError::SUBSTITUTE, | |
| 321 | 348 | &path_in_utf16)) { | |
| 322 | - LOG(ERROR) << "Cannot convert path from encoding " << encoding; | ||
| 349 | + LOG(ERROR) << "Cannot convert path from encoding " << entry_path_encoding; | ||
| 323 | 350 | return false; | |
| 324 | 351 | } | |
| 325 | 352 | ||
| 326 | 353 | // Normalize path. | |
| 327 | 354 | Normalize(path_in_utf16); | |
| 328 | 355 | ||
| 356 | + if (info.size_utf8_filename > 0) { | ||
| 357 | + // Treat an entry as a directory only if both names are directories; | ||
| 358 | + // otherwise callers that analyze file entries should inspect it as a file. | ||
| 359 | + entry_.is_directory = entry_.is_directory && physical_path_is_directory; | ||
| 360 | + // Treat an entry as unsafe if either name is unsafe. | ||
| 361 | + entry_.is_unsafe = entry_.is_unsafe || physical_path_is_unsafe; | ||
| 362 | + } else { | ||
| 363 | + // In the common case (no Unicode Path Extra Field) the physical path | ||
| 364 | + // matches the effective path. | ||
| 365 | + entry_.physical_path = entry_.path; | ||
| 366 | + } | ||
| 367 | + | ||
| 329 | 368 | entry_.original_size = info.uncompressed_size; | |
| 330 | 369 | ||
| 331 | 370 | // The file content of this entry is encrypted if flag bit 0 is set. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -130,6 +130,11 @@ class ZipReader { | |||
| 130 | 130 | // ./a -> DOT/a | |
| 131 | 131 | base::FilePath path; | |
| 132 | 132 | ||
| 133 | + // Physical path from the ZIP Central Directory, before applying the | ||
| 134 | + // Info-ZIP Unicode Path Extra Field. This is converted and normalized in | ||
| 135 | + // the same way as `path`. | ||
| 136 | + base::FilePath physical_path; | ||
| 137 | + | ||
| 133 | 138 | // Size of the original uncompressed file, or 0 if the entry is a directory. | |
| 134 | 139 | // This value should not be trusted, because it is stored as metadata in the | |
| 135 | 140 | // ZIP archive and can be different from the real uncompressed size. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -998,6 +998,123 @@ TEST_F(ZipReaderTest, WrongFilenameLength) { | |||
| 998 | 998 | reader.Next(); | |
| 999 | 999 | } | |
| 1000 | 1000 | ||
| 1001 | + TEST_F(ZipReaderTest, UnicodePathExtraFieldPreservesPhysicalPath) { | ||
| 1002 | + static const char test_data[] = { | ||
| 1003 | + 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71, | ||
| 1004 | + 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, | ||
| 1005 | + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, | ||
| 1006 | + 0x65, 0x2e, 0x65, 0x78, 0x65, 0x54, 0x65, 0x73, 0x74, 0x20, 0x64, 0x61, | ||
| 1007 | + 0x74, 0x61, 0x50, 0x4b, 0x01, 0x02, 0x3f, 0x03, 0x0a, 0x03, 0x00, 0x00, | ||
| 1008 | + 0x00, 0x00, 0xd0, 0x71, 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, | ||
| 1009 | + 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 1010 | + 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0xc9, 0x81, 0x00, 0x00, 0x00, 0x00, | ||
| 1011 | + 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65, 0x75, | ||
| 1012 | + 0x70, 0x11, 0x00, 0x01, 0xed, 0x4b, 0x16, 0x3c, 0x64, 0x6f, 0x77, 0x6e, | ||
| 1013 | + 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, | ||
| 1014 | + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4e, 0x00, 0x00, 0x00, | ||
| 1015 | + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 1016 | + | ||
| 1017 | + std::string test_string(test_data, sizeof(test_data)); | ||
| 1018 | + ZipReader reader; | ||
| 1019 | + ASSERT_TRUE(reader.OpenFromString(test_string)); | ||
| 1020 | + const ZipReader::Entry* entry = reader.Next(); | ||
| 1021 | + ASSERT_TRUE(entry); | ||
| 1022 | + // The Unicode Path Extra Field overrides the Central Directory filename, | ||
| 1023 | + // but the original physical path is preserved separately. `is_unsafe` tracks | ||
| 1024 | + // path traversal safety, not whether the filename looks executable. | ||
| 1025 | + EXPECT_EQ(base::FilePath::FromUTF8Unsafe("download.txt"), entry->path); | ||
| 1026 | + EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe"), | ||
| 1027 | + entry->physical_path); | ||
| 1028 | + EXPECT_FALSE(entry->is_directory); | ||
| 1029 | + EXPECT_FALSE(entry->is_unsafe); | ||
| 1030 | + } | ||
| 1031 | + | ||
| 1032 | + TEST_F(ZipReaderTest, UnicodePathExtraFieldUsesUtf8WithConfiguredEncoding) { | ||
| 1033 | + static constexpr uint8_t test_data[] = { | ||
| 1034 | + 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71, | ||
| 1035 | + 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, | ||
| 1036 | + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, | ||
| 1037 | + 0x65, 0x2e, 0x65, 0x78, 0x65, 0x54, 0x65, 0x73, 0x74, 0x20, 0x64, 0x61, | ||
| 1038 | + 0x74, 0x61, 0x50, 0x4b, 0x01, 0x02, 0x3f, 0x03, 0x0a, 0x03, 0x00, 0x00, | ||
| 1039 | + 0x00, 0x00, 0xd0, 0x71, 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, | ||
| 1040 | + 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 1041 | + 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0xc9, 0x81, 0x00, 0x00, 0x00, 0x00, | ||
| 1042 | + 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65, 0x75, | ||
| 1043 | + 0x70, 0x11, 0x00, 0x01, 0xed, 0x4b, 0x16, 0x3c, 0x72, 0xc3, 0xa9, 0x73, | ||
| 1044 | + 0x75, 0x6d, 0xc3, 0xa9, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, | ||
| 1045 | + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4e, 0x00, 0x00, 0x00, | ||
| 1046 | + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 1047 | + | ||
| 1048 | + std::string test_string(reinterpret_cast<const char*>(test_data), | ||
| 1049 | + sizeof(test_data)); | ||
| 1050 | + ZipReader reader; | ||
| 1051 | + ASSERT_TRUE(reader.OpenFromString(test_string)); | ||
| 1052 | + reader.SetEncoding("windows-1252"); | ||
| 1053 | + const ZipReader::Entry* entry = reader.Next(); | ||
| 1054 | + ASSERT_TRUE(entry); | ||
| 1055 | + EXPECT_EQ(base::FilePath::FromUTF8Unsafe("résumé.txt"), entry->path); | ||
| 1056 | + EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe"), | ||
| 1057 | + entry->physical_path); | ||
| 1058 | + } | ||
| 1059 | + | ||
| 1060 | + TEST_F(ZipReaderTest, UnicodePathExtraFieldFileIfEitherPathIsFile) { | ||
| 1061 | + static const char test_data[] = { | ||
| 1062 | + 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71, | ||
| 1063 | + 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, | ||
| 1064 | + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, | ||
| 1065 | + 0x65, 0x2e, 0x65, 0x78, 0x65, 0x2f, 0x54, 0x65, 0x73, 0x74, 0x20, 0x64, | ||
| 1066 | + 0x61, 0x74, 0x61, 0x50, 0x4b, 0x01, 0x02, 0x3f, 0x03, 0x0a, 0x03, 0x00, | ||
| 1067 | + 0x00, 0x00, 0x00, 0xd0, 0x71, 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, | ||
| 1068 | + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x00, | ||
| 1069 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0xc9, 0x81, 0x00, 0x00, 0x00, | ||
| 1070 | + 0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65, | ||
| 1071 | + 0x2f, 0x75, 0x70, 0x10, 0x00, 0x01, 0x5a, 0x5a, 0x54, 0xa7, 0x6d, 0x61, | ||
| 1072 | + 0x6c, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65, 0x50, 0x4b, 0x05, | ||
| 1073 | + 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4e, 0x00, 0x00, | ||
| 1074 | + 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 1075 | + | ||
| 1076 | + std::string test_string(test_data, sizeof(test_data)); | ||
| 1077 | + ZipReader reader; | ||
| 1078 | + ASSERT_TRUE(reader.OpenFromString(test_string)); | ||
| 1079 | + const ZipReader::Entry* entry = reader.Next(); | ||
| 1080 | + ASSERT_TRUE(entry); | ||
| 1081 | + EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe"), entry->path); | ||
| 1082 | + EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe/"), | ||
| 1083 | + entry->physical_path); | ||
| 1084 | + EXPECT_FALSE(entry->is_directory); | ||
| 1085 | + EXPECT_FALSE(entry->is_unsafe); | ||
| 1086 | + } | ||
| 1087 | + | ||
| 1088 | + TEST_F(ZipReaderTest, UnicodePathExtraFieldPreservesUnsafePhysicalPath) { | ||
| 1089 | + static const char test_data[] = { | ||
| 1090 | + 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71, | ||
| 1091 | + 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, | ||
| 1092 | + 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c, | ||
| 1093 | + 0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65, 0x2f, | ||
| 1094 | + 0x2e, 0x2e, 0x54, 0x65, 0x73, 0x74, | ||
| 1095 | + 0x20, 0x64, 0x61, 0x74, 0x61, 0x50, 0x4b, 0x01, 0x02, 0x3f, 0x03, 0x0a, | ||
| 1096 | + 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71, 0x91, 0x4e, 0x11, 0x2c, 0xf9, | ||
| 1097 | + 0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x15, | ||
| 1098 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0xc9, 0x81, 0x00, | ||
| 1099 | + 0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, | ||
| 1100 | + 0x65, 0x2e, 0x65, 0x78, 0x65, 0x2f, 0x2e, 0x2e, 0x75, | ||
| 1101 | + 0x70, 0x11, 0x00, 0x01, 0x7c, 0xbc, 0xe2, 0x5d, 0x64, | ||
| 1102 | + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x74, | ||
| 1103 | + 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, | ||
| 1104 | + 0x01, 0x00, 0x51, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 1105 | + | ||
| 1106 | + std::string test_string(test_data, sizeof(test_data)); | ||
| 1107 | + ZipReader reader; | ||
| 1108 | + ASSERT_TRUE(reader.OpenFromString(test_string)); | ||
| 1109 | + const ZipReader::Entry* entry = reader.Next(); | ||
| 1110 | + ASSERT_TRUE(entry); | ||
| 1111 | + EXPECT_EQ(base::FilePath::FromUTF8Unsafe("download.txt"), entry->path); | ||
| 1112 | + EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe/UP"), | ||
| 1113 | + entry->physical_path); | ||
| 1114 | + EXPECT_FALSE(entry->is_directory); | ||
| 1115 | + EXPECT_TRUE(entry->is_unsafe); | ||
| 1116 | + } | ||
| 1117 | + | ||
| 1001 | 1118 | class FileWriterDelegateTest : public ::testing::Test { | |
| 1002 | 1119 | protected: | |
| 1003 | 1120 | void SetUp() override { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,5 +2,5 @@ | |||
| 2 | 2 | // Refer to tools/dep_updaters/update-zlib.sh | |
| 3 | 3 | #ifndef SRC_ZLIB_VERSION_H_ | |
| 4 | 4 | #define SRC_ZLIB_VERSION_H_ | |
| 5 | - #define ZLIB_VERSION "1.3.2.1-motley-8b3aa8a" | ||
| 5 | + #define ZLIB_VERSION "1.3.2.1-motley-42c2f19" | ||
| 6 | 6 | #endif // SRC_ZLIB_VERSION_H_ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments