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