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