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