Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 deletions deps/zlib/google/zip_reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/i18n/i18n_constants.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
Expand Down Expand Up @@ -307,25 +308,63 @@ bool ZipReader::OpenEntry() {
DCHECK(path_in_zip[info.size_filename] == '\0');
entry_.path_in_original_encoding = path_in_zip.data();

const char* const configured_encoding =
encoding_.empty() ? base::kCodepageUTF8 : encoding_.c_str();
const char* entry_path_encoding = configured_encoding;
bool physical_path_is_directory = false;
bool physical_path_is_unsafe = false;

// If an Info-ZIP Unicode Path Extra Field is present, the physical Central
// Directory path is about to be overridden. Decode and normalize it now into
// `entry_.physical_path` so consumers (e.g. Safe Browsing) can still see the
// name that other tools (e.g. Windows Explorer) would use for extraction.
if (info.size_utf8_filename > 0) {
std::u16string physical_path_in_utf16;
if (!base::CodepageToUTF16(entry_.path_in_original_encoding,
configured_encoding,
base::OnStringConversionError::SUBSTITUTE,
&physical_path_in_utf16)) {
LOG(ERROR) << "Cannot convert path from encoding " << configured_encoding;
return false;
}
// Normalize() stores the normalized result in entry_.path; copy it before
// applying the Unicode Path Extra Field below.
Normalize(physical_path_in_utf16);
entry_.physical_path = entry_.path;
physical_path_is_directory = entry_.is_directory;
physical_path_is_unsafe = entry_.is_unsafe;

// Use the Info-ZIP Unicode Path Extra Field if present.
DCHECK(info.utf8_filename[info.size_utf8_filename] == '\0');
entry_.path_in_original_encoding = info.utf8_filename;
entry_path_encoding = base::kCodepageUTF8;
}

// Convert path from original encoding to Unicode.
std::u16string path_in_utf16;
const char* const encoding = encoding_.empty() ? "UTF-8" : encoding_.c_str();
if (!base::CodepageToUTF16(entry_.path_in_original_encoding, encoding,
if (!base::CodepageToUTF16(entry_.path_in_original_encoding,
entry_path_encoding,
base::OnStringConversionError::SUBSTITUTE,
&path_in_utf16)) {
LOG(ERROR) << "Cannot convert path from encoding " << encoding;
LOG(ERROR) << "Cannot convert path from encoding " << entry_path_encoding;
return false;
}

// Normalize path.
Normalize(path_in_utf16);

if (info.size_utf8_filename > 0) {
// Treat an entry as a directory only if both names are directories;
// otherwise callers that analyze file entries should inspect it as a file.
entry_.is_directory = entry_.is_directory && physical_path_is_directory;
// Treat an entry as unsafe if either name is unsafe.
entry_.is_unsafe = entry_.is_unsafe || physical_path_is_unsafe;
} else {
// In the common case (no Unicode Path Extra Field) the physical path
// matches the effective path.
entry_.physical_path = entry_.path;
}

entry_.original_size = info.uncompressed_size;

// The file content of this entry is encrypted if flag bit 0 is set.
Expand Down
5 changes: 5 additions & 0 deletions deps/zlib/google/zip_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ class ZipReader {
// ./a -> DOT/a
base::FilePath path;

// Physical path from the ZIP Central Directory, before applying the
// Info-ZIP Unicode Path Extra Field. This is converted and normalized in
// the same way as `path`.
base::FilePath physical_path;

// Size of the original uncompressed file, or 0 if the entry is a directory.
// This value should not be trusted, because it is stored as metadata in the
// ZIP archive and can be different from the real uncompressed size.
Expand Down
117 changes: 117 additions & 0 deletions deps/zlib/google/zip_reader_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,123 @@ TEST_F(ZipReaderTest, WrongFilenameLength) {
reader.Next();
}

TEST_F(ZipReaderTest, UnicodePathExtraFieldPreservesPhysicalPath) {
static const char test_data[] = {
0x50, 0x4b, 0x03, 0x04, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71,
0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00,
0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72,
0x65, 0x2e, 0x65, 0x78, 0x65, 0x54, 0x65, 0x73, 0x74, 0x20, 0x64, 0x61,
0x74, 0x61, 0x50, 0x4b, 0x01, 0x02, 0x3f, 0x03, 0x0a, 0x03, 0x00, 0x00,
0x00, 0x00, 0xd0, 0x71, 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0xc9, 0x81, 0x00, 0x00, 0x00, 0x00,
0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65, 0x75,
0x70, 0x11, 0x00, 0x01, 0xed, 0x4b, 0x16, 0x3c, 0x64, 0x6f, 0x77, 0x6e,
0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4e, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x00, 0x00};

std::string test_string(test_data, sizeof(test_data));
ZipReader reader;
ASSERT_TRUE(reader.OpenFromString(test_string));
const ZipReader::Entry* entry = reader.Next();
ASSERT_TRUE(entry);
// The Unicode Path Extra Field overrides the Central Directory filename,
// but the original physical path is preserved separately. `is_unsafe` tracks
// path traversal safety, not whether the filename looks executable.
EXPECT_EQ(base::FilePath::FromUTF8Unsafe("download.txt"), entry->path);
EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe"),
entry->physical_path);
EXPECT_FALSE(entry->is_directory);
EXPECT_FALSE(entry->is_unsafe);
}

TEST_F(ZipReaderTest, UnicodePathExtraFieldUsesUtf8WithConfiguredEncoding) {
static constexpr uint8_t test_data[] = {
0x50, 0x4b, 0x03, 0x04, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71,
0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00,
0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72,
0x65, 0x2e, 0x65, 0x78, 0x65, 0x54, 0x65, 0x73, 0x74, 0x20, 0x64, 0x61,
0x74, 0x61, 0x50, 0x4b, 0x01, 0x02, 0x3f, 0x03, 0x0a, 0x03, 0x00, 0x00,
0x00, 0x00, 0xd0, 0x71, 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0xc9, 0x81, 0x00, 0x00, 0x00, 0x00,
0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65, 0x75,
0x70, 0x11, 0x00, 0x01, 0xed, 0x4b, 0x16, 0x3c, 0x72, 0xc3, 0xa9, 0x73,
0x75, 0x6d, 0xc3, 0xa9, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4e, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x00, 0x00};

std::string test_string(reinterpret_cast<const char*>(test_data),
sizeof(test_data));
ZipReader reader;
ASSERT_TRUE(reader.OpenFromString(test_string));
reader.SetEncoding("windows-1252");
const ZipReader::Entry* entry = reader.Next();
ASSERT_TRUE(entry);
EXPECT_EQ(base::FilePath::FromUTF8Unsafe("résumé.txt"), entry->path);
EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe"),
entry->physical_path);
}

TEST_F(ZipReaderTest, UnicodePathExtraFieldFileIfEitherPathIsFile) {
static const char test_data[] = {
0x50, 0x4b, 0x03, 0x04, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71,
0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00,
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72,
0x65, 0x2e, 0x65, 0x78, 0x65, 0x2f, 0x54, 0x65, 0x73, 0x74, 0x20, 0x64,
0x61, 0x74, 0x61, 0x50, 0x4b, 0x01, 0x02, 0x3f, 0x03, 0x0a, 0x03, 0x00,
0x00, 0x00, 0x00, 0xd0, 0x71, 0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09,
0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0xc9, 0x81, 0x00, 0x00, 0x00,
0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65,
0x2f, 0x75, 0x70, 0x10, 0x00, 0x01, 0x5a, 0x5a, 0x54, 0xa7, 0x6d, 0x61,
0x6c, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65, 0x50, 0x4b, 0x05,
0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4e, 0x00, 0x00,
0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00};

std::string test_string(test_data, sizeof(test_data));
ZipReader reader;
ASSERT_TRUE(reader.OpenFromString(test_string));
const ZipReader::Entry* entry = reader.Next();
ASSERT_TRUE(entry);
EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe"), entry->path);
EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe/"),
entry->physical_path);
EXPECT_FALSE(entry->is_directory);
EXPECT_FALSE(entry->is_unsafe);
}

TEST_F(ZipReaderTest, UnicodePathExtraFieldPreservesUnsafePhysicalPath) {
static const char test_data[] = {
0x50, 0x4b, 0x03, 0x04, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71,
0x91, 0x4e, 0x11, 0x2c, 0xf9, 0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00,
0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c,
0x77, 0x61, 0x72, 0x65, 0x2e, 0x65, 0x78, 0x65, 0x2f,
0x2e, 0x2e, 0x54, 0x65, 0x73, 0x74,
0x20, 0x64, 0x61, 0x74, 0x61, 0x50, 0x4b, 0x01, 0x02, 0x3f, 0x03, 0x0a,
0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x71, 0x91, 0x4e, 0x11, 0x2c, 0xf9,
0x51, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x15,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0xc9, 0x81, 0x00,
0x00, 0x00, 0x00, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72,
0x65, 0x2e, 0x65, 0x78, 0x65, 0x2f, 0x2e, 0x2e, 0x75,
0x70, 0x11, 0x00, 0x01, 0x7c, 0xbc, 0xe2, 0x5d, 0x64,
0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x74,
0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x01, 0x00, 0x51, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00};

std::string test_string(test_data, sizeof(test_data));
ZipReader reader;
ASSERT_TRUE(reader.OpenFromString(test_string));
const ZipReader::Entry* entry = reader.Next();
ASSERT_TRUE(entry);
EXPECT_EQ(base::FilePath::FromUTF8Unsafe("download.txt"), entry->path);
EXPECT_EQ(base::FilePath::FromUTF8Unsafe("malware.exe/UP"),
entry->physical_path);
EXPECT_FALSE(entry->is_directory);
EXPECT_TRUE(entry->is_unsafe);
}

class FileWriterDelegateTest : public ::testing::Test {
protected:
void SetUp() override {
Expand Down
2 changes: 1 addition & 1 deletion src/zlib_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
// Refer to tools/dep_updaters/update-zlib.sh
#ifndef SRC_ZLIB_VERSION_H_
#define SRC_ZLIB_VERSION_H_
#define ZLIB_VERSION "1.3.2.1-motley-8b3aa8a"
#define ZLIB_VERSION "1.3.2.1-motley-42c2f19"
#endif // SRC_ZLIB_VERSION_H_
Loading