| Index: chrome/browser/extensions/sandboxed_extension_unpacker.cc
|
| ===================================================================
|
| --- chrome/browser/extensions/sandboxed_extension_unpacker.cc (revision 35541)
|
| +++ chrome/browser/extensions/sandboxed_extension_unpacker.cc (working copy)
|
| @@ -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 @@
|
| // 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,39 +97,17 @@
|
| }
|
|
|
| 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
|
| // installed. For example, the install UI shows images from inside the
|
| @@ -144,56 +122,12 @@
|
| 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;
|
| - }
|
| - }
|
| + if (!RewriteCatalogFiles(catalogs))
|
| + 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;
|
| - }
|
| - }
|
| -
|
| ReportSuccess();
|
| }
|
|
|
| @@ -310,3 +244,131 @@
|
| 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;
|
| +}
|
|
|