#include "chrome/utility/safe_browsing/seven_zip_analyzer.h"
#include "base/feature_list.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/common/safe_browsing/archive_analyzer_results.h"
#include "components/safe_browsing/content/common/file_type_policies.h"
#include "components/safe_browsing/core/common/features.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/win/winbase_shim.h"
#elif BUILDFLAG(IS_POSIX)
#include <sys/mman.h>
#endif
namespace safe_browsing {
SevenZipAnalyzer::SevenZipAnalyzer() = default;
SevenZipAnalyzer::~SevenZipAnalyzer() = default;
void SevenZipAnalyzer::OnOpenError(seven_zip::Result result) {
results()->success = false;
results()->analysis_result = ArchiveAnalysisResult::kFailedToOpen;
results()->encryption_info.is_encrypted |=
result == seven_zip::Result::kEncryptedHeaders;
if (IsTopLevelArchive()) {
results()->encryption_info.is_top_level_encrypted |=
result == seven_zip::Result::kEncryptedHeaders;
}
}
base::File SevenZipAnalyzer::OnTempFileRequest() {
return std::move(temp_file2_);
}
bool SevenZipAnalyzer::OnEntry(const seven_zip::EntryInfo& entry,
base::span<uint8_t>& output) {
if (entry.file_size == 0) {
output = base::span<uint8_t>();
return true;
}
mapped_file_.emplace();
bool mapped_file_ok = mapped_file_->Initialize(
temp_file_.Duplicate(), {0, static_cast<size_t>(entry.file_size)},
base::MemoryMappedFile::READ_WRITE_EXTEND);
if (!mapped_file_ok) {
results()->success = false;
results()->analysis_result = ArchiveAnalysisResult::kUnknown;
return false;
}
output = mapped_file_->mutable_bytes();
return true;
}
bool SevenZipAnalyzer::OnDirectory(const seven_zip::EntryInfo& entry) {
return UpdateResultsForEntry(
temp_file_.Duplicate(), GetRootPath().Append(entry.file_path),
entry.file_size, entry.is_encrypted, true,
!entry.is_encrypted);
}
bool SevenZipAnalyzer::EntryDone(seven_zip::Result result,
const seven_zip::EntryInfo& entry) {
if (result == seven_zip::Result::kSuccess || entry.is_encrypted) {
mapped_file_.reset();
if (!UpdateResultsForEntry(
temp_file_.Duplicate(), GetRootPath().Append(entry.file_path),
entry.file_size, entry.is_encrypted, false,
!entry.is_encrypted)) {
awaiting_nested_ = true;
return false;
}
}
return true;
}
void SevenZipAnalyzer::Init() {
GetTempFile(base::BindOnce(&SevenZipAnalyzer::OnGetTempFile,
weak_factory_.GetWeakPtr()));
}
bool SevenZipAnalyzer::ResumeExtraction() {
awaiting_nested_ = false;
reader_->Extract();
return !awaiting_nested_;
}
base::WeakPtr<ArchiveAnalyzer> SevenZipAnalyzer::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void SevenZipAnalyzer::OnGetTempFile(base::File temp_file) {
if (!temp_file.IsValid()) {
InitComplete(ArchiveAnalysisResult::kFailedToOpenTempFile);
return;
}
if (!temp_file_.IsValid()) {
temp_file_ = std::move(temp_file);
GetTempFile(base::BindOnce(&SevenZipAnalyzer::OnGetTempFile,
weak_factory_.GetWeakPtr()));
return;
} else {
temp_file2_ = std::move(temp_file);
}
bool too_big_to_unpack =
base::checked_cast<uint64_t>(GetArchiveFile().GetLength()) >
FileTypePolicies::GetInstance()->GetMaxFileSizeToAnalyze("7z");
if (too_big_to_unpack) {
InitComplete(ArchiveAnalysisResult::kTooLarge);
return;
}
results()->success = true;
results()->analysis_result = ArchiveAnalysisResult::kValid;
reader_ =
seven_zip::SevenZipReader::Create(std::move(GetArchiveFile()), *this);
if (!reader_) {
InitComplete(results()->analysis_result);
return;
}
InitComplete(ArchiveAnalysisResult::kValid);
}
}