Commit d3f04cfd authored by Dominique Fauteux-Chapleau's avatar Dominique Fauteux-Chapleau Committed by Commit Bot

Move deep scanning utils to new file instead of CheckClientDownloadReq

Change-Id: Ic4ef01d8a4e07a41253e36b2ea5e9086db81765f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1937648
Commit-Queue: Dominique Fauteux-Chapleau <domfc@chromium.org>
Reviewed-by: default avatarDaniel Rubery <drubery@chromium.org>
Cr-Commit-Position: refs/heads/master@{#719581}
parent f8a6ce70
......@@ -143,6 +143,8 @@ jumbo_static_library("safe_browsing") {
"cloud_content_scanning/binary_upload_service.h",
"cloud_content_scanning/deep_scanning_dialog_delegate.cc",
"cloud_content_scanning/deep_scanning_dialog_delegate.h",
"cloud_content_scanning/deep_scanning_utils.cc",
"cloud_content_scanning/deep_scanning_utils.h",
"cloud_content_scanning/multipart_uploader.cc",
"cloud_content_scanning/multipart_uploader.h",
"download_protection/check_client_download_request.cc",
......
......@@ -19,7 +19,7 @@
#include "base/time/time.h"
#include "chrome/browser/policy/browser_dm_token_storage.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h"
#include "chrome/browser/safe_browsing/download_protection/check_client_download_request.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
#include "components/policy/core/common/cloud/dm_token.h"
......
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "base/metrics/histogram_functions.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
namespace safe_browsing {
namespace {
constexpr int kMinBytesPerSecond = 1;
constexpr int kMaxBytesPerSecond = 100 * 1024 * 1024; // 100 MB/s
// TODO(drubery): This function would be simpler if the ClientDownloadResponse
// and MalwareDeepScanningVerdict used the same enum.
std::string MalwareVerdictToThreatType(
MalwareDeepScanningVerdict::Verdict verdict) {
switch (verdict) {
case MalwareDeepScanningVerdict::CLEAN:
return "SAFE";
case MalwareDeepScanningVerdict::UWS:
return "POTENTIALLY_UNWANTED";
case MalwareDeepScanningVerdict::MALWARE:
return "DANGEROUS";
case MalwareDeepScanningVerdict::VERDICT_UNSPECIFIED:
default:
return "UNKNOWN";
}
}
} // namespace
void MaybeReportDeepScanningVerdict(Profile* profile,
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& mime_type,
const std::string& trigger,
const int64_t content_size,
BinaryUploadService::Result result,
DeepScanningClientResponse response) {
if (result == BinaryUploadService::Result::FILE_TOO_LARGE) {
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnUnscannedFileEvent(url, file_name, download_digest_sha256,
mime_type, trigger, "fileTooLarge",
content_size);
} else if (result == BinaryUploadService::Result::TIMEOUT) {
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnUnscannedFileEvent(url, file_name, download_digest_sha256,
mime_type, trigger, "scanTimedOut",
content_size);
}
if (result != BinaryUploadService::Result::SUCCESS)
return;
if (response.malware_scan_verdict().verdict() ==
MalwareDeepScanningVerdict::UWS ||
response.malware_scan_verdict().verdict() ==
MalwareDeepScanningVerdict::MALWARE) {
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnDangerousDeepScanningResult(
url, file_name, download_digest_sha256,
MalwareVerdictToThreatType(
response.malware_scan_verdict().verdict()),
mime_type, trigger, content_size);
}
if (response.dlp_scan_verdict().status() == DlpDeepScanningVerdict::SUCCESS) {
if (!response.dlp_scan_verdict().triggered_rules().empty()) {
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnSensitiveDataEvent(response.dlp_scan_verdict(), url, file_name,
download_digest_sha256, mime_type, trigger,
content_size);
}
}
}
std::string DeepScanAccessPointToString(DeepScanAccessPoint access_point) {
// TODO(domfc): Add DRAG_AND_DROP and PASTE access points.
switch (access_point) {
case DeepScanAccessPoint::DOWNLOAD:
return "Download";
case DeepScanAccessPoint::UPLOAD:
return "Upload";
}
NOTREACHED();
return "";
}
void RecordDeepScanMetrics(DeepScanAccessPoint access_point,
base::TimeDelta duration,
int64_t total_bytes,
const BinaryUploadService::Result& result,
const DeepScanningClientResponse& response) {
bool dlp_verdict_success = response.has_dlp_scan_verdict()
? response.dlp_scan_verdict().status() ==
DlpDeepScanningVerdict::SUCCESS
: true;
bool malware_verdict_success =
response.has_malware_scan_verdict()
? response.malware_scan_verdict().verdict() !=
MalwareDeepScanningVerdict::VERDICT_UNSPECIFIED
: true;
bool success = dlp_verdict_success && malware_verdict_success;
std::string result_value;
switch (result) {
case BinaryUploadService::Result::SUCCESS:
if (success)
result_value = "Success";
else
result_value = "FailedToGetVerdict";
break;
case BinaryUploadService::Result::UPLOAD_FAILURE:
result_value = "UploadFailure";
break;
case BinaryUploadService::Result::TIMEOUT:
result_value = "Timeout";
break;
case BinaryUploadService::Result::FILE_TOO_LARGE:
result_value = "FileTooLarge";
break;
case BinaryUploadService::Result::FAILED_TO_GET_TOKEN:
result_value = "FailedToGetToken";
break;
case BinaryUploadService::Result::UNKNOWN:
result_value = "Unknown";
break;
}
// Update |success| so non-SUCCESS results don't log the bytes/sec metric.
success &= (result == BinaryUploadService::Result::SUCCESS);
RecordDeepScanMetrics(access_point, duration, total_bytes, result_value,
success);
}
void RecordDeepScanMetrics(DeepScanAccessPoint access_point,
base::TimeDelta duration,
int64_t total_bytes,
const std::string& result,
bool success) {
// Don't record metrics if the duration is unusable.
if (duration.InMilliseconds() == 0)
return;
std::string access_point_string = DeepScanAccessPointToString(access_point);
if (success) {
base::UmaHistogramCustomCounts(
"SafeBrowsing.DeepScan." + access_point_string + ".BytesPerSeconds",
(1000 * total_bytes) / duration.InMilliseconds(),
/*min=*/kMinBytesPerSecond,
/*max=*/kMaxBytesPerSecond,
/*buckets=*/50);
}
// The scanning timeout is 5 minutes, so the bucket maximum time is 30 minutes
// in order to be lenient and avoid having lots of data in the overlow bucket.
base::UmaHistogramCustomTimes("SafeBrowsing.DeepScan." + access_point_string +
"." + result + ".Duration",
duration, base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMinutes(30), 50);
base::UmaHistogramCustomTimes(
"SafeBrowsing.DeepScan." + access_point_string + ".Duration", duration,
base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(30),
50);
}
} // namespace safe_browsing
// Copyright 2019 The Chromium Authors. All rights reserved.
// 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_CLOUD_CONTENT_SCANNING_DEEP_SCANNING_UTILS_H_
#define CHROME_BROWSER_SAFE_BROWSING_CLOUD_CONTENT_SCANNING_DEEP_SCANNING_UTILS_H_
#include <string>
#include "base/time/time.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h"
#include "url/gurl.h"
class Profile;
namespace safe_browsing {
// Helper function to examine a DeepScanningClientResponse and report the
// appropriate events to the enterprise admin.
void MaybeReportDeepScanningVerdict(Profile* profile,
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& mime_type,
const std::string& trigger,
const int64_t content_size,
BinaryUploadService::Result result,
DeepScanningClientResponse response);
// Access points used to record UMA metrics. Adding an access point here
// requires updating histograms.xml by adding histograms with names
// "SafeBrowsing.DeepScan.<access-point>.BytesPerSeconds"
// "SafeBrowsing.DeepScan.<access-point>.Duration"
// "SafeBrowsing.DeepScan.<access-point>.<result>.Duration"
// TODO(domfc): Add DRAG_AND_DROP and PASTE access points.
enum class DeepScanAccessPoint {
DOWNLOAD,
UPLOAD,
};
std::string DeepScanAccessPointToString(DeepScanAccessPoint access_point);
// Helper functions to record DeepScanning UMA metrics for the duration of the
// request split by its result and bytes/sec for successful requests.
void RecordDeepScanMetrics(DeepScanAccessPoint access_point,
base::TimeDelta duration,
int64_t total_bytes,
const BinaryUploadService::Result& result,
const DeepScanningClientResponse& response);
void RecordDeepScanMetrics(DeepScanAccessPoint access_point,
base::TimeDelta duration,
int64_t total_bytes,
const std::string& result,
bool success);
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_CLOUD_CONTENT_SCANNING_DEEP_SCANNING_UTILS_H_
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/download_protection/check_client_download_request.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include <string>
#include <tuple>
......@@ -59,11 +59,11 @@ std::string ResultToString(const BinaryUploadService::Result& result,
} // namespace
class CheckClientDownloadRequestUMATest
class DeepScanningUtilsUMATest
: public testing::TestWithParam<
std::tuple<DeepScanAccessPoint, BinaryUploadService::Result>> {
public:
CheckClientDownloadRequestUMATest() {}
DeepScanningUtilsUMATest() {}
DeepScanAccessPoint access_point() const { return std::get<0>(GetParam()); }
......@@ -89,12 +89,12 @@ class CheckClientDownloadRequestUMATest
INSTANTIATE_TEST_SUITE_P(
Tests,
CheckClientDownloadRequestUMATest,
DeepScanningUtilsUMATest,
testing::Combine(testing::Values(DeepScanAccessPoint::DOWNLOAD,
DeepScanAccessPoint::UPLOAD),
testing::ValuesIn(kAllBinaryUploadServiceResults)));
TEST_P(CheckClientDownloadRequestUMATest, SuccessfulScanVerdicts) {
TEST_P(DeepScanningUtilsUMATest, SuccessfulScanVerdicts) {
RecordDeepScanMetrics(access_point(), kDuration, kTotalBytes, result(),
DeepScanningClientResponse());
// We expect at least 2 histograms (<access-point>.Duration and
......@@ -118,7 +118,7 @@ TEST_P(CheckClientDownloadRequestUMATest, SuccessfulScanVerdicts) {
kDuration, 1);
}
TEST_P(CheckClientDownloadRequestUMATest, UnsuccessfulDlpScanVerdict) {
TEST_P(DeepScanningUtilsUMATest, UnsuccessfulDlpScanVerdict) {
DlpDeepScanningVerdict dlp_verdict;
dlp_verdict.set_status(DlpDeepScanningVerdict::FAILURE);
DeepScanningClientResponse response;
......@@ -139,7 +139,7 @@ TEST_P(CheckClientDownloadRequestUMATest, UnsuccessfulDlpScanVerdict) {
kDuration, 1);
}
TEST_P(CheckClientDownloadRequestUMATest, UnsuccessfulMalwareScanVerdict) {
TEST_P(DeepScanningUtilsUMATest, UnsuccessfulMalwareScanVerdict) {
MalwareDeepScanningVerdict malware_verdict;
malware_verdict.set_verdict(MalwareDeepScanningVerdict::VERDICT_UNSPECIFIED);
DeepScanningClientResponse response;
......@@ -160,7 +160,7 @@ TEST_P(CheckClientDownloadRequestUMATest, UnsuccessfulMalwareScanVerdict) {
kDuration, 1);
}
TEST_P(CheckClientDownloadRequestUMATest, BypassScanVerdict) {
TEST_P(DeepScanningUtilsUMATest, BypassScanVerdict) {
RecordDeepScanMetrics(access_point(), kDuration, kTotalBytes,
"BypassedByUser", false);
......@@ -176,7 +176,7 @@ TEST_P(CheckClientDownloadRequestUMATest, BypassScanVerdict) {
kDuration, 1);
}
TEST_P(CheckClientDownloadRequestUMATest, CancelledByUser) {
TEST_P(DeepScanningUtilsUMATest, CancelledByUser) {
RecordDeepScanMetrics(access_point(), kDuration, kTotalBytes,
"CancelledByUser", false);
......@@ -192,7 +192,7 @@ TEST_P(CheckClientDownloadRequestUMATest, CancelledByUser) {
kDuration, 1);
}
TEST_P(CheckClientDownloadRequestUMATest, InvalidDuration) {
TEST_P(DeepScanningUtilsUMATest, InvalidDuration) {
RecordDeepScanMetrics(access_point(), kInvalidDuration, kTotalBytes, result(),
DeepScanningClientResponse());
EXPECT_EQ(
......
......@@ -23,6 +23,7 @@
#include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.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/download_protection/check_client_download_request_base.h"
#include "chrome/browser/safe_browsing/download_protection/download_feedback_service.h"
#include "chrome/browser/safe_browsing/download_protection/download_item_request.h"
......@@ -50,26 +51,6 @@ using policy::BrowserDMTokenStorage;
namespace {
constexpr int kMinBytesPerSecond = 1;
constexpr int kMaxBytesPerSecond = 100 * 1024 * 1024; // 100 MB/s
// TODO(drubery): This function would be simpler if the ClientDownloadResponse
// and MalwareDeepScanningVerdict used the same enum.
std::string MalwareVerdictToThreatType(
MalwareDeepScanningVerdict::Verdict verdict) {
switch (verdict) {
case MalwareDeepScanningVerdict::CLEAN:
return "SAFE";
case MalwareDeepScanningVerdict::UWS:
return "POTENTIALLY_UNWANTED";
case MalwareDeepScanningVerdict::MALWARE:
return "DANGEROUS";
case MalwareDeepScanningVerdict::VERDICT_UNSPECIFIED:
default:
return "UNKNOWN";
}
}
void DeepScanningClientResponseToDownloadCheckResult(
const DeepScanningClientResponse& response,
DownloadCheckResult* download_result,
......@@ -125,142 +106,6 @@ void DeepScanningClientResponseToDownloadCheckResult(
} // namespace
void MaybeReportDeepScanningVerdict(Profile* profile,
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& mime_type,
const std::string& trigger,
const int64_t content_size,
BinaryUploadService::Result result,
DeepScanningClientResponse response) {
if (result == BinaryUploadService::Result::FILE_TOO_LARGE) {
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnUnscannedFileEvent(url, file_name, download_digest_sha256,
mime_type, trigger, "fileTooLarge",
content_size);
} else if (result == BinaryUploadService::Result::TIMEOUT) {
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnUnscannedFileEvent(url, file_name, download_digest_sha256,
mime_type, trigger, "scanTimedOut",
content_size);
}
if (result != BinaryUploadService::Result::SUCCESS)
return;
if (response.malware_scan_verdict().verdict() ==
MalwareDeepScanningVerdict::UWS ||
response.malware_scan_verdict().verdict() ==
MalwareDeepScanningVerdict::MALWARE) {
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnDangerousDeepScanningResult(
url, file_name, download_digest_sha256,
MalwareVerdictToThreatType(
response.malware_scan_verdict().verdict()),
mime_type, trigger, content_size);
}
if (response.dlp_scan_verdict().status() == DlpDeepScanningVerdict::SUCCESS) {
if (!response.dlp_scan_verdict().triggered_rules().empty()) {
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnSensitiveDataEvent(response.dlp_scan_verdict(), url, file_name,
download_digest_sha256, mime_type, trigger,
content_size);
}
}
}
std::string DeepScanAccessPointToString(DeepScanAccessPoint access_point) {
// TODO(domfc): Add DRAG_AND_DROP and PASTE access points.
switch (access_point) {
case DeepScanAccessPoint::DOWNLOAD:
return "Download";
case DeepScanAccessPoint::UPLOAD:
return "Upload";
}
NOTREACHED();
return "";
}
void RecordDeepScanMetrics(DeepScanAccessPoint access_point,
base::TimeDelta duration,
int64_t total_bytes,
const BinaryUploadService::Result& result,
const DeepScanningClientResponse& response) {
bool dlp_verdict_success = response.has_dlp_scan_verdict()
? response.dlp_scan_verdict().status() ==
DlpDeepScanningVerdict::SUCCESS
: true;
bool malware_verdict_success =
response.has_malware_scan_verdict()
? response.malware_scan_verdict().verdict() !=
MalwareDeepScanningVerdict::VERDICT_UNSPECIFIED
: true;
bool success = dlp_verdict_success && malware_verdict_success;
std::string result_value;
switch (result) {
case BinaryUploadService::Result::SUCCESS:
if (success)
result_value = "Success";
else
result_value = "FailedToGetVerdict";
break;
case BinaryUploadService::Result::UPLOAD_FAILURE:
result_value = "UploadFailure";
break;
case BinaryUploadService::Result::TIMEOUT:
result_value = "Timeout";
break;
case BinaryUploadService::Result::FILE_TOO_LARGE:
result_value = "FileTooLarge";
break;
case BinaryUploadService::Result::FAILED_TO_GET_TOKEN:
result_value = "FailedToGetToken";
break;
case BinaryUploadService::Result::UNKNOWN:
result_value = "Unknown";
break;
}
// Update |success| so non-SUCCESS results don't log the bytes/sec metric.
success &= (result == BinaryUploadService::Result::SUCCESS);
RecordDeepScanMetrics(access_point, duration, total_bytes, result_value,
success);
}
void RecordDeepScanMetrics(DeepScanAccessPoint access_point,
base::TimeDelta duration,
int64_t total_bytes,
const std::string& result,
bool success) {
// Don't record metrics if the duration is unusable.
if (duration.InMilliseconds() == 0)
return;
std::string access_point_string = DeepScanAccessPointToString(access_point);
if (success) {
base::UmaHistogramCustomCounts(
"SafeBrowsing.DeepScan." + access_point_string + ".BytesPerSeconds",
(1000 * total_bytes) / duration.InMilliseconds(),
/*min=*/kMinBytesPerSecond,
/*max=*/kMaxBytesPerSecond,
/*buckets=*/50);
}
// The scanning timeout is 5 minutes, so the bucket maximum time is 30 minutes
// in order to be lenient and avoid having lots of data in the overlow bucket.
base::UmaHistogramCustomTimes("SafeBrowsing.DeepScan." + access_point_string +
"." + result + ".Duration",
duration, base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMinutes(30), 50);
base::UmaHistogramCustomTimes(
"SafeBrowsing.DeepScan." + access_point_string + ".Duration", duration,
base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(30),
50);
}
CheckClientDownloadRequest::CheckClientDownloadRequest(
download::DownloadItem* item,
CheckDownloadRepeatingCallback callback,
......
......@@ -24,8 +24,6 @@
#include "content/public/browser/browser_thread.h"
#include "url/gurl.h"
class Profile;
namespace safe_browsing {
class CheckClientDownloadRequest : public CheckClientDownloadRequestBase,
......@@ -110,43 +108,6 @@ class CheckClientDownloadRequest : public CheckClientDownloadRequestBase,
DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest);
};
// Helper function to examine a DeepScanningClientResponse and report the
// appropriate events to the enterprise admin.
void MaybeReportDeepScanningVerdict(Profile* profile,
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& mime_type,
const std::string& trigger,
const int64_t content_size,
BinaryUploadService::Result result,
DeepScanningClientResponse response);
// Access points used to record UMA metrics. Adding an access point here
// requires updating histograms.xml by adding histograms with names
// "SafeBrowsing.DeepScan.<access-point>.BytesPerSeconds"
// "SafeBrowsing.DeepScan.<access-point>.Duration"
// "SafeBrowsing.DeepScan.<access-point>.<result>.Duration"
// TODO(domfc): Add DRAG_AND_DROP and PASTE access points.
enum class DeepScanAccessPoint {
DOWNLOAD,
UPLOAD,
};
std::string DeepScanAccessPointToString(DeepScanAccessPoint access_point);
// Helper functions to record DeepScanning UMA metrics for the duration of the
// request split by its result and bytes/sec for successful requests.
void RecordDeepScanMetrics(DeepScanAccessPoint access_point,
base::TimeDelta duration,
int64_t total_bytes,
const BinaryUploadService::Result& result,
const DeepScanningClientResponse& response);
void RecordDeepScanMetrics(DeepScanAccessPoint access_point,
base::TimeDelta duration,
int64_t total_bytes,
const std::string& result,
bool success);
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_CHECK_CLIENT_DOWNLOAD_REQUEST_H_
......@@ -4731,8 +4731,8 @@ test("unit_tests") {
"../browser/safe_browsing/cloud_content_scanning/binary_fcm_service_unittest.cc",
"../browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc",
"../browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate_unittest.cc",
"../browser/safe_browsing/cloud_content_scanning/deep_scanning_utils_unittest.cc",
"../browser/safe_browsing/cloud_content_scanning/multipart_uploader_unittest.cc",
"../browser/safe_browsing/download_protection/check_client_download_request_unittest.cc",
"../browser/safe_browsing/download_protection/download_feedback_service_unittest.cc",
"../browser/safe_browsing/download_protection/download_feedback_unittest.cc",
"../browser/safe_browsing/download_protection/download_item_request_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment