Home | History | Annotate | Download | only in safe_browsing
      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 
     21 using content::BrowserThread;
     22 
     23 namespace safe_browsing {
     24 
     25 SandboxedZipAnalyzer::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 
     33 void 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 
     45 SandboxedZipAnalyzer::~SandboxedZipAnalyzer() {
     46   // If we're using UtilityProcessHost, we may not be destroyed on
     47   // the UI or IO thread.
     48 }
     49 
     50 void 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 
     71 bool 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 
     84 void 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 
     94 void 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 
    105 void 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