OLD | NEW |
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" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 public content::URLFetcherDelegate { | 60 public content::URLFetcherDelegate { |
61 public: | 61 public: |
62 CheckClientDownloadRequest(const DownloadInfo& info, | 62 CheckClientDownloadRequest(const DownloadInfo& info, |
63 const CheckDownloadCallback& callback, | 63 const CheckDownloadCallback& callback, |
64 DownloadProtectionService* service, | 64 DownloadProtectionService* service, |
65 SafeBrowsingService* sb_service) | 65 SafeBrowsingService* sb_service) |
66 : info_(info), | 66 : info_(info), |
67 callback_(callback), | 67 callback_(callback), |
68 service_(service), | 68 service_(service), |
69 sb_service_(sb_service), | 69 sb_service_(sb_service), |
70 pingback_enabled_(service_->enabled()) { | 70 pingback_enabled_(service_->enabled()), |
| 71 is_signed_(false) { |
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
72 } | 73 } |
73 | 74 |
74 void Start() { | 75 void Start() { |
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
76 // TODO(noelutz): implement some cache to make sure we don't issue the same | 77 // TODO(noelutz): implement some cache to make sure we don't issue the same |
77 // request over and over again if a user downloads the same binary multiple | 78 // request over and over again if a user downloads the same binary multiple |
78 // times. | 79 // times. |
79 if (info_.download_url_chain.empty()) { | 80 if (info_.download_url_chain.empty()) { |
80 RecordStats(REASON_INVALID_URL); | 81 RecordStats(REASON_INVALID_URL); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 private: | 156 private: |
156 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; | 157 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; |
157 friend class DeleteTask<CheckClientDownloadRequest>; | 158 friend class DeleteTask<CheckClientDownloadRequest>; |
158 | 159 |
159 virtual ~CheckClientDownloadRequest() { | 160 virtual ~CheckClientDownloadRequest() { |
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
161 } | 162 } |
162 | 163 |
163 void ExtractFileFeatures() { | 164 void ExtractFileFeatures() { |
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
165 bool is_signed; | |
166 if (safe_browsing::signature_util::IsSigned(info_.local_file)) { | 166 if (safe_browsing::signature_util::IsSigned(info_.local_file)) { |
167 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); | 167 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); |
168 is_signed = true; | 168 is_signed_ = true; |
169 } else { | 169 } else { |
170 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); | 170 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); |
171 is_signed = false; | 171 is_signed_ = false; |
172 } | 172 } |
173 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed); | 173 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed_); |
174 | 174 |
175 // TODO(noelutz): DownloadInfo should also contain the IP address of every | 175 // TODO(noelutz): DownloadInfo should also contain the IP address of every |
176 // URL in the redirect chain. We also should check whether the download | 176 // URL in the redirect chain. We also should check whether the download |
177 // URL is hosted on the internal network. | 177 // URL is hosted on the internal network. |
178 BrowserThread::PostTask( | 178 BrowserThread::PostTask( |
179 BrowserThread::IO, | 179 BrowserThread::IO, |
180 FROM_HERE, | 180 FROM_HERE, |
181 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); | 181 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); |
182 } | 182 } |
183 | 183 |
184 void CheckWhitelists() { | 184 void CheckWhitelists() { |
185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
186 DownloadCheckResultReason reason = REASON_MAX; | 186 DownloadCheckResultReason reason = REASON_MAX; |
187 if (!pingback_enabled_ || !sb_service_.get()) { | 187 if (!sb_service_.get()) { |
188 reason = REASON_SB_DISABLED; | 188 reason = REASON_SB_DISABLED; |
189 } else { | 189 } else { |
190 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { | 190 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { |
191 const GURL& url = info_.download_url_chain[i]; | 191 const GURL& url = info_.download_url_chain[i]; |
192 if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) { | 192 if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) { |
193 reason = REASON_WHITELISTED_URL; | 193 reason = REASON_WHITELISTED_URL; |
194 break; | 194 break; |
195 } | 195 } |
196 } | 196 } |
197 if (info_.referrer_url.is_valid() && | 197 if (info_.referrer_url.is_valid() && reason == REASON_MAX && |
198 sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) { | 198 sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) { |
199 reason = REASON_WHITELISTED_REFERRER; | 199 reason = REASON_WHITELISTED_REFERRER; |
200 } | 200 } |
| 201 if (reason != REASON_MAX || is_signed_) { |
| 202 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); |
| 203 } |
201 } | 204 } |
202 if (reason != REASON_MAX) { | 205 if (reason != REASON_MAX) { |
203 RecordStats(reason); | 206 RecordStats(reason); |
204 PostFinishTask(SAFE); | 207 PostFinishTask(SAFE); |
205 return; | 208 } else if (!pingback_enabled_) { |
| 209 RecordStats(REASON_SB_DISABLED); |
| 210 PostFinishTask(SAFE); |
| 211 } else { |
| 212 // TODO(noelutz): check signature and CA against whitelist. |
| 213 |
| 214 // The URLFetcher is owned by the UI thread, so post a message to |
| 215 // start the pingback. |
| 216 BrowserThread::PostTask( |
| 217 BrowserThread::UI, |
| 218 FROM_HERE, |
| 219 base::Bind(&CheckClientDownloadRequest::SendRequest, this)); |
206 } | 220 } |
207 | |
208 // TODO(noelutz): check signature and CA against whitelist. | |
209 | |
210 // The URLFetcher is owned by the UI thread, so post a message to | |
211 // start the pingback. | |
212 BrowserThread::PostTask( | |
213 BrowserThread::UI, | |
214 FROM_HERE, | |
215 base::Bind(&CheckClientDownloadRequest::SendRequest, this)); | |
216 } | 221 } |
217 | 222 |
218 void SendRequest() { | 223 void SendRequest() { |
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
220 | 225 |
221 // This is our last chance to check whether the request has been canceled | 226 // This is our last chance to check whether the request has been canceled |
222 // before sending it. | 227 // before sending it. |
223 if (!service_) { | 228 if (!service_) { |
| 229 RecordStats(REASON_REQUEST_CANCELED); |
224 FinishRequest(SAFE); | 230 FinishRequest(SAFE); |
225 return; | 231 return; |
226 } | 232 } |
227 | 233 |
228 ClientDownloadRequest request; | 234 ClientDownloadRequest request; |
229 request.set_url(info_.download_url_chain.back().spec()); | 235 request.set_url(info_.download_url_chain.back().spec()); |
230 request.mutable_digests()->set_sha256(info_.sha256_hash); | 236 request.mutable_digests()->set_sha256(info_.sha256_hash); |
231 request.set_length(info_.total_bytes); | 237 request.set_length(info_.total_bytes); |
232 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { | 238 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { |
233 ClientDownloadRequest::Resource* resource = request.add_resources(); | 239 ClientDownloadRequest::Resource* resource = request.add_resources(); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", | 288 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", |
283 reason, | 289 reason, |
284 REASON_MAX); | 290 REASON_MAX); |
285 } | 291 } |
286 | 292 |
287 DownloadInfo info_; | 293 DownloadInfo info_; |
288 CheckDownloadCallback callback_; | 294 CheckDownloadCallback callback_; |
289 // Will be NULL if the request has been canceled. | 295 // Will be NULL if the request has been canceled. |
290 DownloadProtectionService* service_; | 296 DownloadProtectionService* service_; |
291 scoped_refptr<SafeBrowsingService> sb_service_; | 297 scoped_refptr<SafeBrowsingService> sb_service_; |
292 bool pingback_enabled_; | 298 const bool pingback_enabled_; |
| 299 bool is_signed_; |
293 scoped_ptr<content::URLFetcher> fetcher_; | 300 scoped_ptr<content::URLFetcher> fetcher_; |
294 | 301 |
295 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); | 302 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); |
296 }; | 303 }; |
297 | 304 |
298 DownloadProtectionService::DownloadProtectionService( | 305 DownloadProtectionService::DownloadProtectionService( |
299 SafeBrowsingService* sb_service, | 306 SafeBrowsingService* sb_service, |
300 net::URLRequestContextGetter* request_context_getter) | 307 net::URLRequestContextGetter* request_context_getter) |
301 : sb_service_(sb_service), | 308 : sb_service_(sb_service), |
302 request_context_getter_(request_context_getter), | 309 request_context_getter_(request_context_getter), |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 void DownloadProtectionService::RequestFinished( | 347 void DownloadProtectionService::RequestFinished( |
341 CheckClientDownloadRequest* request) { | 348 CheckClientDownloadRequest* request) { |
342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
343 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = | 350 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = |
344 download_requests_.find(request); | 351 download_requests_.find(request); |
345 DCHECK(it != download_requests_.end()); | 352 DCHECK(it != download_requests_.end()); |
346 download_requests_.erase(*it); | 353 download_requests_.erase(*it); |
347 } | 354 } |
348 | 355 |
349 } // namespace safe_browsing | 356 } // namespace safe_browsing |
OLD | NEW |