#include "chrome/browser/safe_browsing/download_protection/file_analyzer.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/safe_browsing/archive_analyzer_results.h"
#include "chrome/common/safe_browsing/mock_binary_feature_extractor.h"
#include "components/safe_browsing/content/common/file_type_policies_test_util.h"
#include "components/safe_browsing/core/common/features.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/zlib/google/zip.h"
namespace safe_browsing {
_;
DoAll;
IsEmpty;
Return;
SetArgPointee;
SizeIs;
StrEq;
class FileAnalyzerTest : public testing::Test { … };
TEST_F(FileAnalyzerTest, TypeWinExecutable) { … }
TEST_F(FileAnalyzerTest, TypeChromeExtension) { … }
TEST_F(FileAnalyzerTest, TypeAndroidApk) { … }
TEST_F(FileAnalyzerTest, TypeZippedExecutable) { … }
TEST_F(FileAnalyzerTest, TypeMacExecutable) { … }
TEST_F(FileAnalyzerTest, TypeZippedArchive) { … }
TEST_F(FileAnalyzerTest, TypeInvalidZip) { … }
#if BUILDFLAG(IS_MAC)
TEST_F(FileAnalyzerTest, TypeInvalidDmg) {
scoped_refptr<MockBinaryFeatureExtractor> extractor =
new testing::StrictMock<MockBinaryFeatureExtractor>();
FileAnalyzer analyzer(extractor);
base::RunLoop run_loop;
base::FilePath target_path(FILE_PATH_LITERAL("target.dmg"));
base::FilePath tmp_path =
temp_dir_.GetPath().Append(FILE_PATH_LITERAL("tmp.crdownload"));
std::string file_contents = "invalid contents";
ASSERT_TRUE(base::WriteFile(tmp_path, file_contents));
analyzer.Start(
target_path, tmp_path, std::nullopt,
base::BindOnce(&FileAnalyzerTest::DoneCallback, base::Unretained(this),
run_loop.QuitClosure()));
run_loop.Run();
ASSERT_TRUE(has_result_);
EXPECT_EQ(result_.type, ClientDownloadRequest::MAC_ARCHIVE_FAILED_PARSING);
EXPECT_EQ(result_.archive_summary.parser_status(),
ClientDownloadRequest::ArchiveSummary::UNKNOWN);
}
#endif
TEST_F(FileAnalyzerTest, ArchiveIsValidSetForValidArchive) { … }
TEST_F(FileAnalyzerTest, ArchiveIsValidSetForInvalidArchive) { … }
TEST_F(FileAnalyzerTest, ArchivedExecutableSetForZipWithExecutable) { … }
TEST_F(FileAnalyzerTest, ArchivedExecutableFalseForZipNoExecutable) { … }
TEST_F(FileAnalyzerTest, ArchivedArchiveSetForZipWithArchive) { … }
TEST_F(FileAnalyzerTest, ArchivedArchiveSetForZipNoArchive) { … }
TEST_F(FileAnalyzerTest, ArchivedBinariesHasArchiveAndExecutable) { … }
TEST_F(FileAnalyzerTest, ArchivedBinariesSkipsSafeFiles) { … }
TEST_F(FileAnalyzerTest, ArchivedBinariesRespectsPolicyMaximum) { … }
TEST_F(FileAnalyzerTest, ExtractsFileSignatureForExe) { … }
TEST_F(FileAnalyzerTest, ExtractsImageHeadersForExe) { … }
#if BUILDFLAG(IS_MAC)
TEST_F(FileAnalyzerTest, ExtractsSignatureForDmg) {
scoped_refptr<MockBinaryFeatureExtractor> extractor =
new testing::StrictMock<MockBinaryFeatureExtractor>();
FileAnalyzer analyzer(extractor);
base::RunLoop run_loop;
base::FilePath target_path(FILE_PATH_LITERAL("target.dmg"));
base::FilePath signed_dmg;
EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &signed_dmg));
signed_dmg = signed_dmg.AppendASCII("safe_browsing")
.AppendASCII("mach_o")
.AppendASCII("signed-archive.dmg");
analyzer.Start(
target_path, signed_dmg, std::nullopt,
base::BindOnce(&FileAnalyzerTest::DoneCallback, base::Unretained(this),
run_loop.QuitClosure()));
run_loop.Run();
ASSERT_TRUE(has_result_);
EXPECT_EQ(2215u, result_.disk_image_signature.size());
base::FilePath signed_dmg_signature;
EXPECT_TRUE(
base::PathService::Get(chrome::DIR_TEST_DATA, &signed_dmg_signature));
signed_dmg_signature = signed_dmg_signature.AppendASCII("safe_browsing")
.AppendASCII("mach_o")
.AppendASCII("signed-archive-signature.data");
std::string signature;
base::ReadFileToString(signed_dmg_signature, &signature);
EXPECT_EQ(2215u, signature.length());
std::vector<uint8_t> signature_vector(signature.begin(), signature.end());
EXPECT_EQ(signature_vector, result_.disk_image_signature);
}
TEST_F(FileAnalyzerTest, TypeSniffsDmgWithoutExtension) {
scoped_refptr<MockBinaryFeatureExtractor> extractor =
new testing::StrictMock<MockBinaryFeatureExtractor>();
FileAnalyzer analyzer(extractor);
base::RunLoop run_loop;
base::FilePath target_path(FILE_PATH_LITERAL("target.dmg"));
base::FilePath dmg_no_extension;
EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &dmg_no_extension));
dmg_no_extension = dmg_no_extension.AppendASCII("safe_browsing")
.AppendASCII("dmg")
.AppendASCII("data")
.AppendASCII("mach_o_in_dmg.txt");
analyzer.Start(
target_path, dmg_no_extension, std::nullopt,
base::BindOnce(&FileAnalyzerTest::DoneCallback, base::Unretained(this),
run_loop.QuitClosure()));
run_loop.Run();
ASSERT_TRUE(has_result_);
EXPECT_EQ(result_.type, ClientDownloadRequest::MAC_EXECUTABLE);
EXPECT_EQ(result_.archive_summary.parser_status(),
ClientDownloadRequest::ArchiveSummary::VALID);
}
#endif
TEST_F(FileAnalyzerTest, SmallRarHasContentInspection) { … }
TEST_F(FileAnalyzerTest, LargeRarSkipsContentInspection) { … }
TEST_F(FileAnalyzerTest, ZipFilesGetFileCount) { … }
TEST_F(FileAnalyzerTest, ZipFilesGetDirectoryCount) { … }
TEST_F(FileAnalyzerTest, RarFilesGetFileCount) { … }
TEST_F(FileAnalyzerTest, RarFilesGetDirectoryCount) { … }
TEST_F(FileAnalyzerTest, LargeZipSkipsContentInspection) { … }
TEST_F(FileAnalyzerTest, ZipAnalysisResultMetric) { … }
TEST_F(FileAnalyzerTest, RarAnalysisResultMetric) { … }
#if BUILDFLAG(IS_MAC)
TEST_F(FileAnalyzerTest, DmgAnalysisResultMetric) {
scoped_refptr<MockBinaryFeatureExtractor> extractor =
new testing::StrictMock<MockBinaryFeatureExtractor>();
FileAnalyzer analyzer(extractor);
base::HistogramTester histogram_tester;
base::RunLoop run_loop;
base::FilePath target_path(FILE_PATH_LITERAL("target.dmg"));
base::FilePath signed_dmg;
EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &signed_dmg));
signed_dmg = signed_dmg.AppendASCII("safe_browsing")
.AppendASCII("mach_o")
.AppendASCII("signed-archive.dmg");
analyzer.Start(
target_path, signed_dmg, std::nullopt,
base::BindOnce(&FileAnalyzerTest::DoneCallback, base::Unretained(this),
run_loop.QuitClosure()));
run_loop.Run();
ASSERT_TRUE(has_result_);
histogram_tester.ExpectBucketCount(
"SBClientDownload.DmgArchiveAnalysisResult",
ArchiveAnalysisResult::kValid, 1);
}
#endif
TEST_F(FileAnalyzerTest, EncryptedEntriesDoNotHaveHashOrLength) { … }
TEST_F(FileAnalyzerTest, RarDirectoriesNotReported) { … }
TEST_F(FileAnalyzerTest, ZeroLengthSevenZipEntriesSupported) { … }
}