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.
5 #ifndef EXTENSIONS_BROWSER_SANDBOXED_UNPACKER_H_
6 #define EXTENSIONS_BROWSER_SANDBOXED_UNPACKER_H_
10 #include "base/files/file_path.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/ref_counted_delete_on_message_loop.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/time/time.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/utility_process_host_client.h"
17 #include "extensions/browser/crx_file_info.h"
18 #include "extensions/browser/install/crx_install_error.h"
19 #include "extensions/common/manifest.h"
24 class DictionaryValue
;
25 class SequencedTaskRunner
;
29 class UtilityProcessHost
;
36 namespace extensions
{
39 class SandboxedUnpackerClient
40 : public base::RefCountedDeleteOnMessageLoop
<SandboxedUnpackerClient
> {
42 // Initialize the ref-counted base to always delete on the UI thread. Note
43 // the constructor call must also happen on the UI thread.
44 SandboxedUnpackerClient();
46 // temp_dir - A temporary directory containing the results of the extension
47 // unpacking. The client is responsible for deleting this directory.
49 // extension_root - The path to the extension root inside of temp_dir.
51 // original_manifest - The parsed but unmodified version of the manifest,
52 // with no modifications such as localization, etc.
54 // extension - The extension that was unpacked. The client is responsible
55 // for deleting this memory.
57 // install_icon - The icon we will display in the installation UI, if any.
58 virtual void OnUnpackSuccess(const base::FilePath
& temp_dir
,
59 const base::FilePath
& extension_root
,
60 const base::DictionaryValue
* original_manifest
,
61 const Extension
* extension
,
62 const SkBitmap
& install_icon
) = 0;
63 virtual void OnUnpackFailure(const CrxInstallError
& error
) = 0;
66 friend class base::RefCountedDeleteOnMessageLoop
<SandboxedUnpackerClient
>;
67 friend class base::DeleteHelper
<SandboxedUnpackerClient
>;
69 virtual ~SandboxedUnpackerClient() {}
72 // SandboxedUnpacker does work to optionally unpack and then validate/sanitize
73 // an extension, either starting from a crx file or an already unzipped
74 // directory (eg from differential update). This is done in a sandboxed
75 // subprocess to protect the browser process from parsing complex formats like
76 // JPEG or JSON from untrusted sources.
78 // Unpacking an extension using this class makes minor changes to its source,
79 // such as transcoding all images to PNG, parsing all message catalogs
80 // and rewriting the manifest JSON. As such, it should not be used when the
81 // output is not intended to be given back to the author.
84 // Lifetime management:
86 // This class is ref-counted by each call it makes to itself on another thread,
87 // and by UtilityProcessHost.
89 // Additionally, we hold a reference to our own client so that it lives at least
90 // long enough to receive the result of unpacking.
93 // NOTE: This class should only be used on the file thread.
94 class SandboxedUnpacker
: public content::UtilityProcessHostClient
{
96 // Creates a SanboxedUnpacker that will do work to unpack an extension,
97 // passing the |location| and |creation_flags| to Extension::Create. The
98 // |extensions_dir| parameter should specify the directory under which we'll
99 // create a subdirectory to write the unpacked extension contents.
101 Manifest::Location location
,
103 const base::FilePath
& extensions_dir
,
104 const scoped_refptr
<base::SequencedTaskRunner
>& unpacker_io_task_runner
,
105 SandboxedUnpackerClient
* client
);
107 // Start processing the extension, either from a CRX file or already unzipped
108 // in a directory. The client is called with the results. The directory form
109 // requires the id and base64-encoded public key (for insertion into the
110 // 'key' field of the manifest.json file).
111 void StartWithCrx(const CRXFileInfo
& crx_info
);
112 void StartWithDirectory(const std::string
& extension_id
,
113 const std::string
& public_key_base64
,
114 const base::FilePath
& directory
);
117 class ProcessHostClient
;
119 // Enumerate all the ways unpacking can fail. Calls to ReportFailure()
120 // take a failure reason as an argument, and put it in histogram
121 // Extensions.SandboxUnpackFailureReason.
123 // SandboxedUnpacker::CreateTempDirectory()
124 COULD_NOT_GET_TEMP_DIRECTORY
,
125 COULD_NOT_CREATE_TEMP_DIRECTORY
,
127 // SandboxedUnpacker::Start()
128 FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY
,
129 COULD_NOT_GET_SANDBOX_FRIENDLY_PATH
,
131 // SandboxedUnpacker::OnUnpackExtensionSucceeded()
132 COULD_NOT_LOCALIZE_EXTENSION
,
135 // SandboxedUnpacker::OnUnpackExtensionFailed()
136 UNPACKER_CLIENT_FAILED
,
138 // SandboxedUnpacker::OnProcessCrashed()
139 UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL
,
141 // SandboxedUnpacker::ValidateSignature()
142 CRX_FILE_NOT_READABLE
,
144 CRX_MAGIC_NUMBER_INVALID
,
145 CRX_VERSION_NUMBER_INVALID
,
146 CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE
,
148 CRX_ZERO_SIGNATURE_LENGTH
,
149 CRX_PUBLIC_KEY_INVALID
,
150 CRX_SIGNATURE_INVALID
,
151 CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED
,
152 CRX_SIGNATURE_VERIFICATION_FAILED
,
154 // SandboxedUnpacker::RewriteManifestFile()
155 ERROR_SERIALIZING_MANIFEST_JSON
,
156 ERROR_SAVING_MANIFEST_JSON
,
158 // SandboxedUnpacker::RewriteImageFiles()
159 COULD_NOT_READ_IMAGE_DATA_FROM_DISK
,
160 DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST
,
161 INVALID_PATH_FOR_BROWSER_IMAGE
,
162 ERROR_REMOVING_OLD_IMAGE_FILE
,
163 INVALID_PATH_FOR_BITMAP_IMAGE
,
164 ERROR_RE_ENCODING_THEME_IMAGE
,
165 ERROR_SAVING_THEME_IMAGE
,
166 ABORTED_DUE_TO_SHUTDOWN
,
168 // SandboxedUnpacker::RewriteCatalogFiles()
169 COULD_NOT_READ_CATALOG_DATA_FROM_DISK
,
170 INVALID_CATALOG_DATA
,
171 INVALID_PATH_FOR_CATALOG
,
172 ERROR_SERIALIZING_CATALOG
,
173 ERROR_SAVING_CATALOG
,
175 // SandboxedUnpacker::ValidateSignature()
176 CRX_HASH_VERIFICATION_FAILED
,
179 DIRECTORY_MOVE_FAILED
,
180 COULD_NOT_START_UTILITY_PROCESS
,
185 friend class ProcessHostClient
;
186 friend class SandboxedUnpackerTest
;
188 ~SandboxedUnpacker() override
;
190 // Set |temp_dir_| as a temporary directory to unpack the extension in.
191 // Return true on success.
192 virtual bool CreateTempDirectory();
194 // Helper functions to simplify calls to ReportFailure.
195 base::string16
FailureReasonToString16(FailureReason reason
);
196 void FailWithPackageError(FailureReason reason
);
198 // Validates the signature of the extension and extract the key to
199 // |public_key_|. Returns true if the signature validates, false otherwise.
200 bool ValidateSignature(const base::FilePath
& crx_path
,
201 const std::string
& expected_hash
);
203 void StartUnzipOnIOThread(const base::FilePath
& crx_path
);
204 void StartUnpackOnIOThread(const base::FilePath
& directory_path
);
206 // UtilityProcessHostClient
207 bool OnMessageReceived(const IPC::Message
& message
) override
;
208 void OnProcessCrashed(int exit_code
) override
;
210 // IPC message handlers.
211 void OnUnzipToDirSucceeded(const base::FilePath
& directory
);
212 void OnUnzipToDirFailed(const std::string
& error
);
213 void OnUnpackExtensionSucceeded(const base::DictionaryValue
& manifest
);
214 void OnUnpackExtensionFailed(const base::string16
& error_message
);
216 void ReportFailure(FailureReason reason
, const base::string16
& message
);
217 void ReportSuccess(const base::DictionaryValue
& original_manifest
,
218 const SkBitmap
& install_icon
);
220 // Overwrites original manifest with safe result from utility process.
221 // Returns NULL on error. Caller owns the returned object.
222 base::DictionaryValue
* RewriteManifestFile(
223 const base::DictionaryValue
& manifest
);
225 // Overwrites original files with safe results from utility process.
226 // Reports error and returns false if it fails.
227 bool RewriteImageFiles(SkBitmap
* install_icon
);
228 bool RewriteCatalogFiles();
230 // Cleans up temp directory artifacts.
233 // This is a helper class to make it easier to keep track of the lifecycle of
234 // a UtilityProcessHost, including automatic begin and end of batch mode.
235 class UtilityHostWrapper
: public base::RefCountedThreadSafe
<
237 content::BrowserThread::DeleteOnIOThread
> {
239 UtilityHostWrapper();
241 // Start up the utility process if it is not already started, putting it
242 // into batch mode and giving it access to |exposed_dir|. This should only
243 // be called on the IO thread. Returns false if there was an error starting
244 // the utility process or putting it into batch mode.
246 const base::FilePath
& exposed_dir
,
247 const scoped_refptr
<UtilityProcessHostClient
>& client
,
248 const scoped_refptr
<base::SequencedTaskRunner
>& client_task_runner
);
250 // This should only be called on the IO thread.
251 content::UtilityProcessHost
* host() const;
254 friend struct content::BrowserThread::DeleteOnThread
<
255 content::BrowserThread::IO
>;
256 friend class base::DeleteHelper
<UtilityHostWrapper
>;
257 ~UtilityHostWrapper();
259 // Should only be used on the IO thread.
260 base::WeakPtr
<content::UtilityProcessHost
> utility_host_
;
262 DISALLOW_COPY_AND_ASSIGN(UtilityHostWrapper
);
265 // If we unpacked a crx file, we hold on to the path for use in various
267 base::FilePath crx_path_for_histograms_
;
270 scoped_refptr
<SandboxedUnpackerClient
> client_
;
272 // The Extensions directory inside the profile.
273 base::FilePath extensions_dir_
;
275 // A temporary directory to use for unpacking.
276 base::ScopedTempDir temp_dir_
;
278 // The root directory of the unpacked extension. This is a child of temp_dir_.
279 base::FilePath extension_root_
;
281 // Represents the extension we're unpacking.
282 scoped_refptr
<Extension
> extension_
;
284 // Whether we've received a response from the utility process yet.
287 // The public key that was extracted from the CRX header.
288 std::string public_key_
;
290 // The extension's ID. This will be calculated from the public key in the crx
292 std::string extension_id_
;
294 // If we unpacked a .crx file, the time at which unpacking started. Used to
295 // compute the time unpacking takes.
296 base::TimeTicks crx_unpack_start_time_
;
298 // Location to use for the unpacked extension.
299 Manifest::Location location_
;
301 // Creation flags to use for the extension. These flags will be used
302 // when calling Extenion::Create() by the crx installer.
305 // Sequenced task runner where file I/O operations will be performed at.
306 scoped_refptr
<base::SequencedTaskRunner
> unpacker_io_task_runner_
;
308 // Used for sending tasks to the utility process.
309 scoped_refptr
<UtilityHostWrapper
> utility_wrapper_
;
311 DISALLOW_COPY_AND_ASSIGN(SandboxedUnpacker
);
314 } // namespace extensions
316 #endif // EXTENSIONS_BROWSER_SANDBOXED_UNPACKER_H_