summaryrefslogtreecommitdiffstats
path: root/chrome/common
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/common')
-rw-r--r--chrome/common/child_process_info.cc2
-rw-r--r--chrome/common/child_process_info.h1
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--chrome/common/common.vcproj8
-rw-r--r--chrome/common/extensions/extension_unpacker.cc212
-rw-r--r--chrome/common/extensions/extension_unpacker.h45
-rw-r--r--chrome/common/render_messages_internal.h19
-rw-r--r--chrome/common/sandbox_init_wrapper.cc1
9 files changed, 292 insertions, 0 deletions
diff --git a/chrome/common/child_process_info.cc b/chrome/common/child_process_info.cc
index bd4c070..15b0179 100644
--- a/chrome/common/child_process_info.cc
+++ b/chrome/common/child_process_info.cc
@@ -24,6 +24,8 @@ std::wstring ChildProcessInfo::GetTypeNameInEnglish(
return L"Plug-in";
case WORKER_PROCESS:
return L"Web Worker";
+ case UTILITY_PROCESS:
+ return L"Utility";
case UNKNOWN_PROCESS:
default:
DCHECK(false) << "Unknown child process type!";
diff --git a/chrome/common/child_process_info.h b/chrome/common/child_process_info.h
index 0b8386b..5bf9f44 100644
--- a/chrome/common/child_process_info.h
+++ b/chrome/common/child_process_info.h
@@ -17,6 +17,7 @@ class ChildProcessInfo {
RENDER_PROCESS,
PLUGIN_PROCESS,
WORKER_PROCESS,
+ UTILITY_PROCESS,
UNKNOWN_PROCESS,
};
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index d07c3e9..233259e 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -72,6 +72,9 @@ const wchar_t kPluginProcess[] = L"plugin";
// Causes the process to run as a worker subprocess.
const wchar_t kWorkerProcess[] = L"worker";
+// Causes the process to run as a utility subprocess.
+const wchar_t kUtilityProcess[] = L"utility";
+
// Runs the renderer and plugins in the same process as the browser
const wchar_t kSingleProcess[] = L"single-process";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index da3e0e4..f242ec9 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -29,6 +29,7 @@ extern const wchar_t kRendererProcess[];
extern const wchar_t kBrowserSubprocessPath[];
extern const wchar_t kPluginProcess[];
extern const wchar_t kWorkerProcess[];
+extern const wchar_t kUtilityProcess[];
extern const wchar_t kSingleProcess[];
extern const wchar_t kProcessPerTab[];
extern const wchar_t kProcessPerSite[];
diff --git a/chrome/common/common.vcproj b/chrome/common/common.vcproj
index 5ca07ee..25b8b16 100644
--- a/chrome/common/common.vcproj
+++ b/chrome/common/common.vcproj
@@ -253,6 +253,14 @@
Name="extensions"
>
<File
+ RelativePath=".\extensions\extension_unpacker.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\extensions\extension_unpacker.h"
+ >
+ </File>
+ <File
RelativePath=".\extensions\url_pattern.cc"
>
</File>
diff --git a/chrome/common/extensions/extension_unpacker.cc b/chrome/common/extensions/extension_unpacker.cc
new file mode 100644
index 0000000..1849ec8
--- /dev/null
+++ b/chrome/common/extensions/extension_unpacker.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/extension_unpacker.h"
+
+#include "base/file_util.h"
+#include "base/scoped_handle.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "base/third_party/nss/blapi.h"
+#include "base/third_party/nss/sha256.h"
+#include "base/thread.h"
+#include "base/values.h"
+#include "net/base/file_stream.h"
+// TODO(mpcomplete): move to common
+#include "chrome/browser/extensions/extension.h"
+#include "chrome/common/json_value_serializer.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/unzip.h"
+#include "chrome/common/url_constants.h"
+
+namespace {
+const char kCurrentVersionFileName[] = "Current Version";
+
+// The name of a temporary directory to install an extension into for
+// validation before finalizing install.
+const char kTempExtensionName[] = "TEMP_INSTALL";
+
+// Chromium Extension magic number
+const char kExtensionFileMagic[] = "Cr24";
+
+struct ExtensionHeader {
+ char magic[sizeof(kExtensionFileMagic) - 1];
+ uint32 version;
+ size_t header_size;
+ size_t manifest_size;
+};
+
+const size_t kZipHashBytes = 32; // SHA-256
+const size_t kZipHashHexBytes = kZipHashBytes * 2; // Hex string is 2x size.
+
+#if defined(OS_WIN)
+
+// Registry key where registry defined extension installers live.
+const wchar_t kRegistryExtensions[] = L"Software\\Google\\Chrome\\Extensions";
+
+// Registry value of of that key that defines the path to the .crx file.
+const wchar_t kRegistryExtensionPath[] = L"path";
+
+// Registry value of that key that defines the current version of the .crx file.
+const wchar_t kRegistryExtensionVersion[] = L"version";
+
+#endif
+
+// A marker file to indicate that an extension was installed from an external
+// source.
+const char kExternalInstallFile[] = "EXTERNAL_INSTALL";
+
+// The version of the extension package that this code understands.
+const uint32 kExpectedVersion = 1;
+}
+
+// The extension file format is a header, followed by the manifest, followed
+// by the zip file. The header is a magic number, a version, the size of the
+// header, and the size of the manifest. These ints are 4 byte little endian.
+DictionaryValue* ExtensionUnpacker::ReadManifest() {
+ ScopedStdioHandle file(file_util::OpenFile(extension_path_, "rb"));
+ if (!file.get()) {
+ SetError("no such extension file");
+ return NULL;
+ }
+
+ // Read and verify the header.
+ ExtensionHeader header;
+ size_t len;
+
+ // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it
+ // appears that we don't have any endian/alignment aware serialization
+ // code in the code base. So for now, this assumes that we're running
+ // on a little endian machine with 4 byte alignment.
+ len = fread(&header, 1, sizeof(ExtensionHeader), file.get());
+ if (len < sizeof(ExtensionHeader)) {
+ SetError("invalid extension header");
+ return NULL;
+ }
+ if (strncmp(kExtensionFileMagic, header.magic, sizeof(header.magic))) {
+ SetError("bad magic number");
+ return NULL;
+ }
+ if (header.version != kExpectedVersion) {
+ SetError("bad version number");
+ return NULL;
+ }
+ if (header.header_size > sizeof(ExtensionHeader))
+ fseek(file.get(), header.header_size - sizeof(ExtensionHeader), SEEK_CUR);
+
+ char buf[1 << 16];
+ std::string manifest_str;
+ size_t read_size = std::min(sizeof(buf), header.manifest_size);
+ size_t remainder = header.manifest_size;
+ while ((len = fread(buf, 1, read_size, file.get())) > 0) {
+ manifest_str.append(buf, len);
+ if (len <= remainder)
+ break;
+ remainder -= len;
+ read_size = std::min(sizeof(buf), remainder);
+ }
+
+ // Verify the JSON
+ JSONStringValueSerializer json(manifest_str);
+ std::string error;
+ scoped_ptr<Value> val(json.Deserialize(&error));
+ if (!val.get()) {
+ SetError(error);
+ return NULL;
+ }
+ if (!val->IsType(Value::TYPE_DICTIONARY)) {
+ SetError("manifest isn't a JSON dictionary");
+ return NULL;
+ }
+ DictionaryValue* manifest = static_cast<DictionaryValue*>(val.get());
+
+ std::string zip_hash;
+ if (!manifest->GetString(Extension::kZipHashKey, &zip_hash)) {
+ SetError("missing zip_hash key");
+ return NULL;
+ }
+ if (zip_hash.size() != kZipHashHexBytes) {
+ SetError("invalid zip_hash key");
+ return NULL;
+ }
+
+ // Read the rest of the zip file and compute a hash to compare against
+ // what the manifest claims. Compute the hash incrementally since the
+ // zip file could be large.
+ const unsigned char* ubuf = reinterpret_cast<const unsigned char*>(buf);
+ SHA256Context ctx;
+ SHA256_Begin(&ctx);
+ while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0)
+ SHA256_Update(&ctx, ubuf, len);
+ uint8 hash[32];
+ SHA256_End(&ctx, hash, NULL, sizeof(hash));
+
+ std::vector<uint8> zip_hash_bytes;
+ if (!HexStringToBytes(zip_hash, &zip_hash_bytes)) {
+ SetError("invalid zip_hash key");
+ return NULL;
+ }
+ if (zip_hash_bytes.size() != kZipHashBytes) {
+ SetError("invalid zip_hash key");
+ return NULL;
+ }
+ for (size_t i = 0; i < kZipHashBytes; ++i) {
+ if (zip_hash_bytes[i] != hash[i]) {
+ SetError("zip_hash key didn't match zip hash");
+ return NULL;
+ }
+ }
+
+ // TODO(erikkay): The manifest will also contain a signature of the hash
+ // (or perhaps the whole manifest) for authentication purposes.
+
+ // The caller owns val (now cast to manifest).
+ val.release();
+ return manifest;
+}
+
+bool ExtensionUnpacker::Run() {
+ LOG(INFO) << "Installing extension " << extension_path_.value();
+
+ // Read and verify the extension.
+ scoped_ptr<DictionaryValue> manifest(ReadManifest());
+ if (!manifest.get()) {
+ // ReadManifest has already reported the extension error.
+ return false;
+ }
+ Extension extension;
+ std::string error;
+ if (!extension.InitFromValue(*manifest,
+ true, // require ID
+ &error)) {
+ SetError("Invalid extension manifest.");
+ return false;
+ }
+
+ // ID is required for installed extensions.
+ if (extension.id().empty()) {
+ SetError("Required value 'id' is missing.");
+ return false;
+ }
+
+ // <profile>/Extensions/INSTALL_TEMP/<version>
+ std::string version = extension.VersionString();
+ FilePath temp_install =
+ extension_path_.DirName().AppendASCII(kTempExtensionName);
+ if (!file_util::CreateDirectory(temp_install)) {
+ SetError("Couldn't create directory for unzipping.");
+ return false;
+ }
+
+ if (!Unzip(extension_path_, temp_install, NULL)) {
+ SetError("Couldn't unzip extension.");
+ return false;
+ }
+
+ return true;
+}
+
+void ExtensionUnpacker::SetError(const std::string &error) {
+ error_message_ = error;
+}
diff --git a/chrome/common/extensions/extension_unpacker.h b/chrome/common/extensions/extension_unpacker.h
new file mode 100644
index 0000000..6d5fbf3
--- /dev/null
+++ b/chrome/common/extensions/extension_unpacker.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_UNPACKER_H_
+#define CHROME_COMMON_EXTENSIONS_EXTENSION_UNPACKER_H_
+
+#include <string>
+
+#include "base/file_path.h"
+
+class DictionaryValue;
+
+// Implements IO for the ExtensionsService.
+// TODO(aa): Extract an interface out of this for testing the frontend, once the
+// frontend has significant logic to test.
+class ExtensionUnpacker {
+ public:
+ explicit ExtensionUnpacker(const FilePath& extension_path)
+ : extension_path_(extension_path) {}
+
+ // Install the extension file at |extension_path|. Returns true on success.
+ // Otherwise, error_message will contain a string explaining what went wrong.
+ bool Run();
+
+ const std::string& error_message() { return error_message_; }
+
+ private:
+ // Read the manifest from the front of the extension file.
+ // Caller takes ownership of return value.
+ DictionaryValue* ReadManifest();
+
+ // Set the error message.
+ void SetError(const std::string& error);
+
+ // The extension to unpack.
+ FilePath extension_path_;
+
+ // The last error message that was set. Empty if there were no errors.
+ std::string error_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionUnpacker);
+};
+
+#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_UNPACKER_H_
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 5b12febb..4cf50d1 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -587,6 +587,15 @@ IPC_BEGIN_MESSAGES(View)
// width.
IPC_MESSAGE_ROUTED0(ViewMsg_EnableIntrinsicWidthChangedMode)
+ //---------------------------------------------------------------------------
+ // Utility process messages:
+ // These are messages from the browser to the utility process. They're here
+ // because we ran out of spare message types.
+
+ // Tell the utility process to unpack the given extension file in its
+ // directory and verify that it is valid.
+ IPC_MESSAGE_CONTROL1(UtilityMsg_UnpackExtension,
+ FilePath /* extension_filename */)
IPC_END_MESSAGES(View)
@@ -1372,4 +1381,14 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowPopup,
ViewHostMsg_ShowPopup_Params)
+ //---------------------------------------------------------------------------
+ // Utility process host messages:
+ // These are messages from the utility process to the browser. They're here
+ // because we ran out of spare message types.
+
+ // Reply when the utility process is done unpacking an extension. |success|
+ // argument is true if the extension unpacked and verified successfully.
+ IPC_MESSAGE_CONTROL2(UtilityHostMsg_UnpackExtension_Reply,
+ bool /* success */,
+ std::string /* error_message, if any */)
IPC_END_MESSAGES(ViewHost)
diff --git a/chrome/common/sandbox_init_wrapper.cc b/chrome/common/sandbox_init_wrapper.cc
index 8d264ce..c296ff8 100644
--- a/chrome/common/sandbox_init_wrapper.cc
+++ b/chrome/common/sandbox_init_wrapper.cc
@@ -27,6 +27,7 @@ void SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line,
if (!command_line.HasSwitch(switches::kNoSandbox)) {
if ((process_type == switches::kRendererProcess) ||
(process_type == switches::kWorkerProcess) ||
+ (process_type == switches::kUtilityProcess) ||
(process_type == switches::kPluginProcess &&
command_line.HasSwitch(switches::kSafePlugins))) {
#if defined(OS_WIN)