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