@@ -998,6 +998,123 @@ TEST_F(ZipReaderTest, WrongFilenameLength) {
998998 reader.Next ();
999999}
10001000
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+
10011118class FileWriterDelegateTest : public ::testing::Test {
10021119 protected:
10031120 void SetUp () override {
0 commit comments