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