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 3// found in the LICENSE file. 4 5#include "chrome/browser/safe_browsing/sandboxed_zip_analyzer.h" 6 7#include "base/bind.h" 8#include "base/command_line.h" 9#include "base/location.h" 10#include "base/logging.h" 11#include "base/threading/sequenced_worker_pool.h" 12#include "chrome/common/chrome_utility_messages.h" 13#include "chrome/common/safe_browsing/zip_analyzer.h" 14#include "content/public/browser/browser_thread.h" 15#include "content/public/browser/child_process_data.h" 16#include "content/public/browser/render_process_host.h" 17#include "content/public/common/content_switches.h" 18#include "ipc/ipc_message_macros.h" 19#include "ipc/ipc_platform_file.h" 20 21using content::BrowserThread; 22 23namespace safe_browsing { 24 25SandboxedZipAnalyzer::SandboxedZipAnalyzer( 26 const base::FilePath& zip_file, 27 const ResultCallback& result_callback) 28 : zip_file_name_(zip_file), 29 callback_(result_callback), 30 callback_called_(false) { 31} 32 33void SandboxedZipAnalyzer::Start() { 34 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 35 // Starting the analyzer will block on opening the zip file, so run this 36 // on a worker thread. The task does not need to block shutdown. 37 if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( 38 FROM_HERE, 39 base::Bind(&SandboxedZipAnalyzer::AnalyzeInSandbox, this), 40 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) { 41 NOTREACHED(); 42 } 43} 44 45SandboxedZipAnalyzer::~SandboxedZipAnalyzer() { 46 // If we're using UtilityProcessHost, we may not be destroyed on 47 // the UI or IO thread. 48} 49 50void SandboxedZipAnalyzer::AnalyzeInSandbox() { 51 zip_file_.Initialize(zip_file_name_, 52 base::File::FLAG_OPEN | base::File::FLAG_READ); 53 if (!zip_file_.IsValid()) { 54 VLOG(1) << "Could not open zip file: " << zip_file_name_.value(); 55 if (!BrowserThread::PostTask( 56 BrowserThread::IO, FROM_HERE, 57 base::Bind(&SandboxedZipAnalyzer::OnAnalyzeZipFileFinished, this, 58 zip_analyzer::Results()))) { 59 NOTREACHED(); 60 } 61 return; 62 } 63 64 BrowserThread::PostTask( 65 BrowserThread::IO, FROM_HERE, 66 base::Bind(&SandboxedZipAnalyzer::StartProcessOnIOThread, this)); 67 // The file will be closed on the IO thread once it has been handed 68 // off to the child process. 69} 70 71bool SandboxedZipAnalyzer::OnMessageReceived(const IPC::Message& message) { 72 bool handled = true; 73 IPC_BEGIN_MESSAGE_MAP(SandboxedZipAnalyzer, message) 74 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, 75 OnUtilityProcessStarted) 76 IPC_MESSAGE_HANDLER( 77 ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished, 78 OnAnalyzeZipFileFinished) 79 IPC_MESSAGE_UNHANDLED(handled = false) 80 IPC_END_MESSAGE_MAP() 81 return handled; 82} 83 84void SandboxedZipAnalyzer::OnAnalyzeZipFileFinished( 85 const zip_analyzer::Results& results) { 86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 87 if (callback_called_) 88 return; 89 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 90 base::Bind(callback_, results)); 91 callback_called_ = true; 92} 93 94void SandboxedZipAnalyzer::StartProcessOnIOThread() { 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 96 utility_process_host_ = content::UtilityProcessHost::Create( 97 this, 98 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get()) 99 ->AsWeakPtr(); 100 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing); 101 // Wait for the startup notification before sending the main IPC to the 102 // utility process, so that we can dup the file handle. 103} 104 105void SandboxedZipAnalyzer::OnUtilityProcessStarted() { 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 107 base::ProcessHandle utility_process = 108 content::RenderProcessHost::run_renderer_in_process() ? 109 base::GetCurrentProcessHandle() : 110 utility_process_host_->GetData().handle; 111 112 if (utility_process == base::kNullProcessHandle) { 113 DLOG(ERROR) << "Child process handle is null"; 114 } 115 utility_process_host_->Send( 116 new ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection( 117 IPC::TakeFileHandleForProcess(zip_file_.Pass(), utility_process))); 118} 119 120} // namespace safe_browsing 121