Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: chrome/browser/safe_browsing/download_protection_service.cc

Issue 8345033: Collect some histograms about signed binary downloads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/safe_browsing/download_protection_service.h" 5 #include "chrome/browser/safe_browsing/download_protection_service.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
11 #include "base/string_util.h"
11 #include "chrome/browser/safe_browsing/safe_browsing_service.h" 12 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
13 #include "chrome/browser/safe_browsing/signature_util.h"
12 #include "chrome/common/net/http_return.h" 14 #include "chrome/common/net/http_return.h"
13 #include "chrome/common/safe_browsing/csd.pb.h" 15 #include "chrome/common/safe_browsing/csd.pb.h"
14 #include "content/browser/browser_thread.h" 16 #include "content/browser/browser_thread.h"
15 #include "net/base/load_flags.h" 17 #include "net/base/load_flags.h"
16 #include "net/url_request/url_request_context_getter.h" 18 #include "net/url_request/url_request_context_getter.h"
17 #include "net/url_request/url_request_status.h" 19 #include "net/url_request/url_request_status.h"
18 20
19 namespace safe_browsing { 21 namespace safe_browsing {
20 22
21 const char DownloadProtectionService::kDownloadRequestUrl[] = 23 const char DownloadProtectionService::kDownloadRequestUrl[] =
22 "https://sb-ssl.google.com/safebrowsing/clientreport/download"; 24 "https://sb-ssl.google.com/safebrowsing/clientreport/download";
23 25
26 namespace {
27 bool IsBinaryFile(const FilePath& file) {
28 return (file.MatchesExtension(FILE_PATH_LITERAL(".exe")) ||
29 file.MatchesExtension(FILE_PATH_LITERAL(".cab")) ||
30 file.MatchesExtension(FILE_PATH_LITERAL(".msi")));
31 }
32 } // namespace
33
24 DownloadProtectionService::DownloadInfo::DownloadInfo() 34 DownloadProtectionService::DownloadInfo::DownloadInfo()
25 : total_bytes(0), user_initiated(false) {} 35 : total_bytes(0), user_initiated(false) {}
26 36
27 DownloadProtectionService::DownloadInfo::~DownloadInfo() {} 37 DownloadProtectionService::DownloadInfo::~DownloadInfo() {}
28 38
29 DownloadProtectionService::DownloadProtectionService( 39 DownloadProtectionService::DownloadProtectionService(
30 SafeBrowsingService* sb_service, 40 SafeBrowsingService* sb_service,
31 net::URLRequestContextGetter* request_context_getter) 41 net::URLRequestContextGetter* request_context_getter)
32 : sb_service_(sb_service), 42 : sb_service_(sb_service),
33 request_context_getter_(request_context_getter), 43 request_context_getter_(request_context_getter),
34 enabled_(false) {} 44 enabled_(false) {}
35 45
36 DownloadProtectionService::~DownloadProtectionService() { 46 DownloadProtectionService::~DownloadProtectionService() {
47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
37 STLDeleteContainerPairFirstPointers(download_requests_.begin(), 48 STLDeleteContainerPairFirstPointers(download_requests_.begin(),
38 download_requests_.end()); 49 download_requests_.end());
39 download_requests_.clear(); 50 download_requests_.clear();
40 } 51 }
41 52
42 void DownloadProtectionService::SetEnabled(bool enabled) { 53 void DownloadProtectionService::SetEnabled(bool enabled) {
43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
44 BrowserThread::PostTask( 55 BrowserThread::PostTask(
45 BrowserThread::IO, 56 BrowserThread::IO,
46 FROM_HERE, 57 FROM_HERE,
47 base::Bind(&DownloadProtectionService::SetEnabledOnIOThread, 58 base::Bind(&DownloadProtectionService::SetEnabledOnIOThread,
48 this, enabled)); 59 base::Unretained(this), enabled));
noelutz 2011/10/22 00:41:46 I just want to make sure I follow the code here.
49 } 60 }
50 61
51 void DownloadProtectionService::SetEnabledOnIOThread(bool enabled) { 62 void DownloadProtectionService::SetEnabledOnIOThread(bool enabled) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
53 if (enabled == enabled_) { 64 if (enabled == enabled_) {
54 return; 65 return;
55 } 66 }
56 enabled_ = enabled; 67 enabled_ = enabled;
57 if (!enabled_) { 68 if (!enabled_) {
58 for (std::map<const URLFetcher*, CheckDownloadCallback>::iterator it = 69 for (std::map<const URLFetcher*, CheckDownloadCallback>::iterator it =
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 // For now no matter what we'll always say the download is safe. 102 // For now no matter what we'll always say the download is safe.
92 // TODO(noelutz): Parse the response body to see exactly what's going on. 103 // TODO(noelutz): Parse the response body to see exactly what's going on.
93 reason = REASON_INVALID_RESPONSE_PROTO; 104 reason = REASON_INVALID_RESPONSE_PROTO;
94 } else { 105 } else {
95 reason = REASON_SERVER_PING_FAILED; 106 reason = REASON_SERVER_PING_FAILED;
96 } 107 }
97 BrowserThread::PostTask( 108 BrowserThread::PostTask(
98 BrowserThread::UI, 109 BrowserThread::UI,
99 FROM_HERE, 110 FROM_HERE,
100 base::Bind(&DownloadProtectionService::EndCheckClientDownload, 111 base::Bind(&DownloadProtectionService::EndCheckClientDownload,
101 this, SAFE, reason, callback)); 112 base::Unretained(this), SAFE, reason, callback));
102 } else { 113 } else {
103 NOTREACHED(); 114 NOTREACHED();
104 } 115 }
105 } 116 }
106 117
107 bool DownloadProtectionService::CheckClientDownload( 118 bool DownloadProtectionService::CheckClientDownload(
108 const DownloadInfo& info, 119 const DownloadInfo& info,
109 const CheckDownloadCallback& callback) { 120 const CheckDownloadCallback& callback) {
110 // TODO(noelutz): implement some cache to make sure we don't issue the same 121 // TODO(noelutz): implement some cache to make sure we don't issue the same
111 // request over and over again if a user downloads the same binary multiple 122 // request over and over again if a user downloads the same binary multiple
112 // times. 123 // times.
113 if (info.download_url_chain.empty()) { 124 if (info.download_url_chain.empty()) {
114 RecordStats(REASON_INVALID_URL); 125 RecordStats(REASON_INVALID_URL);
115 return true; 126 return true;
116 } 127 }
117 const GURL& final_url = info.download_url_chain.back(); 128 const GURL& final_url = info.download_url_chain.back();
118 if (!final_url.is_valid() || final_url.is_empty() || 129 if (!final_url.is_valid() || final_url.is_empty() ||
119 !final_url.SchemeIs("http")) { 130 !final_url.SchemeIs("http")) {
120 RecordStats(REASON_INVALID_URL); 131 RecordStats(REASON_INVALID_URL);
121 return true; // For now we only support HTTP download URLs. 132 return true; // For now we only support HTTP download URLs.
122 } 133 }
134
135 if (!IsBinaryFile(info.local_file)) {
136 RecordStats(REASON_NOT_BINARY_FILE);
137 return true;
138 }
139
140 // Compute features from the file contents. Note that we record histograms
141 // based on the result, so this runs regardless of whether the pingbacks are
142 // enabled. Since we do blocking I/O, this happens on the file thread.
143 BrowserThread::PostTask(
144 BrowserThread::FILE,
145 FROM_HERE,
146 base::Bind(&DownloadProtectionService::ExtractFileFeatures,
147 base::Unretained(this), info, enabled_, callback));
noelutz 2011/10/22 00:41:46 I think there is a race condition here. You acces
148 return false;
149 }
150
151 void DownloadProtectionService::ExtractFileFeatures(
152 const DownloadInfo& info,
153 bool pingback_enabled,
154 const CheckDownloadCallback& callback) {
155 bool is_signed;
156 if (safe_browsing::signature_util::IsSigned(info.local_file)) {
157 VLOG(2) << "Downloaded a signed binary: " << info.local_file.value();
158 is_signed = true;
159 } else {
160 VLOG(2) << "Downloaded an unsigned binary: " << info.local_file.value();
161 is_signed = false;
162 }
163 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed);
164
123 // TODO(noelutz): DownloadInfo should also contain the IP address of every 165 // TODO(noelutz): DownloadInfo should also contain the IP address of every
124 // URL in the redirect chain. We also should check whether the download URL 166 // URL in the redirect chain. We also should check whether the download URL
125 // is hosted on the internal network. 167 // is hosted on the internal network.
126 BrowserThread::PostTask( 168 BrowserThread::PostTask(
127 BrowserThread::IO, 169 BrowserThread::IO,
128 FROM_HERE, 170 FROM_HERE,
129 base::Bind(&DownloadProtectionService::StartCheckClientDownload, 171 base::Bind(&DownloadProtectionService::StartCheckClientDownload,
130 this, info, callback)); 172 base::Unretained(this), info, pingback_enabled, callback));
131 return false;
132 } 173 }
133 174
134 void DownloadProtectionService::StartCheckClientDownload( 175 void DownloadProtectionService::StartCheckClientDownload(
135 const DownloadInfo& info, 176 const DownloadInfo& info,
177 bool pingback_enabled,
136 const CheckDownloadCallback& callback) { 178 const CheckDownloadCallback& callback) {
137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
138 if (!enabled_ || !sb_service_.get()) { 180 DownloadCheckResultReason reason = REASON_MAX;
139 // This is a hard fail. We won't even call the callback in this case. 181 if (!enabled_ || !sb_service_) {
140 RecordStats(REASON_SB_DISABLED); 182 reason = REASON_SB_DISABLED;
183 RecordStats(reason);
184 BrowserThread::PostTask(
185 BrowserThread::UI,
186 FROM_HERE,
187 base::Bind(&DownloadProtectionService::EndCheckClientDownload,
188 base::Unretained(this), SAFE, reason, callback));
noelutz 2011/10/22 00:41:46 Will this always work? What if the destructor is
141 return; 189 return;
142 } 190 }
143 DownloadCheckResultReason reason = REASON_MAX;
144 for (size_t i = 0; i < info.download_url_chain.size(); ++i) { 191 for (size_t i = 0; i < info.download_url_chain.size(); ++i) {
145 if (sb_service_->MatchDownloadWhitelistUrl(info.download_url_chain[i])) { 192 if (sb_service_->MatchDownloadWhitelistUrl(info.download_url_chain[i])) {
146 reason = REASON_WHITELISTED_URL; 193 reason = REASON_WHITELISTED_URL;
147 break; 194 break;
148 } 195 }
149 } 196 }
150 if (sb_service_->MatchDownloadWhitelistUrl(info.referrer_url)) { 197 if (sb_service_->MatchDownloadWhitelistUrl(info.referrer_url)) {
151 reason = REASON_WHITELISTED_REFERRER; 198 reason = REASON_WHITELISTED_REFERRER;
152 } 199 }
153 // TODO(noelutz): check signature and CA against whitelist. 200 // TODO(noelutz): check signature and CA against whitelist.
(...skipping 19 matching lines...) Expand all
173 if (!request.SerializeToString(&request_data)) { 220 if (!request.SerializeToString(&request_data)) {
174 reason = REASON_INVALID_REQUEST_PROTO; 221 reason = REASON_INVALID_REQUEST_PROTO;
175 } 222 }
176 223
177 if (reason != REASON_MAX) { 224 if (reason != REASON_MAX) {
178 // We stop here because the download is considered safe. 225 // We stop here because the download is considered safe.
179 BrowserThread::PostTask( 226 BrowserThread::PostTask(
180 BrowserThread::UI, 227 BrowserThread::UI,
181 FROM_HERE, 228 FROM_HERE,
182 base::Bind(&DownloadProtectionService::EndCheckClientDownload, 229 base::Bind(&DownloadProtectionService::EndCheckClientDownload,
183 this, SAFE, reason, callback)); 230 base::Unretained(this), SAFE, reason, callback));
noelutz 2011/10/22 00:41:46 same question as above.
184 return; 231 return;
185 } 232 }
186 233
187 URLFetcher* fetcher = URLFetcher::Create(0 /* ID used for testing */, 234 URLFetcher* fetcher = URLFetcher::Create(0 /* ID used for testing */,
188 GURL(kDownloadRequestUrl), 235 GURL(kDownloadRequestUrl),
189 URLFetcher::POST, 236 URLFetcher::POST,
190 this); 237 this);
191 download_requests_[fetcher] = callback; 238 download_requests_[fetcher] = callback;
192 fetcher->set_load_flags(net::LOAD_DISABLE_CACHE); 239 fetcher->set_load_flags(net::LOAD_DISABLE_CACHE);
193 fetcher->set_request_context(request_context_getter_.get()); 240 fetcher->set_request_context(request_context_getter_.get());
194 fetcher->set_upload_data("application/octet-stream", request_data); 241 fetcher->set_upload_data("application/octet-stream", request_data);
195 fetcher->Start(); 242 fetcher->Start();
196 } 243 }
197 244
198 void DownloadProtectionService::EndCheckClientDownload( 245 void DownloadProtectionService::EndCheckClientDownload(
199 DownloadCheckResult result, 246 DownloadCheckResult result,
200 DownloadCheckResultReason reason, 247 DownloadCheckResultReason reason,
201 const CheckDownloadCallback& callback) { 248 const CheckDownloadCallback& callback) {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203 RecordStats(reason); 250 RecordStats(reason);
204 callback.Run(result); 251 callback.Run(result);
205 } 252 }
206 253
207 void DownloadProtectionService::RecordStats(DownloadCheckResultReason reason) { 254 void DownloadProtectionService::RecordStats(DownloadCheckResultReason reason) {
208 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", 255 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats",
209 reason, 256 reason,
210 REASON_MAX); 257 REASON_MAX);
211 } 258 }
212 } // namespace safe_browsing 259 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698