diff options
Diffstat (limited to 'chrome/browser/extensions/sandboxed_extension_unpacker.cc')
-rw-r--r-- | chrome/browser/extensions/sandboxed_extension_unpacker.cc | 218 |
1 files changed, 140 insertions, 78 deletions
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.cc b/chrome/browser/extensions/sandboxed_extension_unpacker.cc index 160a0de..65ccded 100644 --- a/chrome/browser/extensions/sandboxed_extension_unpacker.cc +++ b/chrome/browser/extensions/sandboxed_extension_unpacker.cc @@ -21,7 +21,6 @@ #include "chrome/common/extensions/extension_unpacker.h" #include "chrome/common/json_value_serializer.h" #include "net/base/base64.h" - #include "third_party/skia/include/core/SkBitmap.h" const char SandboxedExtensionUnpacker::kExtensionHeaderMagic[] = "Cr24"; @@ -83,7 +82,8 @@ void SandboxedExtensionUnpacker::Start() { // Otherwise, unpack the extension in this process. ExtensionUnpacker unpacker(temp_crx_path); if (unpacker.Run() && unpacker.DumpImagesToFile()) - OnUnpackExtensionSucceeded(*unpacker.parsed_manifest()); + OnUnpackExtensionSucceeded(*unpacker.parsed_manifest(), + *unpacker.parsed_catalogs()); else OnUnpackExtensionFailed(unpacker.error_message()); } @@ -97,38 +97,16 @@ void SandboxedExtensionUnpacker::StartProcessOnIOThread( } void SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded( - const DictionaryValue& manifest) { - DCHECK(ChromeThread::CurrentlyOn(thread_identifier_)); + const DictionaryValue& manifest, + const DictionaryValue& catalogs) { + // Skip check for unittests. + if (thread_identifier_ != ChromeThread::ID_COUNT) + DCHECK(ChromeThread::CurrentlyOn(thread_identifier_)); got_response_ = true; - ExtensionUnpacker::DecodedImages images; - if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) { - ReportFailure("Couldn't read image data from disk."); + scoped_ptr<DictionaryValue> final_manifest(RewriteManifestFile(manifest)); + if (!final_manifest.get()) return; - } - - // Add the public key extracted earlier to the parsed manifest and overwrite - // the original manifest. We do this to ensure the manifest doesn't contain an - // exploitable bug that could be used to compromise the browser. - scoped_ptr<DictionaryValue> final_manifest( - static_cast<DictionaryValue*>(manifest.DeepCopy())); - final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_); - - std::string manifest_json; - JSONStringValueSerializer serializer(&manifest_json); - serializer.set_pretty_print(true); - if (!serializer.Serialize(*final_manifest)) { - ReportFailure("Error serializing manifest.json."); - return; - } - - FilePath manifest_path = - extension_root_.AppendASCII(Extension::kManifestFilename); - if (!file_util::WriteFile(manifest_path, - manifest_json.data(), manifest_json.size())) { - ReportFailure("Error saving manifest.json."); - return; - } // Create an extension object that refers to the temporary location the // extension was unpacked to. We use this until the extension is finally @@ -144,55 +122,11 @@ void SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded( return; } - // Delete any images that may be used by the browser. We're going to write - // out our own versions of the parsed images, and we want to make sure the - // originals are gone for good. - std::set<FilePath> image_paths = extension_->GetBrowserImages(); - if (image_paths.size() != images.size()) { - ReportFailure("Decoded images don't match what's in the manifest."); + if (!RewriteImageFiles()) return; - } - - for (std::set<FilePath>::iterator it = image_paths.begin(); - it != image_paths.end(); ++it) { - FilePath path = *it; - if (path.IsAbsolute() || path.ReferencesParent()) { - ReportFailure("Invalid path for browser image."); - return; - } - if (!file_util::Delete(extension_root_.Append(path), false)) { - ReportFailure("Error removing old image file."); - return; - } - } - // Write our parsed images back to disk as well. - for (size_t i = 0; i < images.size(); ++i) { - const SkBitmap& image = images[i].a; - FilePath path_suffix = images[i].b; - if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { - ReportFailure("Invalid path for bitmap image."); - return; - } - FilePath path = extension_root_.Append(path_suffix); - - std::vector<unsigned char> image_data; - // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even - // though they may originally be .jpg, etc. Figure something out. - // http://code.google.com/p/chromium/issues/detail?id=12459 - if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { - ReportFailure("Error re-encoding theme image."); - return; - } - - // Note: we're overwriting existing files that the utility process wrote, - // so we can be sure the directory exists. - const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); - if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) { - ReportFailure("Error saving theme image."); - return; - } - } + if (!RewriteCatalogFiles(catalogs)) + return; ReportSuccess(); } @@ -310,3 +244,131 @@ void SandboxedExtensionUnpacker::ReportSuccess() { client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_, extension_.release()); } + +DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile( + const DictionaryValue& manifest) { + // Add the public key extracted earlier to the parsed manifest and overwrite + // the original manifest. We do this to ensure the manifest doesn't contain an + // exploitable bug that could be used to compromise the browser. + scoped_ptr<DictionaryValue> final_manifest( + static_cast<DictionaryValue*>(manifest.DeepCopy())); + final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_); + + std::string manifest_json; + JSONStringValueSerializer serializer(&manifest_json); + serializer.set_pretty_print(true); + if (!serializer.Serialize(*final_manifest)) { + ReportFailure("Error serializing manifest.json."); + return NULL; + } + + FilePath manifest_path = + extension_root_.AppendASCII(Extension::kManifestFilename); + if (!file_util::WriteFile(manifest_path, + manifest_json.data(), manifest_json.size())) { + ReportFailure("Error saving manifest.json."); + return NULL; + } + + return final_manifest.release(); +} + +bool SandboxedExtensionUnpacker::RewriteImageFiles() { + ExtensionUnpacker::DecodedImages images; + if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) { + ReportFailure("Couldn't read image data from disk."); + return false; + } + + // Delete any images that may be used by the browser. We're going to write + // out our own versions of the parsed images, and we want to make sure the + // originals are gone for good. + std::set<FilePath> image_paths = extension_->GetBrowserImages(); + if (image_paths.size() != images.size()) { + ReportFailure("Decoded images don't match what's in the manifest."); + return false; + } + + for (std::set<FilePath>::iterator it = image_paths.begin(); + it != image_paths.end(); ++it) { + FilePath path = *it; + if (path.IsAbsolute() || path.ReferencesParent()) { + ReportFailure("Invalid path for browser image."); + return false; + } + if (!file_util::Delete(extension_root_.Append(path), false)) { + ReportFailure("Error removing old image file."); + return false; + } + } + + // Write our parsed images back to disk as well. + for (size_t i = 0; i < images.size(); ++i) { + const SkBitmap& image = images[i].a; + FilePath path_suffix = images[i].b; + if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { + ReportFailure("Invalid path for bitmap image."); + return false; + } + FilePath path = extension_root_.Append(path_suffix); + + std::vector<unsigned char> image_data; + // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even + // though they may originally be .jpg, etc. Figure something out. + // http://code.google.com/p/chromium/issues/detail?id=12459 + if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { + ReportFailure("Error re-encoding theme image."); + return false; + } + + // Note: we're overwriting existing files that the utility process wrote, + // so we can be sure the directory exists. + const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); + if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) { + ReportFailure("Error saving theme image."); + return false; + } + } + + return true; +} + +bool SandboxedExtensionUnpacker::RewriteCatalogFiles( + const DictionaryValue& catalogs) { + // Write our parsed catalogs back to disk. + DictionaryValue::key_iterator key_it = catalogs.begin_keys(); + for (; key_it != catalogs.end_keys(); ++key_it) { + DictionaryValue* catalog; + if (!catalogs.GetDictionary(*key_it, &catalog)) { + ReportFailure("Invalid catalog data."); + return false; + } + + FilePath relative_path = FilePath::FromWStringHack(*key_it); + relative_path = relative_path.AppendASCII(Extension::kMessagesFilename); + if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { + ReportFailure("Invalid path for catalog."); + return false; + } + FilePath path = extension_root_.Append(relative_path); + + std::string catalog_json; + JSONStringValueSerializer serializer(&catalog_json); + serializer.set_pretty_print(true); + if (!serializer.Serialize(*catalog)) { + ReportFailure("Error serializing catalog."); + return false; + } + + // Note: we're overwriting existing files that the utility process read, + // so we can be sure the directory exists. + if (!file_util::WriteFile(path, + catalog_json.c_str(), + catalog_json.size())) { + ReportFailure("Error saving catalog."); + return false; + } + } + + return true; +} |