12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/sandboxed_zip_analyzer.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/location.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_utility_messages.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/safe_browsing/zip_analyzer.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/child_process_data.h" 167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "content/public/browser/render_process_host.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/content_switches.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_message_macros.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_platform_file.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread; 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace safe_browsing { 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SandboxedZipAnalyzer::SandboxedZipAnalyzer( 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& zip_file, 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ResultCallback& result_callback) 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : zip_file_name_(zip_file), 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch callback_(result_callback), 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch callback_called_(false) { 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SandboxedZipAnalyzer::Start() { 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Starting the analyzer will block on opening the zip file, so run this 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // on a worker thread. The task does not need to block shutdown. 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SandboxedZipAnalyzer::AnalyzeInSandbox, this), 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) { 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SandboxedZipAnalyzer::~SandboxedZipAnalyzer() { 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If we're using UtilityProcessHost, we may not be destroyed on 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the UI or IO thread. 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SandboxedZipAnalyzer::AnalyzeInSandbox() { 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) zip_file_.Initialize(zip_file_name_, 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::File::FLAG_OPEN | base::File::FLAG_READ); 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!zip_file_.IsValid()) { 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VLOG(1) << "Could not open zip file: " << zip_file_name_.value(); 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!BrowserThread::PostTask( 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::IO, FROM_HERE, 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SandboxedZipAnalyzer::OnAnalyzeZipFileFinished, this, 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) zip_analyzer::Results()))) { 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch BrowserThread::PostTask( 657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch BrowserThread::IO, FROM_HERE, 667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::Bind(&SandboxedZipAnalyzer::StartProcessOnIOThread, this)); 677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // The file will be closed on the IO thread once it has been handed 687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // off to the child process. 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SandboxedZipAnalyzer::OnMessageReceived(const IPC::Message& message) { 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool handled = true; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(SandboxedZipAnalyzer, message) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnUtilityProcessStarted) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_HANDLER( 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished, 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnAnalyzeZipFileFinished) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_END_MESSAGE_MAP() 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return handled; 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SandboxedZipAnalyzer::OnAnalyzeZipFileFinished( 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const zip_analyzer::Results& results) { 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (callback_called_) 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(callback_, results)); 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch callback_called_ = true; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SandboxedZipAnalyzer::StartProcessOnIOThread() { 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) utility_process_host_ = content::UtilityProcessHost::Create( 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, 987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get()) 997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ->AsWeakPtr(); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) utility_process_host_->Send(new ChromeUtilityMsg_StartupPing); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Wait for the startup notification before sending the main IPC to the 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // utility process, so that we can dup the file handle. 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SandboxedZipAnalyzer::OnUtilityProcessStarted() { 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::ProcessHandle utility_process = 1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch content::RenderProcessHost::run_renderer_in_process() ? 1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::GetCurrentProcessHandle() : 1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch utility_process_host_->GetData().handle; 1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (utility_process == base::kNullProcessHandle) { 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(ERROR) << "Child process handle is null"; 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) utility_process_host_->Send( 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection( 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IPC::TakeFileHandleForProcess(zip_file_.Pass(), utility_process))); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace safe_browsing 121