blob: 597357276206c4b9f03c7dca863ae8d098b04396 [file]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/utility/safe_browsing/zip_analyzer.h"
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <set>
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/checked_math.h"
#include "base/rand_util.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/common/safe_browsing/archive_analyzer_results.h"
#include "chrome/utility/safe_browsing/archive_analysis_delegate.h"
#include "chrome/utility/safe_browsing/zip_writer_delegate.h"
#include "components/safe_browsing/content/common/file_type_policies.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
#include "third_party/zlib/google/zip_reader.h"
namespace safe_browsing {
ZipAnalyzer::ZipAnalyzer() = default;
ZipAnalyzer::~ZipAnalyzer() = default;
void ZipAnalyzer::Init() {
GetTempFile(
base::BindOnce(&ZipAnalyzer::OnGetTempFile, weak_factory_.GetWeakPtr()));
}
bool ZipAnalyzer::ResumeExtraction() {
while (const zip::ZipReader::Entry* const entry = reader_.Next()) {
// Clear the `temp_file` between extractions.
if (temp_file_.Seek(base::File::Whence::FROM_BEGIN, 0) != 0) {
PLOG(WARNING) << "Failed seek";
}
// Since this code is expected to run within a utility process, this call
// will fail on some platforms. We handle this by passing the length
// into `UpdateResultsForEntry`, which will only consider
// the appropriate bytes. See crbug.com/40830053 and crbug.com/41349785.
if (!temp_file_.SetLength(0)) {
PLOG(WARNING) << "Failed truncate";
}
CHECK(analysis_delegate_);
std::unique_ptr<SafeBrowsingZipWriterDelegate> writer =
analysis_delegate_->CreateZipWriterDelegate(temp_file_.Duplicate());
bool extract_success = reader_.ExtractCurrentEntry(
writer.get(), std::numeric_limits<uint64_t>::max());
writer->Close();
has_encrypted_ |= entry->is_encrypted;
has_aes_encrypted_ |= entry->uses_aes_encryption;
has_disk_error_ |= writer->has_disk_error();
if (!extract_success && entry->is_encrypted) {
results()->encryption_info.password_status =
EncryptionInfo::kKnownIncorrect;
}
if (!UpdateResultsForEntry(temp_file_.Duplicate(),
GetRootPath().Append(entry->path),
writer->file_length(), entry->is_encrypted,
entry->is_directory, extract_success)) {
return false;
}
}
if (has_encrypted_) {
if (has_aes_encrypted_ && password() && !password()->empty()) {
results()->encryption_info.password_status = EncryptionInfo::kUnknown;
} else if (results()->encryption_info.password_status !=
EncryptionInfo::kKnownIncorrect) {
results()->encryption_info.password_status =
EncryptionInfo::kKnownCorrect;
}
}
if (has_disk_error_) {
results()->analysis_result = ArchiveAnalysisResult::kDiskError;
} else if (reader_.ok()) {
results()->analysis_result = ArchiveAnalysisResult::kValid;
} else {
results()->analysis_result = ArchiveAnalysisResult::kFailedDuringIteration;
}
results()->success = reader_.ok() && !has_disk_error_;
return true;
}
base::WeakPtr<ArchiveAnalyzer> ZipAnalyzer::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void ZipAnalyzer::OnGetTempFile(base::File temp_file) {
if (!temp_file.IsValid()) {
InitComplete(ArchiveAnalysisResult::kFailedToOpenTempFile);
return;
}
CHECK(analysis_delegate_);
reader_delegate_ =
analysis_delegate_->CreateZipReaderDelegate(GetArchiveFile().Duplicate());
if (!reader_delegate_ ||
!reader_.OpenFromReaderDelegate(reader_delegate_.get())) {
InitComplete(ArchiveAnalysisResult::kUnknown);
return;
}
bool too_big_to_unpack =
base::checked_cast<uint64_t>(GetArchiveFile().GetLength()) >
FileTypePolicies::GetInstance()->GetMaxFileSizeToAnalyze("zip");
if (too_big_to_unpack) {
InitComplete(ArchiveAnalysisResult::kTooLarge);
return;
}
temp_file_ = std::move(temp_file);
if (password().has_value()) {
reader_.SetPassword(*password());
}
InitComplete(ArchiveAnalysisResult::kValid);
}
} // namespace safe_browsing