Home | History | Annotate | Download | only in extensions
      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.
      4 
      5 #include "chrome/browser/extensions/sandboxed_unpacker.h"
      6 
      7 #include <set>
      8 
      9 #include "base/base64.h"
     10 #include "base/bind.h"
     11 #include "base/command_line.h"
     12 #include "base/file_util.h"
     13 #include "base/files/file_util_proxy.h"
     14 #include "base/json/json_string_value_serializer.h"
     15 #include "base/memory/scoped_handle.h"
     16 #include "base/message_loop/message_loop.h"
     17 #include "base/metrics/histogram.h"
     18 #include "base/path_service.h"
     19 #include "base/sequenced_task_runner.h"
     20 #include "base/strings/utf_string_conversions.h"  // TODO(viettrungluu): delete me.
     21 #include "base/threading/sequenced_worker_pool.h"
     22 #include "chrome/browser/extensions/extension_service.h"
     23 #include "chrome/common/chrome_paths.h"
     24 #include "chrome/common/chrome_switches.h"
     25 #include "chrome/common/chrome_utility_messages.h"
     26 #include "chrome/common/extensions/extension.h"
     27 #include "chrome/common/extensions/extension_file_util.h"
     28 #include "chrome/common/extensions/extension_l10n_util.h"
     29 #include "chrome/common/extensions/extension_manifest_constants.h"
     30 #include "chrome/common/extensions/extension_manifest_constants.h"
     31 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
     32 #include "content/public/browser/browser_thread.h"
     33 #include "content/public/browser/utility_process_host.h"
     34 #include "content/public/common/common_param_traits.h"
     35 #include "crypto/signature_verifier.h"
     36 #include "extensions/common/constants.h"
     37 #include "extensions/common/crx_file.h"
     38 #include "extensions/common/id_util.h"
     39 #include "grit/generated_resources.h"
     40 #include "third_party/skia/include/core/SkBitmap.h"
     41 #include "ui/base/l10n/l10n_util.h"
     42 #include "ui/gfx/codec/png_codec.h"
     43 
     44 using content::BrowserThread;
     45 using content::UtilityProcessHost;
     46 
     47 // The following macro makes histograms that record the length of paths
     48 // in this file much easier to read.
     49 // Windows has a short max path length. If the path length to a
     50 // file being unpacked from a CRX exceeds the max length, we might
     51 // fail to install. To see if this is happening, see how long the
     52 // path to the temp unpack directory is. See crbug.com/69693 .
     53 #define PATH_LENGTH_HISTOGRAM(name, path) \
     54     UMA_HISTOGRAM_CUSTOM_COUNTS(name, path.value().length(), 0, 500, 100)
     55 
     56 // Record a rate (kB per second) at which extensions are unpacked.
     57 // Range from 1kB/s to 100mB/s.
     58 #define UNPACK_RATE_HISTOGRAM(name, rate) \
     59     UMA_HISTOGRAM_CUSTOM_COUNTS(name, rate, 1, 100000, 100);
     60 
     61 namespace extensions {
     62 namespace {
     63 
     64 void RecordSuccessfulUnpackTimeHistograms(
     65     const base::FilePath& crx_path, const base::TimeDelta unpack_time) {
     66 
     67   const int64 kBytesPerKb = 1024;
     68   const int64 kBytesPerMb = 1024 * 1024;
     69 
     70   UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackSuccessTime", unpack_time);
     71 
     72   // To get a sense of how CRX size impacts unpack time, record unpack
     73   // time for several increments of CRX size.
     74   int64 crx_file_size;
     75   if (!file_util::GetFileSize(crx_path, &crx_file_size)) {
     76     UMA_HISTOGRAM_COUNTS("Extensions.SandboxUnpackSuccessCantGetCrxSize", 1);
     77     return;
     78   }
     79 
     80   // Cast is safe as long as the number of bytes in the CRX is less than
     81   // 2^31 * 2^10.
     82   int crx_file_size_kb = static_cast<int>(crx_file_size / kBytesPerKb);
     83   UMA_HISTOGRAM_COUNTS(
     84       "Extensions.SandboxUnpackSuccessCrxSize", crx_file_size_kb);
     85 
     86   // We have time in seconds and file size in bytes.  We want the rate bytes are
     87   // unpacked in kB/s.
     88   double file_size_kb =
     89       static_cast<double>(crx_file_size) / static_cast<double>(kBytesPerKb);
     90   int unpack_rate_kb_per_s =
     91       static_cast<int>(file_size_kb / unpack_time.InSecondsF());
     92   UNPACK_RATE_HISTOGRAM("Extensions.SandboxUnpackRate", unpack_rate_kb_per_s);
     93 
     94   if (crx_file_size < 50.0 * kBytesPerKb) {
     95     UNPACK_RATE_HISTOGRAM(
     96         "Extensions.SandboxUnpackRateUnder50kB", unpack_rate_kb_per_s);
     97 
     98   } else if (crx_file_size < 1 * kBytesPerMb) {
     99     UNPACK_RATE_HISTOGRAM(
    100         "Extensions.SandboxUnpackRate50kBTo1mB", unpack_rate_kb_per_s);
    101 
    102   } else if (crx_file_size < 2 * kBytesPerMb) {
    103     UNPACK_RATE_HISTOGRAM(
    104         "Extensions.SandboxUnpackRate1To2mB", unpack_rate_kb_per_s);
    105 
    106   } else if (crx_file_size < 5 * kBytesPerMb) {
    107     UNPACK_RATE_HISTOGRAM(
    108         "Extensions.SandboxUnpackRate2To5mB", unpack_rate_kb_per_s);
    109 
    110   } else if (crx_file_size < 10 * kBytesPerMb) {
    111     UNPACK_RATE_HISTOGRAM(
    112         "Extensions.SandboxUnpackRate5To10mB", unpack_rate_kb_per_s);
    113 
    114   } else {
    115     UNPACK_RATE_HISTOGRAM(
    116         "Extensions.SandboxUnpackRateOver10mB", unpack_rate_kb_per_s);
    117   }
    118 }
    119 
    120 // Work horse for FindWritableTempLocation. Creates a temp file in the folder
    121 // and uses NormalizeFilePath to check if the path is junction free.
    122 bool VerifyJunctionFreeLocation(base::FilePath* temp_dir) {
    123   if (temp_dir->empty())
    124     return false;
    125 
    126   base::FilePath temp_file;
    127   if (!file_util::CreateTemporaryFileInDir(*temp_dir, &temp_file)) {
    128     LOG(ERROR) << temp_dir->value() << " is not writable";
    129     return false;
    130   }
    131   // NormalizeFilePath requires a non-empty file, so write some data.
    132   // If you change the exit points of this function please make sure all
    133   // exit points delete this temp file!
    134   file_util::WriteFile(temp_file, ".", 1);
    135 
    136   base::FilePath normalized_temp_file;
    137   bool normalized =
    138       file_util::NormalizeFilePath(temp_file, &normalized_temp_file);
    139   if (!normalized) {
    140     // If |temp_file| contains a link, the sandbox will block al file system
    141     // operations, and the install will fail.
    142     LOG(ERROR) << temp_dir->value() << " seem to be on remote drive.";
    143   } else {
    144     *temp_dir = normalized_temp_file.DirName();
    145   }
    146   // Clean up the temp file.
    147   base::DeleteFile(temp_file, false);
    148 
    149   return normalized;
    150 }
    151 
    152 // This function tries to find a location for unpacking the extension archive
    153 // that is writable and does not lie on a shared drive so that the sandboxed
    154 // unpacking process can write there. If no such location exists we can not
    155 // proceed and should fail.
    156 // The result will be written to |temp_dir|. The function will write to this
    157 // parameter even if it returns false.
    158 bool FindWritableTempLocation(const base::FilePath& extensions_dir,
    159                               base::FilePath* temp_dir) {
    160 // On ChromeOS, we will only attempt to unpack extension in cryptohome (profile)
    161 // directory to provide additional security/privacy and speed up the rest of
    162 // the extension install process.
    163 #if !defined(OS_CHROMEOS)
    164   PathService::Get(base::DIR_TEMP, temp_dir);
    165   if (VerifyJunctionFreeLocation(temp_dir))
    166     return true;
    167 #endif
    168 
    169   *temp_dir = extension_file_util::GetInstallTempDir(extensions_dir);
    170   if (VerifyJunctionFreeLocation(temp_dir))
    171     return true;
    172   // Neither paths is link free chances are good installation will fail.
    173   LOG(ERROR) << "Both the %TEMP% folder and the profile seem to be on "
    174              << "remote drives or read-only. Installation can not complete!";
    175   return false;
    176 }
    177 
    178 // Read the decoded images back from the file we saved them to.
    179 // |extension_path| is the path to the extension we unpacked that wrote the
    180 // data. Returns true on success.
    181 bool ReadImagesFromFile(const base::FilePath& extension_path,
    182                         DecodedImages* images) {
    183   base::FilePath path =
    184       extension_path.AppendASCII(kDecodedImagesFilename);
    185   std::string file_str;
    186   if (!file_util::ReadFileToString(path, &file_str))
    187     return false;
    188 
    189   IPC::Message pickle(file_str.data(), file_str.size());
    190   PickleIterator iter(pickle);
    191   return IPC::ReadParam(&pickle, &iter, images);
    192 }
    193 
    194 // Read the decoded message catalogs back from the file we saved them to.
    195 // |extension_path| is the path to the extension we unpacked that wrote the
    196 // data. Returns true on success.
    197 bool ReadMessageCatalogsFromFile(const base::FilePath& extension_path,
    198                                  base::DictionaryValue* catalogs) {
    199   base::FilePath path = extension_path.AppendASCII(
    200       kDecodedMessageCatalogsFilename);
    201   std::string file_str;
    202   if (!file_util::ReadFileToString(path, &file_str))
    203     return false;
    204 
    205   IPC::Message pickle(file_str.data(), file_str.size());
    206   PickleIterator iter(pickle);
    207   return IPC::ReadParam(&pickle, &iter, catalogs);
    208 }
    209 
    210 }  // namespace
    211 
    212 SandboxedUnpacker::SandboxedUnpacker(
    213     const base::FilePath& crx_path,
    214     Manifest::Location location,
    215     int creation_flags,
    216     const base::FilePath& extensions_dir,
    217     base::SequencedTaskRunner* unpacker_io_task_runner,
    218     SandboxedUnpackerClient* client)
    219     : crx_path_(crx_path),
    220       client_(client),
    221       extensions_dir_(extensions_dir),
    222       got_response_(false),
    223       location_(location),
    224       creation_flags_(creation_flags),
    225       unpacker_io_task_runner_(unpacker_io_task_runner) {
    226 }
    227 
    228 bool SandboxedUnpacker::CreateTempDirectory() {
    229   CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
    230 
    231   base::FilePath temp_dir;
    232   if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) {
    233     ReportFailure(
    234         COULD_NOT_GET_TEMP_DIRECTORY,
    235         l10n_util::GetStringFUTF16(
    236             IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    237             ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY")));
    238     return false;
    239   }
    240 
    241   if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_dir)) {
    242     ReportFailure(
    243         COULD_NOT_CREATE_TEMP_DIRECTORY,
    244         l10n_util::GetStringFUTF16(
    245             IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    246             ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY")));
    247     return false;
    248   }
    249 
    250   return true;
    251 }
    252 
    253 void SandboxedUnpacker::Start() {
    254   // We assume that we are started on the thread that the client wants us to do
    255   // file IO on.
    256   CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
    257 
    258   unpack_start_time_ = base::TimeTicks::Now();
    259 
    260   PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackInitialCrxPathLength",
    261                         crx_path_);
    262   if (!CreateTempDirectory())
    263     return;  // ReportFailure() already called.
    264 
    265   // Initialize the path that will eventually contain the unpacked extension.
    266   extension_root_ = temp_dir_.path().AppendASCII(kTempExtensionName);
    267   PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackUnpackedCrxPathLength",
    268                         extension_root_);
    269 
    270   // Extract the public key and validate the package.
    271   if (!ValidateSignature())
    272     return;  // ValidateSignature() already reported the error.
    273 
    274   // Copy the crx file into our working directory.
    275   base::FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName());
    276   PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackTempCrxPathLength",
    277                         temp_crx_path);
    278 
    279   if (!base::CopyFile(crx_path_, temp_crx_path)) {
    280     // Failed to copy extension file to temporary directory.
    281     ReportFailure(
    282         FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY,
    283         l10n_util::GetStringFUTF16(
    284             IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    285             ASCIIToUTF16("FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY")));
    286     return;
    287   }
    288 
    289   // The utility process will have access to the directory passed to
    290   // SandboxedUnpacker.  That directory should not contain a symlink or NTFS
    291   // reparse point.  When the path is used, following the link/reparse point
    292   // will cause file system access outside the sandbox path, and the sandbox
    293   // will deny the operation.
    294   base::FilePath link_free_crx_path;
    295   if (!file_util::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) {
    296     LOG(ERROR) << "Could not get the normalized path of "
    297                << temp_crx_path.value();
    298     ReportFailure(
    299         COULD_NOT_GET_SANDBOX_FRIENDLY_PATH,
    300         l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED));
    301     return;
    302   }
    303   PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength",
    304                         link_free_crx_path);
    305 
    306   BrowserThread::PostTask(
    307       BrowserThread::IO, FROM_HERE,
    308       base::Bind(
    309           &SandboxedUnpacker::StartProcessOnIOThread,
    310           this,
    311           link_free_crx_path));
    312 }
    313 
    314 SandboxedUnpacker::~SandboxedUnpacker() {
    315 }
    316 
    317 bool SandboxedUnpacker::OnMessageReceived(const IPC::Message& message) {
    318   bool handled = true;
    319   IPC_BEGIN_MESSAGE_MAP(SandboxedUnpacker, message)
    320     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnpackExtension_Succeeded,
    321                         OnUnpackExtensionSucceeded)
    322     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnpackExtension_Failed,
    323                         OnUnpackExtensionFailed)
    324     IPC_MESSAGE_UNHANDLED(handled = false)
    325   IPC_END_MESSAGE_MAP()
    326   return handled;
    327 }
    328 
    329 void SandboxedUnpacker::OnProcessCrashed(int exit_code) {
    330   // Don't report crashes if they happen after we got a response.
    331   if (got_response_)
    332     return;
    333 
    334   // Utility process crashed while trying to install.
    335   ReportFailure(
    336      UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL,
    337      l10n_util::GetStringFUTF16(
    338          IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    339          ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL")));
    340 }
    341 
    342 void SandboxedUnpacker::StartProcessOnIOThread(
    343     const base::FilePath& temp_crx_path) {
    344   UtilityProcessHost* host =
    345       UtilityProcessHost::Create(this, unpacker_io_task_runner_.get());
    346   // Grant the subprocess access to the entire subdir the extension file is
    347   // in, so that it can unpack to that dir.
    348   host->SetExposedDir(temp_crx_path.DirName());
    349   host->Send(
    350       new ChromeUtilityMsg_UnpackExtension(
    351           temp_crx_path, extension_id_, location_, creation_flags_));
    352 }
    353 
    354 void SandboxedUnpacker::OnUnpackExtensionSucceeded(
    355     const DictionaryValue& manifest) {
    356   CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
    357   got_response_ = true;
    358 
    359   scoped_ptr<DictionaryValue> final_manifest(RewriteManifestFile(manifest));
    360   if (!final_manifest)
    361     return;
    362 
    363   // Create an extension object that refers to the temporary location the
    364   // extension was unpacked to. We use this until the extension is finally
    365   // installed. For example, the install UI shows images from inside the
    366   // extension.
    367 
    368   // Localize manifest now, so confirm UI gets correct extension name.
    369 
    370   // TODO(rdevlin.cronin): Continue removing std::string errors and replacing
    371   // with string16
    372   std::string utf8_error;
    373   if (!extension_l10n_util::LocalizeExtension(extension_root_,
    374                                               final_manifest.get(),
    375                                               &utf8_error)) {
    376     ReportFailure(
    377         COULD_NOT_LOCALIZE_EXTENSION,
    378         l10n_util::GetStringFUTF16(
    379             IDS_EXTENSION_PACKAGE_ERROR_MESSAGE,
    380             UTF8ToUTF16(utf8_error)));
    381     return;
    382   }
    383 
    384   extension_ = Extension::Create(
    385       extension_root_,
    386       location_,
    387       *final_manifest,
    388       Extension::REQUIRE_KEY | creation_flags_,
    389       &utf8_error);
    390 
    391   if (!extension_.get()) {
    392     ReportFailure(INVALID_MANIFEST,
    393                   ASCIIToUTF16("Manifest is invalid: " + utf8_error));
    394     return;
    395   }
    396 
    397   SkBitmap install_icon;
    398   if (!RewriteImageFiles(&install_icon))
    399     return;
    400 
    401   if (!RewriteCatalogFiles())
    402     return;
    403 
    404   ReportSuccess(manifest, install_icon);
    405 }
    406 
    407 void SandboxedUnpacker::OnUnpackExtensionFailed(const string16& error) {
    408   CHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
    409   got_response_ = true;
    410   ReportFailure(
    411       UNPACKER_CLIENT_FAILED,
    412       l10n_util::GetStringFUTF16(
    413            IDS_EXTENSION_PACKAGE_ERROR_MESSAGE,
    414            error));
    415 }
    416 
    417 bool SandboxedUnpacker::ValidateSignature() {
    418   ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb"));
    419 
    420   if (!file.get()) {
    421     // Could not open crx file for reading.
    422 #if defined (OS_WIN)
    423     // On windows, get the error code.
    424     uint32 error_code = ::GetLastError();
    425     // TODO(skerner): Use this histogram to understand why so many
    426     // windows users hit this error.  crbug.com/69693
    427 
    428     // Windows errors are unit32s, but all of likely errors are in
    429     // [1, 1000].  See winerror.h for the meaning of specific values.
    430     // Clip errors outside the expected range to a single extra value.
    431     // If there are errors in that extra bucket, we will know to expand
    432     // the range.
    433     const uint32 kMaxErrorToSend = 1001;
    434     error_code = std::min(error_code, kMaxErrorToSend);
    435     UMA_HISTOGRAM_ENUMERATION("Extensions.ErrorCodeFromCrxOpen",
    436                               error_code, kMaxErrorToSend);
    437 #endif
    438 
    439     ReportFailure(
    440         CRX_FILE_NOT_READABLE,
    441         l10n_util::GetStringFUTF16(
    442             IDS_EXTENSION_PACKAGE_ERROR_CODE,
    443             ASCIIToUTF16("CRX_FILE_NOT_READABLE")));
    444     return false;
    445   }
    446 
    447   // Read and verify the header.
    448   // TODO(erikkay): Yuck.  I'm not a big fan of this kind of code, but it
    449   // appears that we don't have any endian/alignment aware serialization
    450   // code in the code base.  So for now, this assumes that we're running
    451   // on a little endian machine with 4 byte alignment.
    452   CrxFile::Header header;
    453   size_t len = fread(&header, 1, sizeof(header), file.get());
    454   if (len < sizeof(header)) {
    455     // Invalid crx header
    456     ReportFailure(
    457         CRX_HEADER_INVALID,
    458         l10n_util::GetStringFUTF16(
    459             IDS_EXTENSION_PACKAGE_ERROR_CODE,
    460             ASCIIToUTF16("CRX_HEADER_INVALID")));
    461     return false;
    462   }
    463 
    464   CrxFile::Error error;
    465   scoped_ptr<CrxFile> crx(CrxFile::Parse(header, &error));
    466   if (!crx) {
    467     switch (error) {
    468       case CrxFile::kWrongMagic:
    469         ReportFailure(
    470             CRX_MAGIC_NUMBER_INVALID,
    471             l10n_util::GetStringFUTF16(
    472                 IDS_EXTENSION_PACKAGE_ERROR_CODE,
    473                 ASCIIToUTF16("CRX_MAGIC_NUMBER_INVALID")));
    474         break;
    475       case CrxFile::kInvalidVersion:
    476         // Bad version numer
    477         ReportFailure(
    478             CRX_VERSION_NUMBER_INVALID,
    479             l10n_util::GetStringFUTF16(
    480                 IDS_EXTENSION_PACKAGE_ERROR_CODE,
    481                 ASCIIToUTF16("CRX_VERSION_NUMBER_INVALID")));
    482         break;
    483       case CrxFile::kInvalidKeyTooLarge:
    484       case CrxFile::kInvalidSignatureTooLarge:
    485         // Excessively large key or signature
    486         ReportFailure(
    487             CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE,
    488             l10n_util::GetStringFUTF16(
    489                 IDS_EXTENSION_PACKAGE_ERROR_CODE,
    490                 ASCIIToUTF16("CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE")));
    491         break;
    492       case CrxFile::kInvalidKeyTooSmall:
    493         // Key length is zero
    494         ReportFailure(
    495             CRX_ZERO_KEY_LENGTH,
    496             l10n_util::GetStringFUTF16(
    497                 IDS_EXTENSION_PACKAGE_ERROR_CODE,
    498                 ASCIIToUTF16("CRX_ZERO_KEY_LENGTH")));
    499         break;
    500       case CrxFile::kInvalidSignatureTooSmall:
    501         // Signature length is zero
    502         ReportFailure(
    503             CRX_ZERO_SIGNATURE_LENGTH,
    504             l10n_util::GetStringFUTF16(
    505                 IDS_EXTENSION_PACKAGE_ERROR_CODE,
    506                 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH")));
    507         break;
    508     }
    509     return false;
    510   }
    511 
    512   std::vector<uint8> key;
    513   key.resize(header.key_size);
    514   len = fread(&key.front(), sizeof(uint8), header.key_size, file.get());
    515   if (len < header.key_size) {
    516     // Invalid public key
    517     ReportFailure(
    518         CRX_PUBLIC_KEY_INVALID,
    519         l10n_util::GetStringFUTF16(
    520             IDS_EXTENSION_PACKAGE_ERROR_CODE,
    521             ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID")));
    522     return false;
    523   }
    524 
    525   std::vector<uint8> signature;
    526   signature.resize(header.signature_size);
    527   len = fread(&signature.front(), sizeof(uint8), header.signature_size,
    528       file.get());
    529   if (len < header.signature_size) {
    530     // Invalid signature
    531     ReportFailure(
    532         CRX_SIGNATURE_INVALID,
    533         l10n_util::GetStringFUTF16(
    534             IDS_EXTENSION_PACKAGE_ERROR_CODE,
    535             ASCIIToUTF16("CRX_SIGNATURE_INVALID")));
    536     return false;
    537   }
    538 
    539   crypto::SignatureVerifier verifier;
    540   if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm,
    541                            sizeof(extension_misc::kSignatureAlgorithm),
    542                            &signature.front(),
    543                            signature.size(),
    544                            &key.front(),
    545                            key.size())) {
    546     // Signature verification initialization failed. This is most likely
    547     // caused by a public key in the wrong format (should encode algorithm).
    548     ReportFailure(
    549         CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED,
    550         l10n_util::GetStringFUTF16(
    551             IDS_EXTENSION_PACKAGE_ERROR_CODE,
    552             ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED")));
    553     return false;
    554   }
    555 
    556   unsigned char buf[1 << 12];
    557   while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0)
    558     verifier.VerifyUpdate(buf, len);
    559 
    560   if (!verifier.VerifyFinal()) {
    561     // Signature verification failed
    562     ReportFailure(
    563         CRX_SIGNATURE_VERIFICATION_FAILED,
    564         l10n_util::GetStringFUTF16(
    565             IDS_EXTENSION_PACKAGE_ERROR_CODE,
    566             ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED")));
    567     return false;
    568   }
    569 
    570   std::string public_key =
    571       std::string(reinterpret_cast<char*>(&key.front()), key.size());
    572   base::Base64Encode(public_key, &public_key_);
    573 
    574   extension_id_ = id_util::GenerateId(public_key);
    575 
    576   return true;
    577 }
    578 
    579 void SandboxedUnpacker::ReportFailure(FailureReason reason,
    580                                       const string16& error) {
    581   UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason",
    582                             reason, NUM_FAILURE_REASONS);
    583   UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackFailureTime",
    584                       base::TimeTicks::Now() - unpack_start_time_);
    585   Cleanup();
    586   client_->OnUnpackFailure(error);
    587 }
    588 
    589 void SandboxedUnpacker::ReportSuccess(
    590     const DictionaryValue& original_manifest,
    591     const SkBitmap& install_icon) {
    592   UMA_HISTOGRAM_COUNTS("Extensions.SandboxUnpackSuccess", 1);
    593 
    594   RecordSuccessfulUnpackTimeHistograms(
    595       crx_path_, base::TimeTicks::Now() - unpack_start_time_);
    596 
    597   // Client takes ownership of temporary directory and extension.
    598   client_->OnUnpackSuccess(
    599       temp_dir_.Take(), extension_root_, &original_manifest, extension_.get(),
    600       install_icon);
    601   extension_ = NULL;
    602 }
    603 
    604 DictionaryValue* SandboxedUnpacker::RewriteManifestFile(
    605     const DictionaryValue& manifest) {
    606   // Add the public key extracted earlier to the parsed manifest and overwrite
    607   // the original manifest. We do this to ensure the manifest doesn't contain an
    608   // exploitable bug that could be used to compromise the browser.
    609   scoped_ptr<DictionaryValue> final_manifest(manifest.DeepCopy());
    610   final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_);
    611 
    612   std::string manifest_json;
    613   JSONStringValueSerializer serializer(&manifest_json);
    614   serializer.set_pretty_print(true);
    615   if (!serializer.Serialize(*final_manifest)) {
    616     // Error serializing manifest.json.
    617     ReportFailure(
    618         ERROR_SERIALIZING_MANIFEST_JSON,
    619         l10n_util::GetStringFUTF16(
    620             IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    621             ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON")));
    622     return NULL;
    623   }
    624 
    625   base::FilePath manifest_path =
    626       extension_root_.Append(kManifestFilename);
    627   if (!file_util::WriteFile(manifest_path,
    628                             manifest_json.data(), manifest_json.size())) {
    629     // Error saving manifest.json.
    630     ReportFailure(
    631         ERROR_SAVING_MANIFEST_JSON,
    632         l10n_util::GetStringFUTF16(
    633             IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    634             ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON")));
    635     return NULL;
    636   }
    637 
    638   return final_manifest.release();
    639 }
    640 
    641 bool SandboxedUnpacker::RewriteImageFiles(SkBitmap* install_icon) {
    642   DecodedImages images;
    643   if (!ReadImagesFromFile(temp_dir_.path(), &images)) {
    644     // Couldn't read image data from disk.
    645     ReportFailure(
    646         COULD_NOT_READ_IMAGE_DATA_FROM_DISK,
    647         l10n_util::GetStringFUTF16(
    648             IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    649             ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK")));
    650     return false;
    651   }
    652 
    653   // Delete any images that may be used by the browser.  We're going to write
    654   // out our own versions of the parsed images, and we want to make sure the
    655   // originals are gone for good.
    656   std::set<base::FilePath> image_paths =
    657       extension_file_util::GetBrowserImagePaths(extension_.get());
    658   if (image_paths.size() != images.size()) {
    659     // Decoded images don't match what's in the manifest.
    660     ReportFailure(
    661         DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST,
    662         l10n_util::GetStringFUTF16(
    663             IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    664             ASCIIToUTF16("DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST")));
    665     return false;
    666   }
    667 
    668   for (std::set<base::FilePath>::iterator it = image_paths.begin();
    669        it != image_paths.end(); ++it) {
    670     base::FilePath path = *it;
    671     if (path.IsAbsolute() || path.ReferencesParent()) {
    672       // Invalid path for browser image.
    673       ReportFailure(
    674           INVALID_PATH_FOR_BROWSER_IMAGE,
    675           l10n_util::GetStringFUTF16(
    676               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    677               ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE")));
    678       return false;
    679     }
    680     if (!base::DeleteFile(extension_root_.Append(path), false)) {
    681       // Error removing old image file.
    682       ReportFailure(
    683           ERROR_REMOVING_OLD_IMAGE_FILE,
    684           l10n_util::GetStringFUTF16(
    685               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    686               ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE")));
    687       return false;
    688     }
    689   }
    690 
    691   std::string install_icon_path = IconsInfo::GetIcons(extension_).Get(
    692       extension_misc::EXTENSION_ICON_LARGE,
    693       ExtensionIconSet::MATCH_BIGGER);
    694 
    695   // Write our parsed images back to disk as well.
    696   for (size_t i = 0; i < images.size(); ++i) {
    697     if (BrowserThread::GetBlockingPool()->IsShutdownInProgress()) {
    698       // Abort package installation if shutdown was initiated, crbug.com/235525
    699       ReportFailure(
    700           ABORTED_DUE_TO_SHUTDOWN,
    701           l10n_util::GetStringFUTF16(
    702               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    703               ASCIIToUTF16("ABORTED_DUE_TO_SHUTDOWN")));
    704       return false;
    705     }
    706 
    707     const SkBitmap& image = images[i].a;
    708     base::FilePath path_suffix = images[i].b;
    709     if (path_suffix.MaybeAsASCII() == install_icon_path)
    710       *install_icon = image;
    711 
    712     if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) {
    713       // Invalid path for bitmap image.
    714       ReportFailure(
    715           INVALID_PATH_FOR_BITMAP_IMAGE,
    716           l10n_util::GetStringFUTF16(
    717               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    718               ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE")));
    719       return false;
    720     }
    721     base::FilePath path = extension_root_.Append(path_suffix);
    722 
    723     std::vector<unsigned char> image_data;
    724     // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even
    725     // though they may originally be .jpg, etc.  Figure something out.
    726     // http://code.google.com/p/chromium/issues/detail?id=12459
    727     if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) {
    728       // Error re-encoding theme image.
    729       ReportFailure(
    730           ERROR_RE_ENCODING_THEME_IMAGE,
    731           l10n_util::GetStringFUTF16(
    732               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    733               ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE")));
    734       return false;
    735     }
    736 
    737     // Note: we're overwriting existing files that the utility process wrote,
    738     // so we can be sure the directory exists.
    739     const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]);
    740     if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) {
    741       // Error saving theme image.
    742       ReportFailure(
    743           ERROR_SAVING_THEME_IMAGE,
    744           l10n_util::GetStringFUTF16(
    745               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    746               ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE")));
    747       return false;
    748     }
    749   }
    750 
    751   return true;
    752 }
    753 
    754 bool SandboxedUnpacker::RewriteCatalogFiles() {
    755   DictionaryValue catalogs;
    756   if (!ReadMessageCatalogsFromFile(temp_dir_.path(), &catalogs)) {
    757     // Could not read catalog data from disk.
    758     ReportFailure(
    759         COULD_NOT_READ_CATALOG_DATA_FROM_DISK,
    760         l10n_util::GetStringFUTF16(
    761             IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    762             ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK")));
    763     return false;
    764   }
    765 
    766   // Write our parsed catalogs back to disk.
    767   for (DictionaryValue::Iterator it(catalogs); !it.IsAtEnd(); it.Advance()) {
    768     const DictionaryValue* catalog = NULL;
    769     if (!it.value().GetAsDictionary(&catalog)) {
    770       // Invalid catalog data.
    771       ReportFailure(
    772           INVALID_CATALOG_DATA,
    773           l10n_util::GetStringFUTF16(
    774               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    775               ASCIIToUTF16("INVALID_CATALOG_DATA")));
    776       return false;
    777     }
    778 
    779     // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())|
    780     // hack and remove the corresponding #include.
    781     base::FilePath relative_path =
    782         base::FilePath::FromWStringHack(UTF8ToWide(it.key()));
    783     relative_path = relative_path.Append(kMessagesFilename);
    784     if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) {
    785       // Invalid path for catalog.
    786       ReportFailure(
    787           INVALID_PATH_FOR_CATALOG,
    788           l10n_util::GetStringFUTF16(
    789               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    790               ASCIIToUTF16("INVALID_PATH_FOR_CATALOG")));
    791       return false;
    792     }
    793     base::FilePath path = extension_root_.Append(relative_path);
    794 
    795     std::string catalog_json;
    796     JSONStringValueSerializer serializer(&catalog_json);
    797     serializer.set_pretty_print(true);
    798     if (!serializer.Serialize(*catalog)) {
    799       // Error serializing catalog.
    800       ReportFailure(
    801           ERROR_SERIALIZING_CATALOG,
    802           l10n_util::GetStringFUTF16(
    803               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    804               ASCIIToUTF16("ERROR_SERIALIZING_CATALOG")));
    805       return false;
    806     }
    807 
    808     // Note: we're overwriting existing files that the utility process read,
    809     // so we can be sure the directory exists.
    810     if (!file_util::WriteFile(path,
    811                               catalog_json.c_str(),
    812                               catalog_json.size())) {
    813       // Error saving catalog.
    814       ReportFailure(
    815           ERROR_SAVING_CATALOG,
    816           l10n_util::GetStringFUTF16(
    817               IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
    818               ASCIIToUTF16("ERROR_SAVING_CATALOG")));
    819       return false;
    820     }
    821   }
    822 
    823   return true;
    824 }
    825 
    826 void SandboxedUnpacker::Cleanup() {
    827   DCHECK(unpacker_io_task_runner_->RunsTasksOnCurrentThread());
    828   if (!temp_dir_.Delete()) {
    829     LOG(WARNING) << "Can not delete temp directory at "
    830                  << temp_dir_.path().value();
    831   }
    832 }
    833 
    834 }  // namespace extensions
    835