1 // Copyright (c) 2011 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 #ifndef CHROME_BROWSER_EXTENSIONS_SANDBOXED_EXTENSION_UNPACKER_H_ 6 #define CHROME_BROWSER_EXTENSIONS_SANDBOXED_EXTENSION_UNPACKER_H_ 7 #pragma once 8 9 #include <string> 10 11 #include "base/file_path.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/memory/scoped_temp_dir.h" 14 #include "chrome/browser/utility_process_host.h" 15 16 class DictionaryValue; 17 class Extension; 18 class ResourceDispatcherHost; 19 20 class SandboxedExtensionUnpackerClient 21 : public base::RefCountedThreadSafe<SandboxedExtensionUnpackerClient> { 22 public: 23 // temp_dir - A temporary directory containing the results of the extension 24 // unpacking. The client is responsible for deleting this directory. 25 // 26 // extension_root - The path to the extension root inside of temp_dir. 27 // 28 // extension - The extension that was unpacked. The client is responsible 29 // for deleting this memory. 30 virtual void OnUnpackSuccess(const FilePath& temp_dir, 31 const FilePath& extension_root, 32 const Extension* extension) = 0; 33 virtual void OnUnpackFailure(const std::string& error) = 0; 34 35 protected: 36 friend class base::RefCountedThreadSafe<SandboxedExtensionUnpackerClient>; 37 38 virtual ~SandboxedExtensionUnpackerClient() {} 39 }; 40 41 // SandboxedExtensionUnpacker unpacks extensions from the CRX format into a 42 // directory. This is done in a sandboxed subprocess to protect the browser 43 // process from parsing complex formats like JPEG or JSON from untrusted 44 // sources. 45 // 46 // Unpacking an extension using this class makes minor changes to its source, 47 // such as transcoding all images to PNG, parsing all message catalogs 48 // and rewriting the manifest JSON. As such, it should not be used when the 49 // output is not intended to be given back to the author. 50 // 51 // 52 // Lifetime management: 53 // 54 // This class is ref-counted by each call it makes to itself on another thread, 55 // and by UtilityProcessHost. 56 // 57 // Additionally, we hold a reference to our own client so that it lives at least 58 // long enough to receive the result of unpacking. 59 // 60 // 61 // NOTE: This class should only be used on the file thread. 62 class SandboxedExtensionUnpacker : public UtilityProcessHost::Client { 63 public: 64 // The size of the magic character sequence at the beginning of each crx 65 // file, in bytes. This should be a multiple of 4. 66 static const size_t kExtensionHeaderMagicSize = 4; 67 68 // This header is the first data at the beginning of an extension. Its 69 // contents are purposely 32-bit aligned so that it can just be slurped into 70 // a struct without manual parsing. 71 struct ExtensionHeader { 72 char magic[kExtensionHeaderMagicSize]; 73 uint32 version; 74 uint32 key_size; // The size of the public key, in bytes. 75 uint32 signature_size; // The size of the signature, in bytes. 76 // An ASN.1-encoded PublicKeyInfo structure follows. 77 // The signature follows. 78 }; 79 80 // The maximum size the crx parser will tolerate for a public key. 81 static const uint32 kMaxPublicKeySize = 1 << 16; 82 83 // The maximum size the crx parser will tolerate for a signature. 84 static const uint32 kMaxSignatureSize = 1 << 16; 85 86 // The magic character sequence at the beginning of each crx file. 87 static const char kExtensionHeaderMagic[]; 88 89 // The current version of the crx format. 90 static const uint32 kCurrentVersion = 2; 91 92 // Unpacks the extension in |crx_path| into a temporary directory and calls 93 // |client| with the result. If |rdh| is provided, unpacking is done in a 94 // sandboxed subprocess. Otherwise, it is done in-process. 95 SandboxedExtensionUnpacker(const FilePath& crx_path, 96 ResourceDispatcherHost* rdh, 97 SandboxedExtensionUnpackerClient* cilent); 98 99 // Start unpacking the extension. The client is called with the results. 100 void Start(); 101 102 private: 103 class ProcessHostClient; 104 105 // Enumerate all the ways unpacking can fail. Calls to ReportFailure() 106 // take a failure reason as an argument, and put it in histogram 107 // Extensions.SandboxUnpackFailureReason. 108 enum FailureReason { 109 // SandboxedExtensionUnpacker::CreateTempDirectory() 110 COULD_NOT_GET_TEMP_DIRECTORY, 111 COULD_NOT_CREATE_TEMP_DIRECTORY, 112 113 // SandboxedExtensionUnpacker::Start() 114 FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY, 115 COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, 116 117 // SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded() 118 COULD_NOT_LOCALIZE_EXTENSION, 119 INVALID_MANIFEST, 120 121 //SandboxedExtensionUnpacker::OnUnpackExtensionFailed() 122 UNPACKER_CLIENT_FAILED, 123 124 // SandboxedExtensionUnpacker::OnProcessCrashed() 125 UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, 126 127 // SandboxedExtensionUnpacker::ValidateSignature() 128 CRX_FILE_NOT_READABLE, 129 CRX_HEADER_INVALID, 130 CRX_MAGIC_NUMBER_INVALID, 131 CRX_VERSION_NUMBER_INVALID, 132 CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE, 133 CRX_ZERO_KEY_LENGTH, 134 CRX_ZERO_SIGNATURE_LENGTH, 135 CRX_PUBLIC_KEY_INVALID, 136 CRX_SIGNATURE_INVALID, 137 CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED, 138 CRX_SIGNATURE_VERIFICATION_FAILED, 139 140 // SandboxedExtensionUnpacker::RewriteManifestFile() 141 ERROR_SERIALIZING_MANIFEST_JSON, 142 ERROR_SAVING_MANIFEST_JSON, 143 144 // SandboxedExtensionUnpacker::RewriteImageFiles() 145 COULD_NOT_READ_IMAGE_DATA_FROM_DISK, 146 DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST, 147 INVALID_PATH_FOR_BROWSER_IMAGE, 148 ERROR_REMOVING_OLD_IMAGE_FILE, 149 INVALID_PATH_FOR_BITMAP_IMAGE, 150 ERROR_RE_ENCODING_THEME_IMAGE, 151 ERROR_SAVING_THEME_IMAGE, 152 153 // SandboxedExtensionUnpacker::RewriteCatalogFiles() 154 COULD_NOT_READ_CATALOG_DATA_FROM_DISK, 155 INVALID_CATALOG_DATA, 156 INVALID_PATH_FOR_CATALOG, 157 ERROR_SERIALIZING_CATALOG, 158 ERROR_SAVING_CATALOG, 159 160 NUM_FAILURE_REASONS 161 }; 162 163 friend class ProcessHostClient; 164 friend class SandboxedExtensionUnpackerTest; 165 166 virtual ~SandboxedExtensionUnpacker(); 167 168 // Set |temp_dir_| as a temporary directory to unpack the extension in. 169 // Return true on success. 170 virtual bool CreateTempDirectory(); 171 172 // Validates the signature of the extension and extract the key to 173 // |public_key_|. Returns true if the signature validates, false otherwise. 174 // 175 // NOTE: Having this method here is a bit ugly. This code should really live 176 // in ExtensionUnpacker as it is not specific to sandboxed unpacking. It was 177 // put here because we cannot run windows crypto code in the sandbox. But we 178 // could still have this method statically on ExtensionUnpacker so that code 179 // just for unpacking is there and code just for sandboxing of unpacking is 180 // here. 181 bool ValidateSignature(); 182 183 // Starts the utility process that unpacks our extension. 184 void StartProcessOnIOThread(const FilePath& temp_crx_path); 185 186 // SandboxedExtensionUnpacker 187 virtual void OnUnpackExtensionSucceeded(const DictionaryValue& manifest); 188 virtual void OnUnpackExtensionFailed(const std::string& error_message); 189 virtual void OnProcessCrashed(int exit_code); 190 191 void ReportFailure(FailureReason reason, const std::string& message); 192 void ReportSuccess(); 193 194 // Overwrites original manifest with safe result from utility process. 195 // Returns NULL on error. Caller owns the returned object. 196 DictionaryValue* RewriteManifestFile(const DictionaryValue& manifest); 197 198 // Overwrites original files with safe results from utility process. 199 // Reports error and returns false if it fails. 200 bool RewriteImageFiles(); 201 bool RewriteCatalogFiles(); 202 203 // The path to the CRX to unpack. 204 FilePath crx_path_; 205 206 // Our client's thread. This is the thread we respond on. 207 BrowserThread::ID thread_identifier_; 208 209 // ResourceDispatcherHost to pass to the utility process. 210 ResourceDispatcherHost* rdh_; 211 212 // Our client. 213 scoped_refptr<SandboxedExtensionUnpackerClient> client_; 214 215 // A temporary directory to use for unpacking. 216 ScopedTempDir temp_dir_; 217 218 // The root directory of the unpacked extension. This is a child of temp_dir_. 219 FilePath extension_root_; 220 221 // Represents the extension we're unpacking. 222 scoped_refptr<Extension> extension_; 223 224 // Whether we've received a response from the utility process yet. 225 bool got_response_; 226 227 // The public key that was extracted from the CRX header. 228 std::string public_key_; 229 }; 230 231 #endif // CHROME_BROWSER_EXTENSIONS_SANDBOXED_EXTENSION_UNPACKER_H_ 232