1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DEEP_SCANNING_REQUEST_H_
#define CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DEEP_SCANNING_REQUEST_H_
#include <memory>
#include "base/callback_list.h"
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/types/optional_ref.h"
#include "chrome/browser/download/download_item_warning_data.h"
#include "chrome/browser/enterprise/connectors/analysis/content_analysis_info.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h"
#include "chrome/browser/safe_browsing/download_protection/deep_scanning_metadata.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
#include "components/enterprise/common/proto/connectors.pb.h"
#include "components/enterprise/obfuscation/core/download_obfuscator.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
namespace download {
class DownloadItem;
}
namespace safe_browsing {
class DownloadProtectionService;
class DownloadRequestMaker;
// This class encapsulates the process of uploading a file to Safe Browsing for
// deep scanning and reporting the result.
// Deep scanning is not supported on Android.
class DeepScanningRequest : public download::DownloadItem::Observer,
public enterprise_connectors::ContentAnalysisInfo {
public:
// Enum representing the type of constructor that initiated scanning.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class DeepScanType {
// Scanning was initiated by a normal download from a web page.
NORMAL = 0,
// Scanning was initiated by a save package being saved on disk.
SAVE_PACKAGE = 1,
kMaxValue = SAVE_PACKAGE,
};
class Observer : public base::CheckedObserver {
public:
~Observer() override = default;
// Called when the DeepScanningRequest finishes.
virtual void OnFinish(DeepScanningRequest* request) {}
};
// Checks the current policies to determine whether files must be uploaded by
// policy. Returns the settings to apply to this analysis if it should happen
// or std::nullopt if no analysis should happen.
static std::optional<enterprise_connectors::AnalysisSettings>
ShouldUploadBinary(const DeepScanningMetadata& metadata);
// Scan the given `metadata item`, with the given `trigger`. The result of the
// scanning will be provided through `callback`. Take a references to the
// owning `download_service`.
DeepScanningRequest(std::unique_ptr<DeepScanningMetadata> metadata,
DownloadItemWarningData::DeepScanTrigger trigger,
DownloadCheckResult pre_scan_download_check_result,
CheckDownloadRepeatingCallback callback,
DownloadProtectionService* download_service,
enterprise_connectors::AnalysisSettings settings,
base::optional_ref<const std::string> password);
// Scan the given `metadata item` that corresponds to a save package, with
// `save_package_page` mapping every currently on-disk file part of that
// package to their final target path. The result of the scanning is provided
// through `callback` once every file has been scanned, and the given result
// is the highest severity one. Takes a reference to the owning
// `download_service`.
DeepScanningRequest(
std::unique_ptr<DeepScanningMetadata> metadata,
DownloadCheckResult pre_scan_download_check_result,
CheckDownloadRepeatingCallback callback,
DownloadProtectionService* download_service,
enterprise_connectors::AnalysisSettings settings,
base::flat_map<base::FilePath, base::FilePath> save_package_files);
~DeepScanningRequest() override;
// Begin the deep scanning request. This must be called on the UI thread.
void Start();
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// download::DownloadItem::Observer:
void OnDownloadUpdated(download::DownloadItem* download) override;
void OnDownloadDestroyed(download::DownloadItem* download) override;
// enterprise_connectors::ContentAnalysisInfo:
const enterprise_connectors::AnalysisSettings& settings() const override;
signin::IdentityManager* identity_manager() const override;
int user_action_requests_count() const override;
std::string tab_title() const override;
std::string user_action_id() const override;
std::string email() const override;
std::string url() const override;
const GURL& tab_url() const override;
enterprise_connectors::ContentAnalysisRequest::Reason reason() const override;
google::protobuf::RepeatedPtrField<::safe_browsing::ReferrerChainEntry>
referrer_chain() const override;
google::protobuf::RepeatedPtrField<std::string> frame_url_chain()
const override;
private:
// Starts the deep scanning request when there is a one-to-one mapping from
// the download item to a file.
void StartSingleFileScan();
// Starts the deep scanning requests when there is a one-to-many mapping from
// the download item to multiple files being scanned as a part of a save
// package.
void StartSavePackageScan();
// Callback when the |download_request_maker_| is finished assembling the
// download metadata request.
void OnDownloadRequestReady(
const base::FilePath& current_path,
std::unique_ptr<FileAnalysisRequest> deep_scan_request,
std::unique_ptr<ClientDownloadRequest> download_request);
// Callbacks for when |binary_upload_service_| finishes uploading.
void OnScanComplete(const base::FilePath& current_path,
BinaryUploadService::Result result,
enterprise_connectors::ContentAnalysisResponse response);
void OnConsumerScanComplete(
const base::FilePath& current_path,
BinaryUploadService::Result result,
enterprise_connectors::ContentAnalysisResponse response);
void OnEnterpriseScanComplete(
const base::FilePath& current_path,
BinaryUploadService::Result result,
enterprise_connectors::ContentAnalysisResponse response);
// Called when a single file scanning request has completed. Calls
// FinishRequest if it was the last required one.
void MaybeFinishRequest(DownloadCheckResult result);
// Finishes the request, providing the result through |callback_| and
// notifying |download_service_|.
void FinishRequest(DownloadCheckResult result);
// Called to verify if `result` is considered as a failure and the scan should
// end early.
bool ShouldTerminateEarly(BinaryUploadService::Result result);
// Called to open the download. This is triggered by the timeout modal dialog.
void OpenDownload();
// Populates a request's proto fields with the appropriate data.
void PopulateRequest(FileAnalysisRequest* request,
Profile* profile,
const base::FilePath& path);
// Creates a ClientDownloadRequest asynchronously to attach to
// `deep_scan_request`. Once it is obtained, OnDownloadRequestReady is called
// to upload the request for deep scanning.
void PrepareClientDownloadRequest(
const base::FilePath& current_path,
std::unique_ptr<FileAnalysisRequest> deep_scan_request);
// Callback invoked in `StartSingleFileScan` to check if `data` has been
// successfully fetched and ready for deep scanning if needed.
void OnGetFileRequestData(const base::FilePath& file_path,
std::unique_ptr<FileAnalysisRequest> request,
BinaryUploadService::Result result,
BinaryUploadService::Request::Data data);
// Callback invoked in `StartSavePackageScan` to check if `data` of a file in
// package has been successfully fetched and ready for deep scanning if
// needed.
void OnGetPackageFileRequestData(const base::FilePath& final_path,
const base::FilePath& current_path,
std::unique_ptr<FileAnalysisRequest> request,
BinaryUploadService::Result result,
BinaryUploadService::Request::Data data);
// Helper function to simplify checking if the report-only feature is set in
// conjunction with the corresponding policy value.
bool ReportOnlyScan();
// Acknowledge the request's handling to the service provider.
void AcknowledgeRequest(enterprise_connectors::EventResult event_result);
bool IsEnterpriseTriggered() const;
bool IsConsumerTriggered() const;
// Callback for when deobfuscation of the file is completed.
void OnDeobfuscationComplete(
DownloadCheckResult download_result,
base::expected<void, enterprise_obfuscation::Error> result);
// Provides scan result to `callback_` and clean up.
void CallbackAndCleanup(DownloadCheckResult result);
// Metadata for the item being scanned. This is owned by `DeepScanningRequest`
// and provides an abstraction layer over different types of scan sources
// (download items, file system access writes).
std::unique_ptr<DeepScanningMetadata> metadata_;
// ScopedObservation to manage `DownloadItem` observation lifetime. Must be
// cleared before `metadata_` is.
std::unique_ptr<DeepScanningMetadata::DownloadScopedObservation>
download_observation_;
// The reason for deep scanning.
DownloadItemWarningData::DeepScanTrigger trigger_;
// The callback to provide the scan result to.
CheckDownloadRepeatingCallback callback_;
// The download protection service that initiated this upload. The
// |download_service_| owns this class.
raw_ptr<DownloadProtectionService> download_service_;
// The time when uploading starts. Keyed with the file's current path.
base::flat_map<base::FilePath, base::TimeTicks> upload_start_times_;
// The settings to apply to this scan.
enterprise_connectors::AnalysisSettings analysis_settings_;
// Used to assemble the download metadata.
std::unique_ptr<DownloadRequestMaker> download_request_maker_;
// This list of observers of this request.
base::ObserverList<Observer> observers_;
// Stores a mapping of temporary paths to final paths for save package files.
// This is empty on non-page save scanning requests.
base::flat_map<base::FilePath, base::FilePath> save_package_files_;
// Stores a mapping of a file's current path to its metadata so it can be used
// in reporting events. This is populated from opening the file for save
// package scans, or populated from `item_` for single file scans.
base::flat_map<base::FilePath, enterprise_connectors::FileMetadata>
file_metadata_;
// Owner of the FileOpeningJob used to safely open multiple files in parallel
// for save package scans. Always nullptr for non-save package scans.
std::unique_ptr<FileOpeningJob> file_opening_job_;
// The total number of files beings scanned for which OnScanComplete hasn't
// been called. Once this is 0, FinishRequest should be called and `this`
// should be destroyed.
size_t pending_scan_requests_;
// The highest precedence DownloadCheckResult obtained from scanning verdicts.
// This should be updated when a scan completes.
DownloadCheckResult download_check_result_ =
DownloadCheckResult::DEEP_SCANNED_SAFE;
// Cached SB result for the download to be used if deep scanning fails.
DownloadCheckResult pre_scan_download_check_result_;
// Cached danger type for the download to be used by reporting in case
// scanning is skipped for any reason.
download::DownloadDangerType pre_scan_danger_type_;
// Set to true when StartSingleFileScan or StartSavePackageScan is called and
// that scanning has started. This is used so that calls to OnDownloadUpdated
// only ever start the scanning process once.
bool scanning_started_ = false;
// Cached callbacks to report scanning results until the final `event_result_`
// is known. The callbacks in this list should be called in FinishRequest.
base::OnceCallbackList<void(enterprise_connectors::EventResult result)>
report_callbacks_;
// The request tokens of all the requests that make up the user action
// represented by this ContentAnalysisDelegate instance.
std::vector<std::string> request_tokens_;
// Password for the file, if it's an archive.
std::optional<std::string> password_;
// Reason the scanning took place. Used to populate enterprise requests to
// give more context on what user action lead to a scan.
enterprise_connectors::ContentAnalysisRequest::Reason reason_ =
enterprise_connectors::ContentAnalysisRequest::UNKNOWN;
base::WeakPtrFactory<DeepScanningRequest> weak_ptr_factory_;
};
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DEEP_SCANNING_REQUEST_H_
|