1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/safe_browsing/download_protection/download_reporter.h"
6 
7 #include "base/strings/string_number_conversions.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/download/simple_download_manager_coordinator_factory.h"
10 #include "chrome/browser/enterprise/connectors/common.h"
11 #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
12 #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
13 #include "chrome/browser/profiles/profile_key.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
16 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
17 #include "components/download/public/common/download_danger_type.h"
18 #include "components/download/public/common/download_item.h"
19 #include "components/download/public/common/simple_download_manager_coordinator.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/download_item_utils.h"
22 
23 namespace safe_browsing {
24 
25 namespace {
26 
DangerTypeIsDangerous(download::DownloadDangerType danger_type)27 bool DangerTypeIsDangerous(download::DownloadDangerType danger_type) {
28   return (danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
29           danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
30           danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
31           danger_type == download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
32           danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
33           danger_type == download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
34 }
35 
DangerTypeToThreatType(download::DownloadDangerType danger_type)36 std::string DangerTypeToThreatType(download::DownloadDangerType danger_type) {
37   switch (danger_type) {
38     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
39       return "DANGEROUS_FILE_TYPE";
40     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
41       return "DANGEROUS_URL";
42     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
43       return "DANGEROUS";
44     case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
45       return "UNCOMMON";
46     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
47       return "DANGEROUS_HOST";
48     case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
49       return "POTENTIALLY_UNWANTED";
50     default:
51       // Expects to only be called with the dangerous threat types listed above.
52       NOTREACHED() << "Unexpected danger type: " << danger_type;
53       return "UNKNOWN";
54   }
55 }
56 
MaybeReportDangerousDownloadWarning(download::DownloadItem * download)57 void MaybeReportDangerousDownloadWarning(download::DownloadItem* download) {
58   // If |download| has a deep scanning malware verdict, then it means the
59   // dangerous file has already been reported.
60   auto* scan_result = static_cast<enterprise_connectors::ScanResult*>(
61       download->GetUserData(enterprise_connectors::ScanResult::kKey));
62   if (scan_result &&
63       enterprise_connectors::ContainsMalwareVerdict(scan_result->response)) {
64     return;
65   }
66 
67   content::BrowserContext* browser_context =
68       content::DownloadItemUtils::GetBrowserContext(download);
69   Profile* profile = Profile::FromBrowserContext(browser_context);
70   if (profile) {
71     std::string raw_digest_sha256 = download->GetHash();
72     extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
73         ->OnDangerousDownloadEvent(
74             download->GetURL(), download->GetTargetFilePath().AsUTF8Unsafe(),
75             base::HexEncode(raw_digest_sha256.data(), raw_digest_sha256.size()),
76             DangerTypeToThreatType(download->GetDangerType()),
77             download->GetMimeType(), download->GetTotalBytes(),
78             EventResult::WARNED);
79   }
80 }
81 
ReportDangerousDownloadWarningBypassed(download::DownloadItem * download,download::DownloadDangerType original_danger_type)82 void ReportDangerousDownloadWarningBypassed(
83     download::DownloadItem* download,
84     download::DownloadDangerType original_danger_type) {
85   content::BrowserContext* browser_context =
86       content::DownloadItemUtils::GetBrowserContext(download);
87   Profile* profile = Profile::FromBrowserContext(browser_context);
88   if (profile) {
89     std::string raw_digest_sha256 = download->GetHash();
90     extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
91         ->OnDangerousDownloadWarningBypassed(
92             download->GetURL(), download->GetTargetFilePath().AsUTF8Unsafe(),
93             base::HexEncode(raw_digest_sha256.data(), raw_digest_sha256.size()),
94             DangerTypeToThreatType(original_danger_type),
95             download->GetMimeType(), download->GetTotalBytes());
96   }
97 }
98 
ReportAnalysisConnectorWarningBypassed(download::DownloadItem * download)99 void ReportAnalysisConnectorWarningBypassed(download::DownloadItem* download) {
100   content::BrowserContext* browser_context =
101       content::DownloadItemUtils::GetBrowserContext(download);
102   Profile* profile = Profile::FromBrowserContext(browser_context);
103   if (profile) {
104     std::string raw_digest_sha256 = download->GetHash();
105     enterprise_connectors::ScanResult* stored_result =
106         static_cast<enterprise_connectors::ScanResult*>(
107             download->GetUserData(enterprise_connectors::ScanResult::kKey));
108 
109     ReportAnalysisConnectorWarningBypass(
110         profile, download->GetURL(),
111         download->GetTargetFilePath().AsUTF8Unsafe(),
112         base::HexEncode(raw_digest_sha256.data(), raw_digest_sha256.size()),
113         download->GetMimeType(),
114         extensions::SafeBrowsingPrivateEventRouter::kTriggerFileDownload,
115         DeepScanAccessPoint::DOWNLOAD, download->GetTotalBytes(),
116         stored_result ? stored_result->response
117                       : enterprise_connectors::ContentAnalysisResponse());
118   }
119 }
120 
121 }  // namespace
122 
DownloadReporter()123 DownloadReporter::DownloadReporter() {
124   // Profile manager can be null in unit tests.
125   if (g_browser_process->profile_manager())
126     g_browser_process->profile_manager()->AddObserver(this);
127 }
128 
~DownloadReporter()129 DownloadReporter::~DownloadReporter() {
130   if (g_browser_process->profile_manager())
131     g_browser_process->profile_manager()->RemoveObserver(this);
132 }
133 
OnProfileAdded(Profile * profile)134 void DownloadReporter::OnProfileAdded(Profile* profile) {
135   observed_profiles_.Add(profile);
136   observed_coordinators_.Add(SimpleDownloadManagerCoordinatorFactory::GetForKey(
137       profile->GetProfileKey()));
138 }
139 
OnOffTheRecordProfileCreated(Profile * off_the_record)140 void DownloadReporter::OnOffTheRecordProfileCreated(Profile* off_the_record) {
141   OnProfileAdded(off_the_record);
142 }
143 
OnProfileWillBeDestroyed(Profile * profile)144 void DownloadReporter::OnProfileWillBeDestroyed(Profile* profile) {
145   observed_profiles_.Remove(profile);
146 }
147 
OnManagerGoingDown(download::SimpleDownloadManagerCoordinator * coordinator)148 void DownloadReporter::OnManagerGoingDown(
149     download::SimpleDownloadManagerCoordinator* coordinator) {
150   observed_coordinators_.Remove(coordinator);
151 }
152 
OnDownloadCreated(download::DownloadItem * download)153 void DownloadReporter::OnDownloadCreated(download::DownloadItem* download) {
154   danger_types_[download] = download->GetDangerType();
155   observed_downloads_.Add(download);
156 }
157 
OnDownloadDestroyed(download::DownloadItem * download)158 void DownloadReporter::OnDownloadDestroyed(download::DownloadItem* download) {
159   observed_downloads_.Remove(download);
160   danger_types_.erase(download);
161 }
162 
OnDownloadUpdated(download::DownloadItem * download)163 void DownloadReporter::OnDownloadUpdated(download::DownloadItem* download) {
164   // If the update isn't a change in danger type, we can ignore it.
165   if (danger_types_[download] == download->GetDangerType())
166     return;
167 
168   download::DownloadDangerType old_danger_type = danger_types_[download];
169   download::DownloadDangerType current_danger_type = download->GetDangerType();
170 
171   if (!DangerTypeIsDangerous(old_danger_type) &&
172       DangerTypeIsDangerous(current_danger_type)) {
173     MaybeReportDangerousDownloadWarning(download);
174   }
175 
176   if (DangerTypeIsDangerous(old_danger_type) &&
177       current_danger_type == download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED) {
178     ReportDangerousDownloadWarningBypassed(download, old_danger_type);
179   }
180 
181   if (old_danger_type ==
182           download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING &&
183       current_danger_type == download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED) {
184     ReportAnalysisConnectorWarningBypassed(download);
185   }
186 
187   danger_types_[download] = current_danger_type;
188 }
189 
190 }  // namespace safe_browsing
191