Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 | 132 |
| 133 DOWNLOAD_HASH_CHECKS_TOTAL, | 133 DOWNLOAD_HASH_CHECKS_TOTAL, |
| 134 DOWNLOAD_HASH_CHECKS_MALWARE, | 134 DOWNLOAD_HASH_CHECKS_MALWARE, |
| 135 | 135 |
| 136 // Memory space for histograms is determined by the max. | 136 // Memory space for histograms is determined by the max. |
| 137 // ALWAYS ADD NEW VALUES BEFORE THIS ONE. | 137 // ALWAYS ADD NEW VALUES BEFORE THIS ONE. |
| 138 DOWNLOAD_CHECKS_MAX | 138 DOWNLOAD_CHECKS_MAX |
| 139 }; | 139 }; |
| 140 } // namespace | 140 } // namespace |
| 141 | 141 |
| 142 DownloadProtectionService::DownloadInfo::DownloadInfo() | |
| 143 : total_bytes(0), user_initiated(false), zipped_executable(false) {} | |
| 144 | |
| 145 DownloadProtectionService::DownloadInfo::~DownloadInfo() {} | |
| 146 | |
| 147 std::string DownloadProtectionService::DownloadInfo::DebugString() const { | |
| 148 std::string chain; | |
| 149 for (size_t i = 0; i < download_url_chain.size(); ++i) { | |
| 150 chain += download_url_chain[i].spec(); | |
| 151 if (i < download_url_chain.size() - 1) { | |
| 152 chain += " -> "; | |
| 153 } | |
| 154 } | |
| 155 return base::StringPrintf( | |
| 156 "DownloadInfo {addr:0x%p, download_url_chain:[%s], local_file:%" | |
| 157 PRFilePath ", target_file:%" PRFilePath ", referrer_url:%s, " | |
| 158 "sha256_hash:%s, total_bytes:%" PRId64 ", user_initiated: %s, " | |
| 159 "zipped_executable: %s}", | |
| 160 reinterpret_cast<const void*>(this), | |
| 161 chain.c_str(), | |
| 162 local_file.value().c_str(), | |
| 163 target_file.value().c_str(), | |
| 164 referrer_url.spec().c_str(), | |
| 165 base::HexEncode(sha256_hash.data(), sha256_hash.size()).c_str(), | |
| 166 total_bytes, | |
| 167 user_initiated ? "true" : "false", | |
| 168 zipped_executable ? "true" : "false"); | |
| 169 } | |
| 170 | |
| 171 // static | |
| 172 DownloadProtectionService::DownloadInfo | |
| 173 DownloadProtectionService::DownloadInfo::FromDownloadItem( | |
| 174 const content::DownloadItem& item) { | |
| 175 DownloadInfo download_info; | |
| 176 download_info.target_file = item.GetTargetFilePath(); | |
| 177 download_info.sha256_hash = item.GetHash(); | |
| 178 download_info.local_file = item.GetFullPath(); | |
| 179 download_info.download_url_chain = item.GetUrlChain(); | |
| 180 download_info.referrer_url = item.GetReferrerUrl(); | |
| 181 download_info.total_bytes = item.GetTotalBytes(); | |
| 182 download_info.remote_address = item.GetRemoteAddress(); | |
| 183 download_info.user_initiated = item.HasUserGesture(); | |
| 184 return download_info; | |
| 185 } | |
| 186 | |
| 187 // Parent SafeBrowsing::Client class used to lookup the bad binary | 142 // Parent SafeBrowsing::Client class used to lookup the bad binary |
| 188 // URL and digest list. There are two sub-classes (one for each list). | 143 // URL and digest list. There are two sub-classes (one for each list). |
| 189 class DownloadSBClient | 144 class DownloadSBClient |
| 190 : public SafeBrowsingDatabaseManager::Client, | 145 : public SafeBrowsingDatabaseManager::Client, |
| 191 public base::RefCountedThreadSafe<DownloadSBClient> { | 146 public base::RefCountedThreadSafe<DownloadSBClient> { |
| 192 public: | 147 public: |
| 193 DownloadSBClient( | 148 DownloadSBClient( |
| 194 const DownloadProtectionService::DownloadInfo& info, | 149 const content::DownloadItem& item, |
| 195 const DownloadProtectionService::CheckDownloadCallback& callback, | 150 const DownloadProtectionService::CheckDownloadCallback& callback, |
| 196 const scoped_refptr<SafeBrowsingUIManager>& ui_manager, | 151 const scoped_refptr<SafeBrowsingUIManager>& ui_manager, |
| 197 SBStatsType total_type, | 152 SBStatsType total_type, |
| 198 SBStatsType dangerous_type) | 153 SBStatsType dangerous_type) |
| 199 : info_(info), | 154 : sha256_hash_(item.GetHash()), |
| 155 url_chain_(item.GetUrlChain()), | |
| 156 referrer_url_(item.GetReferrerUrl()), | |
| 200 callback_(callback), | 157 callback_(callback), |
| 201 ui_manager_(ui_manager), | 158 ui_manager_(ui_manager), |
| 202 start_time_(base::TimeTicks::Now()), | 159 start_time_(base::TimeTicks::Now()), |
| 203 total_type_(total_type), | 160 total_type_(total_type), |
| 204 dangerous_type_(dangerous_type) {} | 161 dangerous_type_(dangerous_type) {} |
| 205 | 162 |
| 206 virtual void StartCheck() = 0; | 163 virtual void StartCheck() = 0; |
| 207 virtual bool IsDangerous(SBThreatType threat_type) const = 0; | 164 virtual bool IsDangerous(SBThreatType threat_type) const = 0; |
| 208 | 165 |
| 209 protected: | 166 protected: |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 224 BrowserThread::PostTask( | 181 BrowserThread::PostTask( |
| 225 BrowserThread::UI, | 182 BrowserThread::UI, |
| 226 FROM_HERE, | 183 FROM_HERE, |
| 227 base::Bind(&DownloadSBClient::ReportMalware, | 184 base::Bind(&DownloadSBClient::ReportMalware, |
| 228 this, threat_type)); | 185 this, threat_type)); |
| 229 } | 186 } |
| 230 } | 187 } |
| 231 | 188 |
| 232 void ReportMalware(SBThreatType threat_type) { | 189 void ReportMalware(SBThreatType threat_type) { |
| 233 std::string post_data; | 190 std::string post_data; |
| 234 if (!info_.sha256_hash.empty()) | 191 if (!sha256_hash_.empty()) |
| 235 post_data += base::HexEncode(info_.sha256_hash.data(), | 192 post_data += base::HexEncode(sha256_hash_.data(), |
| 236 info_.sha256_hash.size()) + "\n"; | 193 sha256_hash_.size()) + "\n"; |
| 237 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { | 194 for (size_t i = 0; i < url_chain_.size(); ++i) { |
| 238 post_data += info_.download_url_chain[i].spec() + "\n"; | 195 post_data += url_chain_[i].spec() + "\n"; |
| 239 } | 196 } |
| 240 ui_manager_->ReportSafeBrowsingHit( | 197 ui_manager_->ReportSafeBrowsingHit( |
| 241 info_.download_url_chain.back(), // malicious_url | 198 url_chain_.back(), // malicious_url |
| 242 info_.download_url_chain.front(), // page_url | 199 url_chain_.front(), // page_url |
| 243 info_.referrer_url, | 200 referrer_url_, |
| 244 true, // is_subresource | 201 true, // is_subresource |
| 245 threat_type, | 202 threat_type, |
| 246 post_data); | 203 post_data); |
| 247 } | 204 } |
| 248 | 205 |
| 249 void UpdateDownloadCheckStats(SBStatsType stat_type) { | 206 void UpdateDownloadCheckStats(SBStatsType stat_type) { |
| 250 UMA_HISTOGRAM_ENUMERATION("SB2.DownloadChecks", | 207 UMA_HISTOGRAM_ENUMERATION("SB2.DownloadChecks", |
| 251 stat_type, | 208 stat_type, |
| 252 DOWNLOAD_CHECKS_MAX); | 209 DOWNLOAD_CHECKS_MAX); |
| 253 } | 210 } |
| 254 | 211 |
| 255 DownloadProtectionService::DownloadInfo info_; | 212 std::string sha256_hash_; |
| 213 std::vector<GURL> url_chain_; | |
| 214 GURL referrer_url_; | |
| 256 DownloadProtectionService::CheckDownloadCallback callback_; | 215 DownloadProtectionService::CheckDownloadCallback callback_; |
| 257 scoped_refptr<SafeBrowsingUIManager> ui_manager_; | 216 scoped_refptr<SafeBrowsingUIManager> ui_manager_; |
| 258 base::TimeTicks start_time_; | 217 base::TimeTicks start_time_; |
| 259 | 218 |
| 260 private: | 219 private: |
| 261 const SBStatsType total_type_; | 220 const SBStatsType total_type_; |
| 262 const SBStatsType dangerous_type_; | 221 const SBStatsType dangerous_type_; |
| 263 | 222 |
| 264 DISALLOW_COPY_AND_ASSIGN(DownloadSBClient); | 223 DISALLOW_COPY_AND_ASSIGN(DownloadSBClient); |
| 265 }; | 224 }; |
| 266 | 225 |
| 267 class DownloadUrlSBClient : public DownloadSBClient { | 226 class DownloadUrlSBClient : public DownloadSBClient { |
| 268 public: | 227 public: |
| 269 DownloadUrlSBClient( | 228 DownloadUrlSBClient( |
| 270 const DownloadProtectionService::DownloadInfo& info, | 229 const content::DownloadItem& item, |
| 271 const DownloadProtectionService::CheckDownloadCallback& callback, | 230 const DownloadProtectionService::CheckDownloadCallback& callback, |
| 272 const scoped_refptr<SafeBrowsingUIManager>& ui_manager, | 231 const scoped_refptr<SafeBrowsingUIManager>& ui_manager, |
| 273 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager) | 232 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager) |
| 274 : DownloadSBClient(info, callback, ui_manager, | 233 : DownloadSBClient(item, callback, ui_manager, |
| 275 DOWNLOAD_URL_CHECKS_TOTAL, | 234 DOWNLOAD_URL_CHECKS_TOTAL, |
| 276 DOWNLOAD_URL_CHECKS_MALWARE), | 235 DOWNLOAD_URL_CHECKS_MALWARE), |
| 277 database_manager_(database_manager) { } | 236 database_manager_(database_manager) { } |
| 278 | 237 |
| 279 virtual void StartCheck() OVERRIDE { | 238 virtual void StartCheck() OVERRIDE { |
| 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 281 if (!database_manager_ || database_manager_->CheckDownloadUrl( | 240 if (!database_manager_ || database_manager_->CheckDownloadUrl( |
| 282 info_.download_url_chain, this)) { | 241 url_chain_, this)) { |
| 283 CheckDone(SB_THREAT_TYPE_SAFE); | 242 CheckDone(SB_THREAT_TYPE_SAFE); |
| 284 } else { | 243 } else { |
| 285 AddRef(); // SafeBrowsingService takes a pointer not a scoped_refptr. | 244 AddRef(); // SafeBrowsingService takes a pointer not a scoped_refptr. |
| 286 } | 245 } |
| 287 } | 246 } |
| 288 | 247 |
| 289 virtual bool IsDangerous(SBThreatType threat_type) const OVERRIDE { | 248 virtual bool IsDangerous(SBThreatType threat_type) const OVERRIDE { |
| 290 return threat_type == SB_THREAT_TYPE_BINARY_MALWARE_URL; | 249 return threat_type == SB_THREAT_TYPE_BINARY_MALWARE_URL; |
| 291 } | 250 } |
| 292 | 251 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 304 private: | 263 private: |
| 305 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; | 264 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; |
| 306 | 265 |
| 307 DISALLOW_COPY_AND_ASSIGN(DownloadUrlSBClient); | 266 DISALLOW_COPY_AND_ASSIGN(DownloadUrlSBClient); |
| 308 }; | 267 }; |
| 309 | 268 |
| 310 class DownloadProtectionService::CheckClientDownloadRequest | 269 class DownloadProtectionService::CheckClientDownloadRequest |
| 311 : public base::RefCountedThreadSafe< | 270 : public base::RefCountedThreadSafe< |
| 312 DownloadProtectionService::CheckClientDownloadRequest, | 271 DownloadProtectionService::CheckClientDownloadRequest, |
| 313 BrowserThread::DeleteOnUIThread>, | 272 BrowserThread::DeleteOnUIThread>, |
| 314 public net::URLFetcherDelegate { | 273 public net::URLFetcherDelegate, |
| 274 public content::DownloadItem::Observer { | |
| 315 public: | 275 public: |
| 316 CheckClientDownloadRequest( | 276 CheckClientDownloadRequest( |
| 317 const DownloadInfo& info, | 277 content::DownloadItem* item, |
| 318 const CheckDownloadCallback& callback, | 278 const CheckDownloadCallback& callback, |
| 319 DownloadProtectionService* service, | 279 DownloadProtectionService* service, |
| 320 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, | 280 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, |
| 321 SignatureUtil* signature_util) | 281 SignatureUtil* signature_util) |
| 322 : info_(info), | 282 : item_(item), |
| 283 zipped_executable_(false), | |
| 323 callback_(callback), | 284 callback_(callback), |
| 324 service_(service), | 285 service_(service), |
| 325 signature_util_(signature_util), | 286 signature_util_(signature_util), |
| 326 database_manager_(database_manager), | 287 database_manager_(database_manager), |
| 327 pingback_enabled_(service_->enabled()), | 288 pingback_enabled_(service_->enabled()), |
| 328 finished_(false), | 289 finished_(false), |
| 329 type_(ClientDownloadRequest::WIN_EXECUTABLE), | 290 type_(ClientDownloadRequest::WIN_EXECUTABLE), |
| 330 ALLOW_THIS_IN_INITIALIZER_LIST(weakptr_factory_(this)), | 291 ALLOW_THIS_IN_INITIALIZER_LIST(weakptr_factory_(this)), |
| 331 start_time_(base::TimeTicks::Now()) { | 292 start_time_(base::TimeTicks::Now()) { |
| 332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 294 item_->AddObserver(this); | |
| 333 } | 295 } |
| 334 | 296 |
| 335 void Start() { | 297 void Start() { |
| 336 VLOG(2) << "Starting SafeBrowsing download check for: " | 298 VLOG(2) << "Starting SafeBrowsing download check for: " |
| 337 << info_.DebugString(); | 299 << item_->DebugString(true); |
| 338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 339 // TODO(noelutz): implement some cache to make sure we don't issue the same | 301 // TODO(noelutz): implement some cache to make sure we don't issue the same |
| 340 // request over and over again if a user downloads the same binary multiple | 302 // request over and over again if a user downloads the same binary multiple |
| 341 // times. | 303 // times. |
| 342 DownloadCheckResultReason reason = REASON_MAX; | 304 DownloadCheckResultReason reason = REASON_MAX; |
| 343 if (!IsSupportedDownload(info_, &reason, &type_)) { | 305 if (!IsSupportedDownload( |
| 306 *item_, item_->GetTargetFilePath(), &reason, &type_)) { | |
| 344 switch (reason) { | 307 switch (reason) { |
| 345 case REASON_EMPTY_URL_CHAIN: | 308 case REASON_EMPTY_URL_CHAIN: |
| 346 case REASON_INVALID_URL: | 309 case REASON_INVALID_URL: |
| 347 RecordImprovedProtectionStats(reason); | 310 RecordImprovedProtectionStats(reason); |
| 348 PostFinishTask(SAFE); | 311 PostFinishTask(SAFE); |
| 349 return; | 312 return; |
| 350 | 313 |
| 351 case REASON_NOT_BINARY_FILE: | 314 case REASON_NOT_BINARY_FILE: |
| 352 RecordFileExtensionType(info_.target_file); | 315 RecordFileExtensionType(item_->GetTargetFilePath()); |
| 353 RecordImprovedProtectionStats(reason); | 316 RecordImprovedProtectionStats(reason); |
| 354 PostFinishTask(SAFE); | 317 PostFinishTask(SAFE); |
| 355 return; | 318 return; |
| 356 | 319 |
| 357 default: | 320 default: |
| 358 // We only expect the reasons explicitly handled above. | 321 // We only expect the reasons explicitly handled above. |
| 359 NOTREACHED(); | 322 NOTREACHED(); |
| 360 } | 323 } |
| 361 } | 324 } |
| 362 RecordFileExtensionType(info_.target_file); | 325 RecordFileExtensionType(item_->GetTargetFilePath()); |
| 363 | 326 |
| 364 // Compute features from the file contents. Note that we record histograms | 327 // Compute features from the file contents. Note that we record histograms |
| 365 // based on the result, so this runs regardless of whether the pingbacks | 328 // based on the result, so this runs regardless of whether the pingbacks |
| 366 // are enabled. | 329 // are enabled. |
| 367 if (info_.target_file.MatchesExtension(FILE_PATH_LITERAL(".zip"))) { | 330 if (item_->GetTargetFilePath().MatchesExtension( |
| 331 FILE_PATH_LITERAL(".zip"))) { | |
| 368 StartExtractZipFeatures(); | 332 StartExtractZipFeatures(); |
| 369 } else { | 333 } else { |
| 370 DCHECK(!download_protection_util::IsArchiveFile(info_.target_file)); | 334 DCHECK(!download_protection_util::IsArchiveFile( |
| 335 item_->GetTargetFilePath())); | |
| 371 StartExtractSignatureFeatures(); | 336 StartExtractSignatureFeatures(); |
| 372 } | 337 } |
| 373 } | 338 } |
| 374 | 339 |
| 375 // Start a timeout to cancel the request if it takes too long. | 340 // Start a timeout to cancel the request if it takes too long. |
| 376 // This should only be called after we have finished accessing the file. | 341 // This should only be called after we have finished accessing the file. |
| 377 void StartTimeout() { | 342 void StartTimeout() { |
| 378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 379 if (!service_) { | 344 if (!service_) { |
| 380 // Request has already been cancelled. | 345 // Request has already been cancelled. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 402 // might be destroyed before the URLFetcher completes. Cancel the | 367 // might be destroyed before the URLFetcher completes. Cancel the |
| 403 // fetcher so it does not try to invoke OnURLFetchComplete. | 368 // fetcher so it does not try to invoke OnURLFetchComplete. |
| 404 fetcher_.reset(); | 369 fetcher_.reset(); |
| 405 } | 370 } |
| 406 // Note: If there is no fetcher, then some callback is still holding a | 371 // Note: If there is no fetcher, then some callback is still holding a |
| 407 // reference to this object. We'll eventually wind up in some method on | 372 // reference to this object. We'll eventually wind up in some method on |
| 408 // the UI thread that will call FinishRequest() again. If FinishRequest() | 373 // the UI thread that will call FinishRequest() again. If FinishRequest() |
| 409 // is called a second time, it will be a no-op. | 374 // is called a second time, it will be a no-op. |
| 410 } | 375 } |
| 411 | 376 |
| 377 // content::DownloadItem::Observer implementation. | |
| 378 virtual void OnDownloadDestroyed(content::DownloadItem* download) OVERRIDE { | |
| 379 Cancel(); | |
| 380 DCHECK(item_ == NULL); | |
| 381 } | |
| 382 | |
| 412 // From the net::URLFetcherDelegate interface. | 383 // From the net::URLFetcherDelegate interface. |
| 413 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE { | 384 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE { |
| 414 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 385 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 415 DCHECK_EQ(source, fetcher_.get()); | 386 DCHECK_EQ(source, fetcher_.get()); |
| 416 VLOG(2) << "Received a response for URL: " | 387 VLOG(2) << "Received a response for URL: " |
| 417 << info_.download_url_chain.back() << ": success=" | 388 << item_->GetUrlChain().back() << ": success=" |
| 418 << source->GetStatus().is_success() << " response_code=" | 389 << source->GetStatus().is_success() << " response_code=" |
| 419 << source->GetResponseCode(); | 390 << source->GetResponseCode(); |
| 420 DownloadCheckResultReason reason = REASON_SERVER_PING_FAILED; | 391 DownloadCheckResultReason reason = REASON_SERVER_PING_FAILED; |
| 421 DownloadCheckResult result = SAFE; | 392 DownloadCheckResult result = SAFE; |
| 422 if (source->GetStatus().is_success() && | 393 if (source->GetStatus().is_success() && |
| 423 net::HTTP_OK == source->GetResponseCode()) { | 394 net::HTTP_OK == source->GetResponseCode()) { |
| 424 ClientDownloadResponse response; | 395 ClientDownloadResponse response; |
| 425 std::string data; | 396 std::string data; |
| 426 bool got_data = source->GetResponseAsString(&data); | 397 bool got_data = source->GetResponseAsString(&data); |
| 427 DCHECK(got_data); | 398 DCHECK(got_data); |
| 428 if (!response.ParseFromString(data)) { | 399 if (!response.ParseFromString(data)) { |
| 429 reason = REASON_INVALID_RESPONSE_PROTO; | 400 reason = REASON_INVALID_RESPONSE_PROTO; |
| 430 } else if (response.verdict() == ClientDownloadResponse::SAFE) { | 401 } else if (response.verdict() == ClientDownloadResponse::SAFE) { |
| 431 reason = REASON_DOWNLOAD_SAFE; | 402 reason = REASON_DOWNLOAD_SAFE; |
| 432 } else if (service_ && !service_->IsSupportedDownload(info_)) { | 403 } else if (service_ && !service_->IsSupportedDownload( |
| 404 *item_, item_->GetTargetFilePath())) { | |
| 433 // The client of the download protection service assumes that we don't | 405 // The client of the download protection service assumes that we don't |
| 434 // support this download so we cannot return any other verdict than | 406 // support this download so we cannot return any other verdict than |
| 435 // SAFE even if the server says it's dangerous to download this file. | 407 // SAFE even if the server says it's dangerous to download this file. |
| 436 // Note: if service_ is NULL we already cancelled the request and | 408 // Note: if service_ is NULL we already cancelled the request and |
| 437 // returned SAFE. | 409 // returned SAFE. |
| 438 reason = REASON_DOWNLOAD_NOT_SUPPORTED; | 410 reason = REASON_DOWNLOAD_NOT_SUPPORTED; |
| 439 } else if (response.verdict() == ClientDownloadResponse::DANGEROUS) { | 411 } else if (response.verdict() == ClientDownloadResponse::DANGEROUS) { |
| 440 reason = REASON_DOWNLOAD_DANGEROUS; | 412 reason = REASON_DOWNLOAD_DANGEROUS; |
| 441 result = DANGEROUS; | 413 result = DANGEROUS; |
| 442 } else if (response.verdict() == ClientDownloadResponse::UNCOMMON) { | 414 } else if (response.verdict() == ClientDownloadResponse::UNCOMMON) { |
| 443 reason = REASON_DOWNLOAD_UNCOMMON; | 415 reason = REASON_DOWNLOAD_UNCOMMON; |
| 444 result = UNCOMMON; | 416 result = UNCOMMON; |
| 445 } else if (response.verdict() == ClientDownloadResponse::DANGEROUS_HOST) { | 417 } else if (response.verdict() == ClientDownloadResponse::DANGEROUS_HOST) { |
| 446 reason = REASON_DOWNLOAD_DANGEROUS_HOST; | 418 reason = REASON_DOWNLOAD_DANGEROUS_HOST; |
| 447 result = DANGEROUS_HOST; | 419 result = DANGEROUS_HOST; |
| 448 } else { | 420 } else { |
| 449 LOG(DFATAL) << "Unknown download response verdict: " | 421 LOG(DFATAL) << "Unknown download response verdict: " |
| 450 << response.verdict(); | 422 << response.verdict(); |
| 451 reason = REASON_INVALID_RESPONSE_VERDICT; | 423 reason = REASON_INVALID_RESPONSE_VERDICT; |
| 452 } | 424 } |
| 453 } | 425 } |
| 454 // We don't need the fetcher anymore. | 426 // We don't need the fetcher anymore. |
| 455 fetcher_.reset(); | 427 fetcher_.reset(); |
| 456 RecordImprovedProtectionStats(reason); | 428 RecordImprovedProtectionStats(reason); |
| 457 UMA_HISTOGRAM_TIMES("SBClientDownload.DownloadRequestDuration", | 429 UMA_HISTOGRAM_TIMES("SBClientDownload.DownloadRequestDuration", |
| 458 base::TimeTicks::Now() - start_time_); | 430 base::TimeTicks::Now() - start_time_); |
| 459 FinishRequest(result); | 431 FinishRequest(result); |
| 460 } | 432 } |
| 461 | 433 |
| 462 static bool IsSupportedDownload(const DownloadInfo& info, | 434 static bool IsSupportedDownload(const content::DownloadItem& item, |
| 435 const base::FilePath& target_path, | |
| 463 DownloadCheckResultReason* reason, | 436 DownloadCheckResultReason* reason, |
| 464 ClientDownloadRequest::DownloadType* type) { | 437 ClientDownloadRequest::DownloadType* type) { |
| 465 if (info.download_url_chain.empty()) { | 438 if (item.GetUrlChain().empty()) { |
| 466 *reason = REASON_EMPTY_URL_CHAIN; | 439 *reason = REASON_EMPTY_URL_CHAIN; |
| 467 return false; | 440 return false; |
| 468 } | 441 } |
| 469 const GURL& final_url = info.download_url_chain.back(); | 442 const GURL& final_url = item.GetUrlChain().back(); |
| 470 if (!final_url.is_valid() || final_url.is_empty() || | 443 if (!final_url.is_valid() || final_url.is_empty() || |
| 471 !final_url.IsStandard() || final_url.SchemeIsFile()) { | 444 !final_url.IsStandard() || final_url.SchemeIsFile()) { |
| 472 *reason = REASON_INVALID_URL; | 445 *reason = REASON_INVALID_URL; |
| 473 return false; | 446 return false; |
| 474 } | 447 } |
| 475 if (!download_protection_util::IsBinaryFile(info.target_file)) { | 448 if (!download_protection_util::IsBinaryFile(target_path)) { |
| 476 *reason = REASON_NOT_BINARY_FILE; | 449 *reason = REASON_NOT_BINARY_FILE; |
| 477 return false; | 450 return false; |
| 478 } | 451 } |
| 479 *type = GetDownloadType(info.target_file); | 452 *type = GetDownloadType(target_path); |
| 480 return true; | 453 return true; |
| 481 } | 454 } |
| 482 | 455 |
| 483 private: | 456 private: |
| 484 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; | 457 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; |
| 485 friend class base::DeleteHelper<CheckClientDownloadRequest>; | 458 friend class base::DeleteHelper<CheckClientDownloadRequest>; |
| 486 | 459 |
| 487 virtual ~CheckClientDownloadRequest() { | 460 virtual ~CheckClientDownloadRequest() { |
| 488 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 461 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 462 DCHECK(item_ == NULL); | |
| 489 } | 463 } |
| 490 | 464 |
| 491 void OnFileFeatureExtractionDone() { | 465 void OnFileFeatureExtractionDone() { |
| 492 // This can run in any thread, since it just posts more messages. | 466 // This can run in any thread, since it just posts more messages. |
| 493 | 467 |
| 494 // TODO(noelutz): DownloadInfo should also contain the IP address of | 468 // TODO(noelutz): DownloadInfo should also contain the IP address of |
| 495 // every URL in the redirect chain. We also should check whether the | 469 // every URL in the redirect chain. We also should check whether the |
| 496 // download URL is hosted on the internal network. | 470 // download URL is hosted on the internal network. |
| 497 BrowserThread::PostTask( | 471 BrowserThread::PostTask( |
| 498 BrowserThread::IO, | 472 BrowserThread::IO, |
| 499 FROM_HERE, | 473 FROM_HERE, |
| 500 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); | 474 base::Bind(&CheckClientDownloadRequest::CheckWhitelists, this)); |
|
noelutz
2013/03/01 20:12:28
this isn't a weak reference. Does that mean that
mattm
2013/03/01 22:13:20
Oh crap. Good catch, I totally forgot the threadi
| |
| 501 | 475 |
| 502 // We wait until after the file checks finish to start the timeout, as | 476 // We wait until after the file checks finish to start the timeout, as |
| 503 // windows can cause permissions errors if the timeout fired while we were | 477 // windows can cause permissions errors if the timeout fired while we were |
| 504 // checking the file signature and we tried to complete the download. | 478 // checking the file signature and we tried to complete the download. |
| 505 BrowserThread::PostTask( | 479 BrowserThread::PostTask( |
| 506 BrowserThread::UI, | 480 BrowserThread::UI, |
| 507 FROM_HERE, | 481 FROM_HERE, |
| 508 base::Bind(&CheckClientDownloadRequest::StartTimeout, this)); | 482 base::Bind(&CheckClientDownloadRequest::StartTimeout, this)); |
| 509 } | 483 } |
| 510 | 484 |
| 511 void StartExtractSignatureFeatures() { | 485 void StartExtractSignatureFeatures() { |
| 512 // Since we do blocking I/O, offload this to a worker thread. | 486 // Since we do blocking I/O, offload this to a worker thread. |
| 513 // The task does not need to block shutdown. | 487 // The task does not need to block shutdown. |
| 514 BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( | 488 BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( |
| 515 FROM_HERE, | 489 FROM_HERE, |
| 516 base::Bind(&CheckClientDownloadRequest::ExtractSignatureFeatures, | 490 base::Bind(&CheckClientDownloadRequest::ExtractSignatureFeatures, |
| 517 this), | 491 this), |
| 518 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); | 492 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); |
| 519 } | 493 } |
| 520 | 494 |
| 521 void ExtractSignatureFeatures() { | 495 void ExtractSignatureFeatures() { |
| 522 base::TimeTicks start_time = base::TimeTicks::Now(); | 496 base::TimeTicks start_time = base::TimeTicks::Now(); |
|
noelutz
2013/03/01 20:12:28
Could the request get cancelled beween StartExtrac
mattm
2013/03/01 22:13:20
We can't just check item_ unless we also add locki
| |
| 523 signature_util_->CheckSignature(info_.local_file, &signature_info_); | 497 signature_util_->CheckSignature(item_->GetFullPath(), &signature_info_); |
| 524 bool is_signed = (signature_info_.certificate_chain_size() > 0); | 498 bool is_signed = (signature_info_.certificate_chain_size() > 0); |
| 525 if (is_signed) { | 499 if (is_signed) { |
| 526 VLOG(2) << "Downloaded a signed binary: " << info_.local_file.value(); | 500 VLOG(2) << "Downloaded a signed binary: " << item_->GetFullPath().value(); |
| 527 } else { | 501 } else { |
| 528 VLOG(2) << "Downloaded an unsigned binary: " << info_.local_file.value(); | 502 VLOG(2) << "Downloaded an unsigned binary: " |
| 503 << item_->GetFullPath().value(); | |
| 529 } | 504 } |
| 530 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed); | 505 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.SignedBinaryDownload", is_signed); |
| 531 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractSignatureFeaturesTime", | 506 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractSignatureFeaturesTime", |
| 532 base::TimeTicks::Now() - start_time); | 507 base::TimeTicks::Now() - start_time); |
| 533 | 508 |
| 534 OnFileFeatureExtractionDone(); | 509 OnFileFeatureExtractionDone(); |
| 535 } | 510 } |
| 536 | 511 |
| 537 void StartExtractZipFeatures() { | 512 void StartExtractZipFeatures() { |
| 538 zip_analysis_start_time_ = base::TimeTicks::Now(); | 513 zip_analysis_start_time_ = base::TimeTicks::Now(); |
| 539 // We give the zip analyzer a weak pointer to this object. Since the | 514 // We give the zip analyzer a weak pointer to this object. Since the |
| 540 // analyzer is refcounted, it might outlive the request. | 515 // analyzer is refcounted, it might outlive the request. |
| 541 analyzer_ = new SandboxedZipAnalyzer( | 516 analyzer_ = new SandboxedZipAnalyzer( |
| 542 info_.local_file, | 517 item_->GetFullPath(), |
| 543 base::Bind(&CheckClientDownloadRequest::OnZipAnalysisFinished, | 518 base::Bind(&CheckClientDownloadRequest::OnZipAnalysisFinished, |
| 544 weakptr_factory_.GetWeakPtr())); | 519 weakptr_factory_.GetWeakPtr())); |
|
noelutz
2013/03/01 20:12:28
In that case it looks like we're safe.
mattm
2013/03/01 22:13:20
Probably, yeah. I added a test in OnZipAnalysisFi
| |
| 545 analyzer_->Start(); | 520 analyzer_->Start(); |
| 546 } | 521 } |
| 547 | 522 |
| 548 void OnZipAnalysisFinished(const zip_analyzer::Results& results) { | 523 void OnZipAnalysisFinished(const zip_analyzer::Results& results) { |
| 549 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 550 if (results.success) { | 525 if (results.success) { |
| 551 info_.zipped_executable = results.has_executable; | 526 zipped_executable_ = results.has_executable; |
| 552 VLOG(1) << "Zip analysis finished for " << info_.local_file.value() | 527 VLOG(1) << "Zip analysis finished for " << item_->GetFullPath().value() |
| 553 << ", has_executable=" << results.has_executable | 528 << ", has_executable=" << results.has_executable |
| 554 << " has_archive=" << results.has_archive; | 529 << " has_archive=" << results.has_archive; |
| 555 } else { | 530 } else { |
| 556 VLOG(1) << "Zip analysis failed for " << info_.local_file.value(); | 531 VLOG(1) << "Zip analysis failed for " << item_->GetFullPath().value(); |
| 557 } | 532 } |
| 558 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable", | 533 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable", |
| 559 info_.zipped_executable); | 534 zipped_executable_); |
| 560 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasArchiveButNoExecutable", | 535 UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasArchiveButNoExecutable", |
| 561 results.has_archive && !info_.zipped_executable); | 536 results.has_archive && !zipped_executable_); |
| 562 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractZipFeaturesTime", | 537 UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractZipFeaturesTime", |
| 563 base::TimeTicks::Now() - zip_analysis_start_time_); | 538 base::TimeTicks::Now() - zip_analysis_start_time_); |
| 564 | 539 |
| 565 if (!info_.zipped_executable) { | 540 if (!zipped_executable_) { |
| 566 RecordImprovedProtectionStats(REASON_ARCHIVE_WITHOUT_BINARIES); | 541 RecordImprovedProtectionStats(REASON_ARCHIVE_WITHOUT_BINARIES); |
| 567 PostFinishTask(SAFE); | 542 PostFinishTask(SAFE); |
| 568 return; | 543 return; |
| 569 } | 544 } |
| 570 OnFileFeatureExtractionDone(); | 545 OnFileFeatureExtractionDone(); |
| 571 } | 546 } |
| 572 | 547 |
| 573 void CheckWhitelists() { | 548 void CheckWhitelists() { |
| 574 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 549 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 575 DownloadCheckResultReason reason = REASON_MAX; | 550 DownloadCheckResultReason reason = REASON_MAX; |
| 576 if (!database_manager_) { | 551 if (!database_manager_) { |
| 577 reason = REASON_SB_DISABLED; | 552 reason = REASON_SB_DISABLED; |
| 578 } else { | 553 } else { |
| 579 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { | 554 for (size_t i = 0; i < item_->GetUrlChain().size(); ++i) { |
| 580 const GURL& url = info_.download_url_chain[i]; | 555 const GURL& url = item_->GetUrlChain()[i]; |
| 581 if (url.is_valid() && | 556 if (url.is_valid() && |
| 582 database_manager_->MatchDownloadWhitelistUrl(url)) { | 557 database_manager_->MatchDownloadWhitelistUrl(url)) { |
| 583 VLOG(2) << url << " is on the download whitelist."; | 558 VLOG(2) << url << " is on the download whitelist."; |
| 584 reason = REASON_WHITELISTED_URL; | 559 reason = REASON_WHITELISTED_URL; |
| 585 break; | 560 break; |
| 586 } | 561 } |
| 587 } | 562 } |
| 588 if (info_.referrer_url.is_valid() && reason == REASON_MAX && | 563 if (item_->GetReferrerUrl().is_valid() && reason == REASON_MAX && |
| 589 database_manager_->MatchDownloadWhitelistUrl( | 564 database_manager_->MatchDownloadWhitelistUrl( |
| 590 info_.referrer_url)) { | 565 item_->GetReferrerUrl())) { |
| 591 VLOG(2) << "Referrer url " << info_.referrer_url | 566 VLOG(2) << "Referrer url " << item_->GetReferrerUrl() |
| 592 << " is on the download whitelist."; | 567 << " is on the download whitelist."; |
| 593 reason = REASON_WHITELISTED_REFERRER; | 568 reason = REASON_WHITELISTED_REFERRER; |
| 594 } | 569 } |
| 595 if (reason != REASON_MAX || signature_info_.trusted()) { | 570 if (reason != REASON_MAX || signature_info_.trusted()) { |
| 596 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); | 571 UMA_HISTOGRAM_COUNTS("SBClientDownload.SignedOrWhitelistedDownload", 1); |
| 597 } | 572 } |
| 598 } | 573 } |
| 599 if (reason == REASON_MAX && signature_info_.trusted()) { | 574 if (reason == REASON_MAX && signature_info_.trusted()) { |
| 600 for (int i = 0; i < signature_info_.certificate_chain_size(); ++i) { | 575 for (int i = 0; i < signature_info_.certificate_chain_size(); ++i) { |
| 601 if (CertificateChainIsWhitelisted( | 576 if (CertificateChainIsWhitelisted( |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 628 #endif | 603 #endif |
| 629 } | 604 } |
| 630 } | 605 } |
| 631 | 606 |
| 632 void SendRequest() { | 607 void SendRequest() { |
| 633 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 634 | 609 |
| 635 // This is our last chance to check whether the request has been canceled | 610 // This is our last chance to check whether the request has been canceled |
| 636 // before sending it. | 611 // before sending it. |
| 637 if (!service_) { | 612 if (!service_) { |
| 638 RecordImprovedProtectionStats(REASON_REQUEST_CANCELED); | 613 RecordImprovedProtectionStats(REASON_REQUEST_CANCELED); |
|
noelutz
2013/03/01 22:24:09
nice catch.
| |
| 639 FinishRequest(SAFE); | 614 FinishRequest(SAFE); |
| 640 return; | 615 return; |
| 641 } | 616 } |
| 642 | 617 |
| 643 ClientDownloadRequest request; | 618 ClientDownloadRequest request; |
| 644 request.set_url(info_.download_url_chain.back().spec()); | 619 request.set_url(item_->GetUrlChain().back().spec()); |
| 645 request.mutable_digests()->set_sha256(info_.sha256_hash); | 620 request.mutable_digests()->set_sha256(item_->GetHash()); |
| 646 request.set_length(info_.total_bytes); | 621 request.set_length(item_->GetReceivedBytes()); |
| 647 for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { | 622 for (size_t i = 0; i < item_->GetUrlChain().size(); ++i) { |
| 648 ClientDownloadRequest::Resource* resource = request.add_resources(); | 623 ClientDownloadRequest::Resource* resource = request.add_resources(); |
| 649 resource->set_url(info_.download_url_chain[i].spec()); | 624 resource->set_url(item_->GetUrlChain()[i].spec()); |
| 650 if (i == info_.download_url_chain.size() - 1) { | 625 if (i == item_->GetUrlChain().size() - 1) { |
| 651 // The last URL in the chain is the download URL. | 626 // The last URL in the chain is the download URL. |
| 652 resource->set_type(ClientDownloadRequest::DOWNLOAD_URL); | 627 resource->set_type(ClientDownloadRequest::DOWNLOAD_URL); |
| 653 resource->set_referrer(info_.referrer_url.spec()); | 628 resource->set_referrer(item_->GetReferrerUrl().spec()); |
| 654 if (!info_.remote_address.empty()) { | 629 if (!item_->GetRemoteAddress().empty()) { |
| 655 resource->set_remote_ip(info_.remote_address); | 630 resource->set_remote_ip(item_->GetRemoteAddress()); |
| 656 } | 631 } |
| 657 } else { | 632 } else { |
| 658 resource->set_type(ClientDownloadRequest::DOWNLOAD_REDIRECT); | 633 resource->set_type(ClientDownloadRequest::DOWNLOAD_REDIRECT); |
| 659 } | 634 } |
| 660 // TODO(noelutz): fill out the remote IP addresses. | 635 // TODO(noelutz): fill out the remote IP addresses. |
| 661 } | 636 } |
| 662 request.set_user_initiated(info_.user_initiated); | 637 request.set_user_initiated(item_->HasUserGesture()); |
| 663 request.set_file_basename(info_.target_file.BaseName().AsUTF8Unsafe()); | 638 request.set_file_basename( |
| 639 item_->GetTargetFilePath().BaseName().AsUTF8Unsafe()); | |
| 664 request.set_download_type(type_); | 640 request.set_download_type(type_); |
| 665 request.mutable_signature()->CopyFrom(signature_info_); | 641 request.mutable_signature()->CopyFrom(signature_info_); |
| 666 std::string request_data; | 642 std::string request_data; |
| 667 if (!request.SerializeToString(&request_data)) { | 643 if (!request.SerializeToString(&request_data)) { |
| 668 RecordImprovedProtectionStats(REASON_INVALID_REQUEST_PROTO); | 644 RecordImprovedProtectionStats(REASON_INVALID_REQUEST_PROTO); |
| 669 FinishRequest(SAFE); | 645 FinishRequest(SAFE); |
| 670 return; | 646 return; |
| 671 } | 647 } |
| 672 | 648 |
| 673 VLOG(2) << "Sending a request for URL: " | 649 VLOG(2) << "Sending a request for URL: " |
| 674 << info_.download_url_chain.back(); | 650 << item_->GetUrlChain().back(); |
| 675 fetcher_.reset(net::URLFetcher::Create(0 /* ID used for testing */, | 651 fetcher_.reset(net::URLFetcher::Create(0 /* ID used for testing */, |
| 676 GURL(GetDownloadRequestUrl()), | 652 GURL(GetDownloadRequestUrl()), |
| 677 net::URLFetcher::POST, | 653 net::URLFetcher::POST, |
| 678 this)); | 654 this)); |
| 679 fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE); | 655 fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
| 680 fetcher_->SetAutomaticallyRetryOn5xx(false); // Don't retry on error. | 656 fetcher_->SetAutomaticallyRetryOn5xx(false); // Don't retry on error. |
| 681 fetcher_->SetRequestContext(service_->request_context_getter_.get()); | 657 fetcher_->SetRequestContext(service_->request_context_getter_.get()); |
| 682 fetcher_->SetUploadData("application/octet-stream", request_data); | 658 fetcher_->SetUploadData("application/octet-stream", request_data); |
| 683 fetcher_->Start(); | 659 fetcher_->Start(); |
| 684 } | 660 } |
| 685 | 661 |
| 686 void PostFinishTask(DownloadCheckResult result) { | 662 void PostFinishTask(DownloadCheckResult result) { |
| 687 BrowserThread::PostTask( | 663 BrowserThread::PostTask( |
| 688 BrowserThread::UI, | 664 BrowserThread::UI, |
| 689 FROM_HERE, | 665 FROM_HERE, |
| 690 base::Bind(&CheckClientDownloadRequest::FinishRequest, this, result)); | 666 base::Bind(&CheckClientDownloadRequest::FinishRequest, this, result)); |
| 691 } | 667 } |
| 692 | 668 |
| 693 void FinishRequest(DownloadCheckResult result) { | 669 void FinishRequest(DownloadCheckResult result) { |
| 694 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 670 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 695 if (finished_) { | 671 if (finished_) { |
| 696 return; | 672 return; |
| 697 } | 673 } |
| 698 finished_ = true; | 674 finished_ = true; |
| 699 if (service_) { | 675 if (service_) { |
| 700 callback_.Run(result); | 676 callback_.Run(result); |
| 677 item_->RemoveObserver(this); | |
| 678 item_ = NULL; | |
| 701 DownloadProtectionService* service = service_; | 679 DownloadProtectionService* service = service_; |
| 702 service_ = NULL; | 680 service_ = NULL; |
| 703 service->RequestFinished(this); | 681 service->RequestFinished(this); |
| 704 // DownloadProtectionService::RequestFinished will decrement our refcount, | 682 // DownloadProtectionService::RequestFinished will decrement our refcount, |
| 705 // so we may be deleted now. | 683 // so we may be deleted now. |
| 706 } else { | 684 } else { |
| 707 callback_.Run(SAFE); | 685 callback_.Run(SAFE); |
| 708 } | 686 } |
| 709 } | 687 } |
| 710 | 688 |
| 711 void RecordImprovedProtectionStats(DownloadCheckResultReason reason) { | 689 void RecordImprovedProtectionStats(DownloadCheckResultReason reason) { |
| 712 VLOG(2) << "SafeBrowsing download verdict for: " | 690 VLOG(2) << "SafeBrowsing download verdict for: " |
| 713 << info_.DebugString() << " verdict:" << reason; | 691 << item_->DebugString(true) << " verdict:" << reason; |
| 714 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", | 692 UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", |
| 715 reason, | 693 reason, |
| 716 REASON_MAX); | 694 REASON_MAX); |
| 717 } | 695 } |
| 718 | 696 |
| 719 bool CertificateChainIsWhitelisted( | 697 bool CertificateChainIsWhitelisted( |
| 720 const ClientDownloadRequest_CertificateChain& chain) { | 698 const ClientDownloadRequest_CertificateChain& chain) { |
| 721 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 722 if (chain.element_size() < 2) { | 700 if (chain.element_size() < 2) { |
| 723 // We need to have both a signing certificate and its issuer certificate | 701 // We need to have both a signing certificate and its issuer certificate |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 750 << cert->subject().GetDisplayName() | 728 << cert->subject().GetDisplayName() |
| 751 << " issuer=" << issuer->subject().GetDisplayName(); | 729 << " issuer=" << issuer->subject().GetDisplayName(); |
| 752 return true; | 730 return true; |
| 753 } | 731 } |
| 754 } | 732 } |
| 755 cert = issuer; | 733 cert = issuer; |
| 756 } | 734 } |
| 757 return false; | 735 return false; |
| 758 } | 736 } |
| 759 | 737 |
| 760 DownloadInfo info_; | 738 // Will be NULL if the request has been canceled. |
| 739 content::DownloadItem* item_; | |
| 740 bool zipped_executable_; | |
| 761 ClientDownloadRequest_SignatureInfo signature_info_; | 741 ClientDownloadRequest_SignatureInfo signature_info_; |
| 762 CheckDownloadCallback callback_; | 742 CheckDownloadCallback callback_; |
| 763 // Will be NULL if the request has been canceled. | 743 // Will be NULL if the request has been canceled. |
| 764 DownloadProtectionService* service_; | 744 DownloadProtectionService* service_; |
| 765 scoped_refptr<SignatureUtil> signature_util_; | 745 scoped_refptr<SignatureUtil> signature_util_; |
| 766 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; | 746 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; |
| 767 const bool pingback_enabled_; | 747 const bool pingback_enabled_; |
| 768 scoped_ptr<net::URLFetcher> fetcher_; | 748 scoped_ptr<net::URLFetcher> fetcher_; |
| 769 scoped_refptr<SandboxedZipAnalyzer> analyzer_; | 749 scoped_refptr<SandboxedZipAnalyzer> analyzer_; |
| 770 base::TimeTicks zip_analysis_start_time_; | 750 base::TimeTicks zip_analysis_start_time_; |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 800 if (enabled == enabled_) { | 780 if (enabled == enabled_) { |
| 801 return; | 781 return; |
| 802 } | 782 } |
| 803 enabled_ = enabled; | 783 enabled_ = enabled; |
| 804 if (!enabled_) { | 784 if (!enabled_) { |
| 805 CancelPendingRequests(); | 785 CancelPendingRequests(); |
| 806 } | 786 } |
| 807 } | 787 } |
| 808 | 788 |
| 809 void DownloadProtectionService::CheckClientDownload( | 789 void DownloadProtectionService::CheckClientDownload( |
| 810 const DownloadProtectionService::DownloadInfo& info, | 790 content::DownloadItem* item, |
| 811 const CheckDownloadCallback& callback) { | 791 const CheckDownloadCallback& callback) { |
| 812 scoped_refptr<CheckClientDownloadRequest> request( | 792 scoped_refptr<CheckClientDownloadRequest> request( |
| 813 new CheckClientDownloadRequest(info, callback, this, | 793 new CheckClientDownloadRequest(item, callback, this, |
| 814 database_manager_, signature_util_.get())); | 794 database_manager_, signature_util_.get())); |
| 815 download_requests_.insert(request); | 795 download_requests_.insert(request); |
| 816 request->Start(); | 796 request->Start(); |
| 817 } | 797 } |
| 818 | 798 |
| 819 void DownloadProtectionService::CheckDownloadUrl( | 799 void DownloadProtectionService::CheckDownloadUrl( |
| 820 const DownloadProtectionService::DownloadInfo& info, | 800 const content::DownloadItem& item, |
| 821 const CheckDownloadCallback& callback) { | 801 const CheckDownloadCallback& callback) { |
| 822 DCHECK(!info.download_url_chain.empty()); | 802 DCHECK(!item.GetUrlChain().empty()); |
| 823 scoped_refptr<DownloadUrlSBClient> client( | 803 scoped_refptr<DownloadUrlSBClient> client( |
| 824 new DownloadUrlSBClient(info, callback, ui_manager_, database_manager_)); | 804 new DownloadUrlSBClient(item, callback, ui_manager_, database_manager_)); |
| 825 // The client will release itself once it is done. | 805 // The client will release itself once it is done. |
| 826 BrowserThread::PostTask( | 806 BrowserThread::PostTask( |
| 827 BrowserThread::IO, | 807 BrowserThread::IO, |
| 828 FROM_HERE, | 808 FROM_HERE, |
| 829 base::Bind(&DownloadUrlSBClient::StartCheck, client)); | 809 base::Bind(&DownloadUrlSBClient::StartCheck, client)); |
| 830 } | 810 } |
| 831 | 811 |
| 832 bool DownloadProtectionService::IsSupportedDownload( | 812 bool DownloadProtectionService::IsSupportedDownload( |
| 833 const DownloadInfo& info) const { | 813 const content::DownloadItem& item, |
| 814 const base::FilePath& target_path) const { | |
| 834 // Currently, the UI only works on Windows. On Linux and Mac we still | 815 // Currently, the UI only works on Windows. On Linux and Mac we still |
| 835 // want to show the dangerous file type warning if the file is possibly | 816 // want to show the dangerous file type warning if the file is possibly |
| 836 // dangerous which means we have to always return false here. | 817 // dangerous which means we have to always return false here. |
| 837 #if defined(OS_WIN) | 818 #if defined(OS_WIN) |
| 838 DownloadCheckResultReason reason = REASON_MAX; | 819 DownloadCheckResultReason reason = REASON_MAX; |
| 839 ClientDownloadRequest::DownloadType type = | 820 ClientDownloadRequest::DownloadType type = |
| 840 ClientDownloadRequest::WIN_EXECUTABLE; | 821 ClientDownloadRequest::WIN_EXECUTABLE; |
| 841 return (CheckClientDownloadRequest::IsSupportedDownload(info, | 822 return (CheckClientDownloadRequest::IsSupportedDownload(item, target_path, |
| 842 &reason, | 823 &reason, &type) && |
| 843 &type) && | |
| 844 (ClientDownloadRequest::ANDROID_APK == type || | 824 (ClientDownloadRequest::ANDROID_APK == type || |
| 845 ClientDownloadRequest::WIN_EXECUTABLE == type || | 825 ClientDownloadRequest::WIN_EXECUTABLE == type || |
| 846 ClientDownloadRequest::ZIPPED_EXECUTABLE == type)); | 826 ClientDownloadRequest::ZIPPED_EXECUTABLE == type)); |
| 847 #else | 827 #else |
| 848 return false; | 828 return false; |
| 849 #endif | 829 #endif |
| 850 } | 830 } |
| 851 | 831 |
| 852 void DownloadProtectionService::CancelPendingRequests() { | 832 void DownloadProtectionService::CancelPendingRequests() { |
| 853 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 833 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 865 void DownloadProtectionService::RequestFinished( | 845 void DownloadProtectionService::RequestFinished( |
| 866 CheckClientDownloadRequest* request) { | 846 CheckClientDownloadRequest* request) { |
| 867 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 847 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 868 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = | 848 std::set<scoped_refptr<CheckClientDownloadRequest> >::iterator it = |
| 869 download_requests_.find(request); | 849 download_requests_.find(request); |
| 870 DCHECK(it != download_requests_.end()); | 850 DCHECK(it != download_requests_.end()); |
| 871 download_requests_.erase(*it); | 851 download_requests_.erase(*it); |
| 872 } | 852 } |
| 873 | 853 |
| 874 void DownloadProtectionService::ShowDetailsForDownload( | 854 void DownloadProtectionService::ShowDetailsForDownload( |
| 875 const DownloadProtectionService::DownloadInfo& info, | 855 const content::DownloadItem& item, |
| 876 content::PageNavigator* navigator) { | 856 content::PageNavigator* navigator) { |
| 877 navigator->OpenURL( | 857 navigator->OpenURL( |
| 878 content::OpenURLParams(GURL(chrome::kDownloadScanningLearnMoreURL), | 858 content::OpenURLParams(GURL(chrome::kDownloadScanningLearnMoreURL), |
| 879 content::Referrer(), | 859 content::Referrer(), |
| 880 NEW_FOREGROUND_TAB, | 860 NEW_FOREGROUND_TAB, |
| 881 content::PAGE_TRANSITION_LINK, | 861 content::PAGE_TRANSITION_LINK, |
| 882 false)); | 862 false)); |
| 883 } | 863 } |
| 884 | 864 |
| 885 namespace { | 865 namespace { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 962 std::string url = kDownloadRequestUrl; | 942 std::string url = kDownloadRequestUrl; |
| 963 std::string api_key = google_apis::GetAPIKey(); | 943 std::string api_key = google_apis::GetAPIKey(); |
| 964 if (!api_key.empty()) { | 944 if (!api_key.empty()) { |
| 965 base::StringAppendF(&url, "?key=%s", | 945 base::StringAppendF(&url, "?key=%s", |
| 966 net::EscapeQueryParamValue(api_key, true).c_str()); | 946 net::EscapeQueryParamValue(api_key, true).c_str()); |
| 967 } | 947 } |
| 968 return url; | 948 return url; |
| 969 } | 949 } |
| 970 | 950 |
| 971 } // namespace safe_browsing | 951 } // namespace safe_browsing |
| OLD | NEW |