| 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 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 | 109 |
| 110 class DownloadProtectionService::CheckClientDownloadRequest | 110 class DownloadProtectionService::CheckClientDownloadRequest |
| 111 : public base::RefCountedThreadSafe< | 111 : public base::RefCountedThreadSafe< |
| 112 DownloadProtectionService::CheckClientDownloadRequest, | 112 DownloadProtectionService::CheckClientDownloadRequest, |
| 113 BrowserThread::DeleteOnUIThread>, | 113 BrowserThread::DeleteOnUIThread>, |
| 114 public content::URLFetcherDelegate { | 114 public content::URLFetcherDelegate { |
| 115 public: | 115 public: |
| 116 CheckClientDownloadRequest(const DownloadInfo& info, | 116 CheckClientDownloadRequest(const DownloadInfo& info, |
| 117 const CheckDownloadCallback& callback, | 117 const CheckDownloadCallback& callback, |
| 118 DownloadProtectionService* service, | 118 DownloadProtectionService* service, |
| 119 SafeBrowsingService* sb_service) | 119 SafeBrowsingService* sb_service, |
| 120 SignatureUtil* signature_util) |
| 120 : info_(info), | 121 : info_(info), |
| 121 callback_(callback), | 122 callback_(callback), |
| 122 service_(service), | 123 service_(service), |
| 124 signature_util_(signature_util), |
| 123 sb_service_(sb_service), | 125 sb_service_(sb_service), |
| 124 pingback_enabled_(service_->enabled()), | 126 pingback_enabled_(service_->enabled()) { |
| 125 is_signed_(false) { | |
| 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 127 } | 128 } |
| 128 | 129 |
| 129 void Start() { | 130 void Start() { |
| 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 131 // TODO(noelutz): implement some cache to make sure we don't issue the same | 132 // TODO(noelutz): implement some cache to make sure we don't issue the same |
| 132 // request over and over again if a user downloads the same binary multiple | 133 // request over and over again if a user downloads the same binary multiple |
| 133 // times. | 134 // times. |
| 134 if (info_.download_url_chain.empty()) { | 135 if (info_.download_url_chain.empty()) { |
| 135 RecordStats(REASON_INVALID_URL); | 136 RecordStats(REASON_INVALID_URL); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 private: | 213 private: |
| 213 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; | 214 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; |
| 214 friend class DeleteTask<CheckClientDownloadRequest>; | 215 friend class DeleteTask<CheckClientDownloadRequest>; |
| 215 | 216 |
| 216 virtual ~CheckClientDownloadRequest() { | 217 virtual ~CheckClientDownloadRequest() { |
| 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 218 } | 219 } |
| 219 | 220 |
| 220 void ExtractFileFeatures() { | 221 void ExtractFileFeatures() { |
| 221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 222 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 222 if (safe_browsing::signature_util::IsSigned(info_.local_file)) { | 223 signature_util_->CheckSignature(info_.local_file, &signature_info_); |
| 224 bool is_signed = signature_info_.has_certificate_contents(); |
| 225 if (is_signed) { |
| 223 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); | 226 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); |
| 224 is_signed_ = true; | |
| 225 } else { | 227 } else { |
| 226 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); | 228 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); |
| 227 is_signed_ = false; | |
| 228 } | 229 } |
| 229 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed_); | 230 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed); |
| 230 | 231 |
| 231 // TODO(noelutz): DownloadInfo should also contain the IP address of every | 232 // TODO(noelutz): DownloadInfo should also contain the IP address of every |
| 232 // URL in the redirect chain. We also should check whether the download | 233 // URL in the redirect chain. We also should check whether the download |
| 233 // URL is hosted on the internal network. | 234 // URL is hosted on the internal network. |
| 234 BrowserThread::PostTask( | 235 BrowserThread::PostTask( |
| 235 BrowserThread::IO, | 236 BrowserThread::IO, |
| 236 FROM_HERE, | 237 FROM_HERE, |
| 237 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); | 238 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); |
| 238 } | 239 } |
| 239 | 240 |
| 240 void CheckWhitelists() { | 241 void CheckWhitelists() { |
| 241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 242 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 242 DownloadCheckResultReason reason = REASON_MAX; | 243 DownloadCheckResultReason reason = REASON_MAX; |
| 243 if (!sb_service_.get()) { | 244 if (!sb_service_.get()) { |
| 244 reason = REASON_SB_DISABLED; | 245 reason = REASON_SB_DISABLED; |
| 245 } else { | 246 } else { |
| 246 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { | 247 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { |
| 247 const GURL& url = info_.download_url_chain[i]; | 248 const GURL& url = info_.download_url_chain[i]; |
| 248 if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) { | 249 if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) { |
| 249 reason = REASON_WHITELISTED_URL; | 250 reason = REASON_WHITELISTED_URL; |
| 250 break; | 251 break; |
| 251 } | 252 } |
| 252 } | 253 } |
| 253 if (info_.referrer_url.is_valid() && reason == REASON_MAX && | 254 if (info_.referrer_url.is_valid() && reason == REASON_MAX && |
| 254 sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) { | 255 sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) { |
| 255 reason = REASON_WHITELISTED_REFERRER; | 256 reason = REASON_WHITELISTED_REFERRER; |
| 256 } | 257 } |
| 257 if (reason != REASON_MAX || is_signed_) { | 258 if (reason != REASON_MAX || signature_info_.has_certificate_contents()) { |
| 258 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); | 259 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); |
| 259 } | 260 } |
| 260 } | 261 } |
| 261 if (reason != REASON_MAX) { | 262 if (reason != REASON_MAX) { |
| 262 RecordStats(reason); | 263 RecordStats(reason); |
| 263 PostFinishTask(SAFE); | 264 PostFinishTask(SAFE); |
| 264 } else if (!pingback_enabled_) { | 265 } else if (!pingback_enabled_) { |
| 265 RecordStats(REASON_SB_DISABLED); | 266 RecordStats(REASON_SB_DISABLED); |
| 266 PostFinishTask(SAFE); | 267 PostFinishTask(SAFE); |
| 267 } else { | 268 } else { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 297 if (i == info_.download_url_chain.size() - 1) { | 298 if (i == info_.download_url_chain.size() - 1) { |
| 298 // The last URL in the chain is the download URL. | 299 // The last URL in the chain is the download URL. |
| 299 resource->set_type(ClientDownloadRequest::DOWNLOAD_URL); | 300 resource->set_type(ClientDownloadRequest::DOWNLOAD_URL); |
| 300 resource->set_referrer(info_.referrer_url.spec()); | 301 resource->set_referrer(info_.referrer_url.spec()); |
| 301 } else { | 302 } else { |
| 302 resource->set_type(ClientDownloadRequest::DOWNLOAD_REDIRECT); | 303 resource->set_type(ClientDownloadRequest::DOWNLOAD_REDIRECT); |
| 303 } | 304 } |
| 304 // TODO(noelutz): fill out the remote IP addresses. | 305 // TODO(noelutz): fill out the remote IP addresses. |
| 305 } | 306 } |
| 306 request.set_user_initiated(info_.user_initiated); | 307 request.set_user_initiated(info_.user_initiated); |
| 308 request.mutable_signature()->CopyFrom(signature_info_); |
| 307 std::string request_data; | 309 std::string request_data; |
| 308 if (!request.SerializeToString(&request_data)) { | 310 if (!request.SerializeToString(&request_data)) { |
| 309 RecordStats(REASON_INVALID_REQUEST_PROTO); | 311 RecordStats(REASON_INVALID_REQUEST_PROTO); |
| 310 FinishRequest(SAFE); | 312 FinishRequest(SAFE); |
| 311 return; | 313 return; |
| 312 } | 314 } |
| 313 | 315 |
| 314 VLOG(2) << "Sending a request for URL: " | 316 VLOG(2) << "Sending a request for URL: " |
| 315 << info_.download_url_chain.back(); | 317 << info_.download_url_chain.back(); |
| 316 fetcher_.reset(content::URLFetcher::Create(0 /* ID used for testing */, | 318 fetcher_.reset(content::URLFetcher::Create(0 /* ID used for testing */, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 340 } | 342 } |
| 341 } | 343 } |
| 342 | 344 |
| 343 void RecordStats(DownloadCheckResultReason reason) { | 345 void RecordStats(DownloadCheckResultReason reason) { |
| 344 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", | 346 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", |
| 345 reason, | 347 reason, |
| 346 REASON_MAX); | 348 REASON_MAX); |
| 347 } | 349 } |
| 348 | 350 |
| 349 DownloadInfo info_; | 351 DownloadInfo info_; |
| 352 ClientDownloadRequest_SignatureInfo signature_info_; |
| 350 CheckDownloadCallback callback_; | 353 CheckDownloadCallback callback_; |
| 351 // Will be NULL if the request has been canceled. | 354 // Will be NULL if the request has been canceled. |
| 352 DownloadProtectionService* service_; | 355 DownloadProtectionService* service_; |
| 356 scoped_refptr<SignatureUtil> signature_util_; |
| 353 scoped_refptr<SafeBrowsingService> sb_service_; | 357 scoped_refptr<SafeBrowsingService> sb_service_; |
| 354 const bool pingback_enabled_; | 358 const bool pingback_enabled_; |
| 355 bool is_signed_; | |
| 356 scoped_ptr<content::URLFetcher> fetcher_; | 359 scoped_ptr<content::URLFetcher> fetcher_; |
| 357 | 360 |
| 358 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); | 361 DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest); |
| 359 }; | 362 }; |
| 360 | 363 |
| 361 DownloadProtectionService::DownloadProtectionService( | 364 DownloadProtectionService::DownloadProtectionService( |
| 362 SafeBrowsingService* sb_service, | 365 SafeBrowsingService* sb_service, |
| 363 net::URLRequestContextGetter* request_context_getter) | 366 net::URLRequestContextGetter* request_context_getter) |
| 364 : sb_service_(sb_service), | 367 : sb_service_(sb_service), |
| 365 request_context_getter_(request_context_getter), | 368 request_context_getter_(request_context_getter), |
| 366 enabled_(false) {} | 369 enabled_(false), |
| 370 signature_util_(new SignatureUtil()) {} |
| 367 | 371 |
| 368 DownloadProtectionService::~DownloadProtectionService() { | 372 DownloadProtectionService::~DownloadProtectionService() { |
| 369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 370 CancelPendingRequests(); | 374 CancelPendingRequests(); |
| 371 } | 375 } |
| 372 | 376 |
| 373 void DownloadProtectionService::SetEnabled(bool enabled) { | 377 void DownloadProtectionService::SetEnabled(bool enabled) { |
| 374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 375 if (enabled == enabled_) { | 379 if (enabled == enabled_) { |
| 376 return; | 380 return; |
| 377 } | 381 } |
| 378 enabled_ = enabled; | 382 enabled_ = enabled; |
| 379 if (!enabled_) { | 383 if (!enabled_) { |
| 380 CancelPendingRequests(); | 384 CancelPendingRequests(); |
| 381 } | 385 } |
| 382 } | 386 } |
| 383 | 387 |
| 384 void DownloadProtectionService::CheckClientDownload( | 388 void DownloadProtectionService::CheckClientDownload( |
| 385 const DownloadProtectionService::DownloadInfo& info, | 389 const DownloadProtectionService::DownloadInfo& info, |
| 386 const CheckDownloadCallback& callback) { | 390 const CheckDownloadCallback& callback) { |
| 387 scoped_refptr<CheckClientDownloadRequest> request( | 391 scoped_refptr<CheckClientDownloadRequest> request( |
| 388 new CheckClientDownloadRequest(info, callback, this, sb_service_)); | 392 new CheckClientDownloadRequest(info, callback, this, |
| 393 sb_service_, signature_util_.get())); |
| 389 download_requests_.insert(request); | 394 download_requests_.insert(request); |
| 390 request->Start(); | 395 request->Start(); |
| 391 } | 396 } |
| 392 | 397 |
| 393 void DownloadProtectionService::CancelPendingRequests() { | 398 void DownloadProtectionService::CancelPendingRequests() { |
| 394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 395 for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = | 400 for (std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = |
| 396 download_requests_.begin(); | 401 download_requests_.begin(); |
| 397 it != download_requests_.end(); ++it) { | 402 it != download_requests_.end(); ++it) { |
| 398 (*it)->Cancel(); | 403 (*it)->Cancel(); |
| 399 } | 404 } |
| 400 download_requests_.clear(); | 405 download_requests_.clear(); |
| 401 } | 406 } |
| 402 | 407 |
| 403 void DownloadProtectionService::RequestFinished( | 408 void DownloadProtectionService::RequestFinished( |
| 404 CheckClientDownloadRequest* request) { | 409 CheckClientDownloadRequest* request) { |
| 405 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 406 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = | 411 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = |
| 407 download_requests_.find(request); | 412 download_requests_.find(request); |
| 408 DCHECK(it != download_requests_.end()); | 413 DCHECK(it != download_requests_.end()); |
| 409 download_requests_.erase(*it); | 414 download_requests_.erase(*it); |
| 410 } | 415 } |
| 411 | 416 |
| 412 } // namespace safe_browsing | 417 } // namespace safe_browsing |
| OLD | NEW |