blob: f2d4902273548ff6961b349c55457e77ddaf5542 [file] [log] [blame]
[email protected]f5bf1842012-02-15 02:52:261// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]af1277b2009-07-28 00:47:532// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
asargentc4fdad22015-08-28 22:44:395#ifndef EXTENSIONS_BROWSER_SANDBOXED_UNPACKER_H_
6#define EXTENSIONS_BROWSER_SANDBOXED_UNPACKER_H_
[email protected]af1277b2009-07-28 00:47:537
waffles5918d5f2017-05-23 01:45:288#include <memory>
[email protected]af1277b2009-07-28 00:47:539#include <string>
10
[email protected]57999812013-02-24 05:40:5211#include "base/files/file_path.h"
[email protected]ea1a3f62012-11-16 20:34:2312#include "base/files/scoped_temp_dir.h"
avic9cec102015-12-23 00:39:2613#include "base/macros.h"
fdoray33d98b62016-12-23 14:02:5214#include "base/memory/ref_counted_delete_on_sequence.h"
Oleg Davydov795d1b602020-01-02 09:44:2715#include "base/memory/scoped_refptr.h"
asargentc4fdad22015-08-28 22:44:3916#include "base/memory/weak_ptr.h"
Karandeep Bhatiaa8930652017-10-11 17:41:1217#include "base/optional.h"
Jay Civellibed6dcd2018-01-25 00:08:2418#include "base/strings/string_piece.h"
[email protected]41a17c52013-06-28 00:27:5319#include "base/time/time.h"
Oksana Zhuravlova23783372018-04-24 18:47:4920#include "base/values.h"
ginkage553af3202015-02-04 12:39:0921#include "extensions/browser/crx_file_info.h"
Jay Civelliea8f3df2018-01-24 05:17:3222#include "extensions/browser/image_sanitizer.h"
ginkage47e603e2015-02-27 08:42:4123#include "extensions/browser/install/crx_install_error.h"
Jay Civelli6d0e68e2018-01-24 16:42:5324#include "extensions/browser/json_file_sanitizer.h"
[email protected]d42c11152013-08-22 19:36:3225#include "extensions/common/manifest.h"
Miyoung Shin364c6572019-09-11 09:02:1926#include "mojo/public/cpp/bindings/remote.h"
Ken Rockotdc32df892019-11-01 06:32:1027#include "services/data_decoder/public/cpp/data_decoder.h"
Ken Rockot19db6382018-02-10 01:41:0228#include "services/data_decoder/public/mojom/json_parser.mojom.h"
[email protected]af1277b2009-07-28 00:47:5329
[email protected]3d8eb9f2013-07-11 23:37:2530class SkBitmap;
31
[email protected]f3a1c642011-07-12 19:15:0332namespace base {
[email protected]7f8f24f2012-11-15 19:40:1433class SequencedTaskRunner;
[email protected]f3a1c642011-07-12 19:15:0334}
35
Joshua Pawlickifd01b7c2019-01-17 16:18:3436namespace crx_file {
37enum class VerifierFormat;
38}
39
[email protected]f5ac2742012-07-02 17:50:5840namespace extensions {
[email protected]1d5e58b2013-01-31 08:41:4041class Extension;
Minh X. Nguyen8803f4e2018-05-25 01:03:1042enum class SandboxedUnpackerFailureReason;
[email protected]f5ac2742012-07-02 17:50:5843
Karan Bhatia23e67edd2018-06-26 20:43:0144namespace declarative_net_request {
Karan Bhatia81348352019-03-25 22:50:0145struct IndexAndPersistJSONRulesetResult;
Karan Bhatia23e67edd2018-06-26 20:43:0146}
47
[email protected]f5ac2742012-07-02 17:50:5848class SandboxedUnpackerClient
fdoray33d98b62016-12-23 14:02:5249 : public base::RefCountedDeleteOnSequence<SandboxedUnpackerClient> {
[email protected]af1277b2009-07-28 00:47:5350 public:
tapted1e394abd2015-04-15 23:22:2551 // Initialize the ref-counted base to always delete on the UI thread. Note
52 // the constructor call must also happen on the UI thread.
53 SandboxedUnpackerClient();
54
Oleg Davydov795d1b602020-01-02 09:44:2755 // Determines whether |extension| requires computing and storing
56 // computed_hashes.json and returns the result through |callback|.
57 // Currently we do this only for force-installed extensions outside of Chrome
58 // Web Store, and that is reflected in method's name.
59 virtual void ShouldComputeHashesForOffWebstoreExtension(
60 scoped_refptr<const Extension> extension,
61 base::OnceCallback<void(bool)> callback);
62
[email protected]9428edc2009-11-18 18:02:4763 // temp_dir - A temporary directory containing the results of the extension
[email protected]af1277b2009-07-28 00:47:5364 // unpacking. The client is responsible for deleting this directory.
65 //
66 // extension_root - The path to the extension root inside of temp_dir.
67 //
[email protected]ad93c6ba2011-05-26 04:48:3368 // original_manifest - The parsed but unmodified version of the manifest,
69 // with no modifications such as localization, etc.
70 //
[email protected]af1277b2009-07-28 00:47:5371 // extension - The extension that was unpacked. The client is responsible
72 // for deleting this memory.
[email protected]3d8eb9f2013-07-11 23:37:2573 //
74 // install_icon - The icon we will display in the installation UI, if any.
Karandeep Bhatiaa8930652017-10-11 17:41:1275 //
76 // dnr_ruleset_checksum - Checksum for the indexed ruleset corresponding to
77 // the Declarative Net Request API. Optional since it's only valid for
78 // extensions which provide a declarative ruleset.
Karan Bhatiaf4859e3692018-06-21 05:57:4279 //
80 // Note: OnUnpackSuccess/Failure may be called either synchronously or
81 // asynchronously from SandboxedUnpacker::StartWithCrx/Directory.
lazyboy6cff6b182017-03-30 18:43:4982 virtual void OnUnpackSuccess(
83 const base::FilePath& temp_dir,
84 const base::FilePath& extension_root,
85 std::unique_ptr<base::DictionaryValue> original_manifest,
86 const Extension* extension,
Karandeep Bhatiaa8930652017-10-11 17:41:1287 const SkBitmap& install_icon,
88 const base::Optional<int>& dnr_ruleset_checksum) = 0;
ginkage47e603e2015-02-27 08:42:4189 virtual void OnUnpackFailure(const CrxInstallError& error) = 0;
[email protected]8de85a62009-11-06 08:32:1790
91 protected:
fdoray33d98b62016-12-23 14:02:5292 friend class base::RefCountedDeleteOnSequence<SandboxedUnpackerClient>;
tapted1e394abd2015-04-15 23:22:2593 friend class base::DeleteHelper<SandboxedUnpackerClient>;
[email protected]8de85a62009-11-06 08:32:1794
noelc8702c42017-03-16 08:51:1995 virtual ~SandboxedUnpackerClient() = default;
[email protected]af1277b2009-07-28 00:47:5396};
97
asargentc4fdad22015-08-28 22:44:3998// SandboxedUnpacker does work to optionally unpack and then validate/sanitize
noelc8702c42017-03-16 08:51:1999// an extension, either starting from a crx file, or else an already unzipped
Jay Civellib6f2cc9c2018-03-10 01:13:57100// directory (eg., from a differential update). The parsing of complex data
101// formats like JPEG or JSON is performed in specific, sandboxed services.
[email protected]af1277b2009-07-28 00:47:53102//
noelc8702c42017-03-16 08:51:19103// Unpacking an extension using this class makes changes to its source, such as
104// transcoding all images to PNG, parsing all message catalogs, and rewriting
105// the manifest JSON. As such, it should not be used when the output is not
106// intended to be given back to the author.
[email protected]7577a5c52009-07-30 06:21:58107//
108// Lifetime management:
109//
Jay Civellib6f2cc9c2018-03-10 01:13:57110// This class is ref-counted by each call it makes to itself on another thread.
[email protected]7577a5c52009-07-30 06:21:58111//
noelc8702c42017-03-16 08:51:19112// Additionally, we hold a reference to our own client so that the client lives
[email protected]7577a5c52009-07-30 06:21:58113// long enough to receive the result of unpacking.
114//
noelc8702c42017-03-16 08:51:19115// NOTE: This class should only be used on the FILE thread.
[email protected]7577a5c52009-07-30 06:21:58116//
noelc8702c42017-03-16 08:51:19117class SandboxedUnpacker : public base::RefCountedThreadSafe<SandboxedUnpacker> {
[email protected]af1277b2009-07-28 00:47:53118 public:
Joshua Pawlicki1ca9a282019-04-18 13:56:48119 // Overrides the required verifier format for testing purposes. Only one
120 // ScopedVerifierFormatOverrideForTest may exist at a time.
121 class ScopedVerifierFormatOverrideForTest {
122 public:
123 explicit ScopedVerifierFormatOverrideForTest(
124 crx_file::VerifierFormat format);
125 ~ScopedVerifierFormatOverrideForTest();
126 };
127
Minh X. Nguyen8803f4e2018-05-25 01:03:10128 // Creates a SandboxedUnpacker that will do work to unpack an extension,
asargentc4fdad22015-08-28 22:44:39129 // passing the |location| and |creation_flags| to Extension::Create. The
130 // |extensions_dir| parameter should specify the directory under which we'll
131 // create a subdirectory to write the unpacked extension contents.
Devlin Croninb7a97172017-08-10 01:25:32132 // Note: Because this requires disk I/O, the task runner passed should use
133 // TaskShutdownBehavior::SKIP_ON_SHUTDOWN to ensure that either the task is
134 // fully run (if initiated before shutdown) or not run at all (if shutdown is
135 // initiated first). See crbug.com/235525.
136 // TODO(devlin): We should probably just have SandboxedUnpacker use the common
137 // ExtensionFileTaskRunner, and not pass in a separate one.
138 // TODO(devlin): SKIP_ON_SHUTDOWN is also not quite sufficient for this. We
139 // should probably instead be using base::ImportantFileWriter or similar.
dcheng605ef8d2014-08-28 18:29:44140 SandboxedUnpacker(
dcheng605ef8d2014-08-28 18:29:44141 Manifest::Location location,
142 int creation_flags,
143 const base::FilePath& extensions_dir,
144 const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner,
145 SandboxedUnpackerClient* client);
[email protected]af1277b2009-07-28 00:47:53146
asargentc4fdad22015-08-28 22:44:39147 // Start processing the extension, either from a CRX file or already unzipped
148 // in a directory. The client is called with the results. The directory form
149 // requires the id and base64-encoded public key (for insertion into the
150 // 'key' field of the manifest.json file).
151 void StartWithCrx(const CRXFileInfo& crx_info);
152 void StartWithDirectory(const std::string& extension_id,
153 const std::string& public_key_base64,
154 const base::FilePath& directory);
[email protected]af1277b2009-07-28 00:47:53155
156 private:
noelc8702c42017-03-16 08:51:19157 friend class base::RefCountedThreadSafe<SandboxedUnpacker>;
[email protected]10735aa2011-01-31 14:41:18158
[email protected]f5ac2742012-07-02 17:50:58159 friend class SandboxedUnpackerTest;
[email protected]af1277b2009-07-28 00:47:53160
noelc8702c42017-03-16 08:51:19161 ~SandboxedUnpacker();
[email protected]e60b6492009-11-07 01:06:28162
noelc8702c42017-03-16 08:51:19163 // Create |temp_dir_| used to unzip or unpack the extension in.
164 bool CreateTempDirectory();
[email protected]650852e2011-01-19 13:26:02165
noelc8702c42017-03-16 08:51:19166 // Helper functions to simplify calling ReportFailure.
Minh X. Nguyen8803f4e2018-05-25 01:03:10167 base::string16 FailureReasonToString16(
168 const SandboxedUnpackerFailureReason reason);
169 void FailWithPackageError(const SandboxedUnpackerFailureReason reason);
ginkage553af3202015-02-04 12:39:09170
[email protected]af1277b2009-07-28 00:47:53171 // Validates the signature of the extension and extract the key to
noelc8702c42017-03-16 08:51:19172 // |public_key_|. True if the signature validates, false otherwise.
asargentc4fdad22015-08-28 22:44:39173 bool ValidateSignature(const base::FilePath& crx_path,
Joshua Pawlickifd01b7c2019-01-17 16:18:34174 const std::string& expected_hash,
175 const crx_file::VerifierFormat required_format);
[email protected]af1277b2009-07-28 00:47:53176
noelc8702c42017-03-16 08:51:19177 // Unzips the extension into directory.
Jay Civellib6f2cc9c2018-03-10 01:13:57178 void Unzip(const base::FilePath& crx_path,
179 const base::FilePath& unzipped_dir);
180 void UnzipDone(const base::FilePath& zip_file,
181 const base::FilePath& unzip_dir,
182 const std::string& error);
[email protected]373c1062011-06-09 21:11:51183
noelc8702c42017-03-16 08:51:19184 // Unpacks the extension in directory and returns the manifest.
185 void Unpack(const base::FilePath& directory);
Oksana Zhuravlova23783372018-04-24 18:47:49186 void ReadManifestDone(base::Optional<base::Value> manifest,
Jay Civelli26a85642018-01-26 21:29:39187 const base::Optional<std::string>& error);
Oleg Davydova4ffe6a2020-01-07 10:34:48188 void UnpackExtensionSucceeded(base::Value manifest);
noelc8702c42017-03-16 08:51:19189
Karan Bhatiaf4859e3692018-06-21 05:57:42190 // Helper which calls ReportFailure.
191 void ReportUnpackExtensionFailed(base::StringPiece error);
Jay Civellibed6dcd2018-01-25 00:08:24192
Oleg Davydova4ffe6a2020-01-07 10:34:48193 void ImageSanitizationDone(ImageSanitizer::Status status,
Jay Civelliea8f3df2018-01-24 05:17:32194 const base::FilePath& path);
195 void ImageSanitizerDecodedImage(const base::FilePath& path, SkBitmap image);
196
Oleg Davydova4ffe6a2020-01-07 10:34:48197 void ReadMessageCatalogs();
Jay Civelli6d0e68e2018-01-24 16:42:53198
199 void SanitizeMessageCatalogs(
Jay Civelli6d0e68e2018-01-24 16:42:53200 const std::set<base::FilePath>& message_catalog_paths);
201
Oleg Davydova4ffe6a2020-01-07 10:34:48202 void MessageCatalogsSanitized(JsonFileSanitizer::Status status,
Jay Civelli6d0e68e2018-01-24 16:42:53203 const std::string& error_msg);
204
noelc8702c42017-03-16 08:51:19205 // Reports unpack success or failure, or unzip failure.
Oleg Davydova4ffe6a2020-01-07 10:34:48206 void ReportSuccess();
Minh X. Nguyen8803f4e2018-05-25 01:03:10207
208 // Puts a sanboxed unpacker failure in histogram
209 // Extensions.SandboxUnpackFailureReason.
210 void ReportFailure(const SandboxedUnpackerFailureReason reason,
211 const base::string16& error);
[email protected]af1277b2009-07-28 00:47:53212
[email protected]9428edc2009-11-18 18:02:47213 // Overwrites original manifest with safe result from utility process.
Oleg Davydova4ffe6a2020-01-07 10:34:48214 // Returns nullopt on error.
215 base::Optional<base::Value> RewriteManifestFile(const base::Value& manifest);
[email protected]9428edc2009-11-18 18:02:47216
[email protected]7f8f24f2012-11-15 19:40:14217 // Cleans up temp directory artifacts.
218 void Cleanup();
219
Karan Bhatia23e67edd2018-06-26 20:43:01220 // If a Declarative Net Request JSON ruleset is present, parses the JSON
221 // ruleset for the Declarative Net Request API and persists the indexed
222 // ruleset.
Oleg Davydova4ffe6a2020-01-07 10:34:48223 void IndexAndPersistJSONRulesetIfNeeded();
Karan Bhatia23e67edd2018-06-26 20:43:01224
225 void OnJSONRulesetIndexed(
Karan Bhatia81348352019-03-25 22:50:01226 declarative_net_request::IndexAndPersistJSONRulesetResult result);
Karan Bhatia71f6a622017-10-02 19:39:10227
Oleg Davydov795d1b602020-01-02 09:44:27228 // Computed hashes: if requested (via ShouldComputeHashes callback in
229 // SandbloxedUnpackerClient), calculate hashes of all extensions' resources
230 // and writes them in _metadata/computed_hashes.json. This is used by content
231 // verification system for extensions outside of Chrome Web Store.
Oleg Davydova4ffe6a2020-01-07 10:34:48232 void CheckComputeHashes();
Oleg Davydov795d1b602020-01-02 09:44:27233
Oleg Davydova4ffe6a2020-01-07 10:34:48234 void MaybeComputeHashes(bool should_compute_hashes);
Oleg Davydov795d1b602020-01-02 09:44:27235
Jay Civelli26a85642018-01-26 21:29:39236 // Returns a JsonParser that can be used on the |unpacker_io_task_runner|.
237 data_decoder::mojom::JsonParser* GetJsonParserPtr();
238
239 // Parses the JSON file at |path| and invokes |callback| when done. |callback|
240 // is called with a null parameter if parsing failed.
241 // This must be called from the |unpacker_io_task_runner_|.
242 void ParseJsonFile(const base::FilePath& path,
243 data_decoder::mojom::JsonParser::ParseCallback callback);
244
noelc8702c42017-03-16 08:51:19245 // If we unpacked a CRX file, we hold on to the path name for use
246 // in various histograms.
asargentc4fdad22015-08-28 22:44:39247 base::FilePath crx_path_for_histograms_;
ginkage553af3202015-02-04 12:39:09248
noelc8702c42017-03-16 08:51:19249 // Our unpacker client.
[email protected]f5ac2742012-07-02 17:50:58250 scoped_refptr<SandboxedUnpackerClient> client_;
[email protected]5c8516202010-03-18 21:43:34251
[email protected]171ab92d2012-10-19 01:16:34252 // The Extensions directory inside the profile.
[email protected]650b2d52013-02-10 03:41:45253 base::FilePath extensions_dir_;
[email protected]171ab92d2012-10-19 01:16:34254
noelc8702c42017-03-16 08:51:19255 // Temporary directory to use for unpacking.
[email protected]ea1a3f62012-11-16 20:34:23256 base::ScopedTempDir temp_dir_;
[email protected]5c8516202010-03-18 21:43:34257
noelc8702c42017-03-16 08:51:19258 // Root directory of the unpacked extension (a child of temp_dir_).
[email protected]650b2d52013-02-10 03:41:45259 base::FilePath extension_root_;
[email protected]5c8516202010-03-18 21:43:34260
Oleg Davydova4ffe6a2020-01-07 10:34:48261 // Parsed original manifest of the extension. Set after unpacking the
262 // extension and working with its manifest, so after UnpackExtensionSucceeded
263 // is called.
264 base::Optional<base::Value> manifest_;
265
266 // Checksum for the indexed ruleset, see more in
267 // SandboxedUnpackerClient::OnUnpackSuccess description.
268 base::Optional<int> dnr_ruleset_checksum_;
269
[email protected]5c8516202010-03-18 21:43:34270 // Represents the extension we're unpacking.
[email protected]b3fe68d2012-07-16 19:14:39271 scoped_refptr<Extension> extension_;
[email protected]5c8516202010-03-18 21:43:34272
[email protected]5c8516202010-03-18 21:43:34273 // The public key that was extracted from the CRX header.
[email protected]af1277b2009-07-28 00:47:53274 std::string public_key_;
[email protected]264fda92011-04-20 15:03:55275
noelc8702c42017-03-16 08:51:19276 // The extension's ID. This will be calculated from the public key
277 // in the CRX header.
[email protected]f5bf1842012-02-15 02:52:26278 std::string extension_id_;
279
noelc8702c42017-03-16 08:51:19280 // If we unpacked a CRX file, the time at which unpacking started.
281 // Used to compute the time unpacking takes.
asargentc4fdad22015-08-28 22:44:39282 base::TimeTicks crx_unpack_start_time_;
[email protected]1bf73cc32011-10-26 22:38:31283
[email protected]fc38935a2011-10-31 23:53:28284 // Location to use for the unpacked extension.
[email protected]1d5e58b2013-01-31 08:41:40285 Manifest::Location location_;
[email protected]fc38935a2011-10-31 23:53:28286
noelc8702c42017-03-16 08:51:19287 // Creation flags to use for the extension. These flags will be used
Istiaque Ahmedf425834e2018-06-12 01:50:25288 // when calling Extension::Create() by the CRX installer.
[email protected]1bf73cc32011-10-26 22:38:31289 int creation_flags_;
[email protected]7f8f24f2012-11-15 19:40:14290
noelc8702c42017-03-16 08:51:19291 // Sequenced task runner where file I/O operations will be performed.
[email protected]7f8f24f2012-11-15 19:40:14292 scoped_refptr<base::SequencedTaskRunner> unpacker_io_task_runner_;
asargentc4fdad22015-08-28 22:44:39293
Jay Civelliea8f3df2018-01-24 05:17:32294 // The normalized path of the install icon path, retrieved from the manifest.
295 base::FilePath install_icon_path_;
296
297 // The decoded install icon.
298 SkBitmap install_icon_;
299
Ken Rockotdc32df892019-11-01 06:32:10300 // Controls our own lazily started, isolated instance of the Data Decoder
301 // service so that multiple decode operations related to this
302 // SandboxedUnpacker can share a single instance.
303 data_decoder::DataDecoder data_decoder_;
Jay Civelliea8f3df2018-01-24 05:17:32304
Miyoung Shin364c6572019-09-11 09:02:19305 // The JSONParser remote from the data decoder service.
306 mojo::Remote<data_decoder::mojom::JsonParser> json_parser_;
Jay Civelli26a85642018-01-26 21:29:39307
Jay Civelliea8f3df2018-01-24 05:17:32308 // The ImageSanitizer used to clean-up images.
309 std::unique_ptr<ImageSanitizer> image_sanitizer_;
310
Jay Civelli6d0e68e2018-01-24 16:42:53311 // Used during the message catalog rewriting phase to sanitize the extension
312 // provided message catalogs.
313 std::unique_ptr<JsonFileSanitizer> json_file_sanitizer_;
314
asargentc4fdad22015-08-28 22:44:39315 DISALLOW_COPY_AND_ASSIGN(SandboxedUnpacker);
[email protected]af1277b2009-07-28 00:47:53316};
317
[email protected]f5ac2742012-07-02 17:50:58318} // namespace extensions
319
asargentc4fdad22015-08-28 22:44:39320#endif // EXTENSIONS_BROWSER_SANDBOXED_UNPACKER_H_