12bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian// Use of this source code is governed by a BSD-style license that can be 32bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian// found in the LICENSE file. 42bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 52bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "chrome/browser/safe_browsing/sandboxed_zip_analyzer.h" 62bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 72bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "base/bind.h" 82bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "base/command_line.h" 92bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "base/location.h" 102bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "base/logging.h" 112bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "base/threading/sequenced_worker_pool.h" 122bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "chrome/common/chrome_utility_messages.h" 132bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "chrome/common/safe_browsing/zip_analyzer.h" 142bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "content/public/browser/browser_thread.h" 152bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "content/public/browser/child_process_data.h" 162bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "content/public/browser/render_process_host.h" 172bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "content/public/common/content_switches.h" 182bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "ipc/ipc_message_macros.h" 192bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian#include "ipc/ipc_platform_file.h" 202bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 212bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanianusing content::BrowserThread; 222bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 232bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramaniannamespace safe_browsing { 242bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 252bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh VenkatasubramanianSandboxedZipAnalyzer::SandboxedZipAnalyzer( 262bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian const base::FilePath& zip_file, 272bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian const ResultCallback& result_callback) 282bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian : zip_file_name_(zip_file), 292bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian callback_(result_callback), 302bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian callback_called_(false) { 312bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian} 322bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 332bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanianvoid SandboxedZipAnalyzer::Start() { 342bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 352bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian // Starting the analyzer will block on opening the zip file, so run this 362bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian // on a worker thread. The task does not need to block shutdown. 372bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( 382bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian FROM_HERE, 392bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian base::Bind(&SandboxedZipAnalyzer::AnalyzeInSandbox, this), 402bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) { 412bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian NOTREACHED(); 422bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian } 432bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian} 442bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 452bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh VenkatasubramanianSandboxedZipAnalyzer::~SandboxedZipAnalyzer() { 462bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian // If we're using UtilityProcessHost, we may not be destroyed on 472bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian // the UI or IO thread. 482bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian} 492bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 502bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanianvoid SandboxedZipAnalyzer::AnalyzeInSandbox() { 512bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian zip_file_.Initialize(zip_file_name_, 522bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian base::File::FLAG_OPEN | base::File::FLAG_READ); 532bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian if (!zip_file_.IsValid()) { 542bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian VLOG(1) << "Could not open zip file: " << zip_file_name_.value(); 552bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian if (!BrowserThread::PostTask( 562bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian BrowserThread::IO, FROM_HERE, 572bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian base::Bind(&SandboxedZipAnalyzer::OnAnalyzeZipFileFinished, this, 582bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian zip_analyzer::Results()))) { 592bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian NOTREACHED(); 602bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian } 612bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian return; 622bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian } 632bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 642bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian BrowserThread::PostTask( 652bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian BrowserThread::IO, FROM_HERE, 662bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian base::Bind(&SandboxedZipAnalyzer::StartProcessOnIOThread, this)); 672bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian // The file will be closed on the IO thread once it has been handed 682bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian // off to the child process. 692bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian} 702bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 712bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanianbool SandboxedZipAnalyzer::OnMessageReceived(const IPC::Message& message) { 722bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian bool handled = true; 732bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian IPC_BEGIN_MESSAGE_MAP(SandboxedZipAnalyzer, message) 742bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, 752bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian OnUtilityProcessStarted) 762bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian IPC_MESSAGE_HANDLER( 772bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished, 782bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian OnAnalyzeZipFileFinished) 792bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian IPC_MESSAGE_UNHANDLED(handled = false) 802bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian IPC_END_MESSAGE_MAP() 812bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian return handled; 822bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian} 832bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 842bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanianvoid SandboxedZipAnalyzer::OnAnalyzeZipFileFinished( 852bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian const zip_analyzer::Results& results) { 862bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 872bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian if (callback_called_) 882bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian return; 892bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 902bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian base::Bind(callback_, results)); 912bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian callback_called_ = true; 922bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian} 932bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian 942bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanianvoid SandboxedZipAnalyzer::StartProcessOnIOThread() { 952bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 962bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian utility_process_host_ = content::UtilityProcessHost::Create( 972bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian this, 982bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get()) 992bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian ->AsWeakPtr(); 1002bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian utility_process_host_->Send(new ChromeUtilityMsg_StartupPing); 1012bd8b54017b5320bc0c1df9bf86f4cdc9f8db242Vignesh Venkatasubramanian // 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