Skip to content
This repository has been archived by the owner on Jan 4, 2019. It is now read-only.

Commit

Permalink
Merge pull request #12 from brave/sandbox
Browse files Browse the repository at this point in the history
enable sandbox for renderers that don't run node
  • Loading branch information
bbondy committed Feb 9, 2016
2 parents 4675933 + a6a9ea3 commit c794907
Show file tree
Hide file tree
Showing 10 changed files with 328 additions and 258 deletions.
17 changes: 9 additions & 8 deletions atom/app/atom_main_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace atom {
namespace {

bool IsBrowserProcess(base::CommandLine* cmd) {
std::string process_type = cmd->GetSwitchValueASCII(switches::kProcessType);
std::string process_type = cmd->GetSwitchValueASCII(::switches::kProcessType);
return process_type.empty();
}

Expand Down Expand Up @@ -62,7 +62,7 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {

// Only enable logging when --enable-logging is specified.
scoped_ptr<base::Environment> env(base::Environment::Create());
if (!command_line->HasSwitch(switches::kEnableLogging) &&
if (!command_line->HasSwitch(::switches::kEnableLogging) &&
!env->HasVar("ELECTRON_ENABLE_LOGGING")) {
settings.logging_dest = logging::LOG_NONE;
logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
Expand Down Expand Up @@ -96,21 +96,22 @@ void AtomMainDelegate::PreSandboxStartup() {

auto command_line = base::CommandLine::ForCurrentProcess();
std::string process_type = command_line->GetSwitchValueASCII(
switches::kProcessType);
::switches::kProcessType);

if (process_type == switches::kUtilityProcess) {
if (process_type == ::switches::kUtilityProcess) {
AtomContentUtilityClient::PreSandboxStartup();
}

if (process_type == ::switches::kRendererProcess) {
AtomRendererClient::PreSandboxStartup();
}

// Only append arguments for browser process.
if (!IsBrowserProcess(command_line))
return;

// Disable renderer sandbox for most of node's functions.
command_line->AppendSwitch(switches::kNoSandbox);

// Allow file:// URIs to read other file:// URIs by default.
command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
command_line->AppendSwitch(::switches::kAllowFileAccessFromFiles);

#if defined(OS_MACOSX)
// Enable AVFoundation.
Expand Down
6 changes: 6 additions & 0 deletions atom/browser/atom_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/web_preferences.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_cert_request_info.h"
Expand Down Expand Up @@ -251,6 +252,11 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(

WebContentsPreferences::AppendExtraCommandLineSwitches(
web_contents, command_line);

if (WebContentsPreferences::run_node(command_line)) {
// Disable renderer sandbox for most of node's functions.
command_line->AppendSwitch(::switches::kNoSandbox);
}
}

void AtomBrowserClient::DidCreatePpapiPlugin(
Expand Down
2 changes: 0 additions & 2 deletions atom/browser/web_contents_preferences.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
#include <string>

#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/web_preferences.h"
Expand Down
15 changes: 15 additions & 0 deletions atom/browser/web_contents_preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#ifndef ATOM_BROWSER_WEB_CONTENTS_PREFERENCES_H_
#define ATOM_BROWSER_WEB_CONTENTS_PREFERENCES_H_

#include "atom/common/options_switches.h"
#include "base/command_line.h"
#include "base/values.h"
#include "content/public/browser/web_contents_user_data.h"

Expand All @@ -30,6 +32,19 @@ class WebContentsPreferences
static void AppendExtraCommandLineSwitches(
content::WebContents* web_contents, base::CommandLine* command_line);

static bool run_node(base::CommandLine* cmd_line) {
// if node integration is disabled or there is
// preload script/url then start node
return
cmd_line->GetSwitchValueASCII(switches::kNodeIntegration) != "false" ||
cmd_line->HasSwitch(switches::kPreloadScript) ||
cmd_line->HasSwitch(switches::kPreloadURL);
}

static bool run_node() {
return run_node(base::CommandLine::ForCurrentProcess());
}

// Modify the WebPreferences according to |web_contents|'s preferences.
static void OverrideWebkitPrefs(
content::WebContents* web_contents, content::WebPreferences* prefs);
Expand Down
242 changes: 242 additions & 0 deletions atom/common/javascript_bindings.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include <utility>
#include <string>
#include <vector>

#include "atom/common/api/api_messages.h"
#include "atom/common/asar/asar_util.h"
#include "atom/common/javascript_bindings.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/options_switches.h"
#include "atom/renderer/api/atom_api_web_frame.h"
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/path_service.h"
#include "base/files/file_path.h"
#include "content/public/renderer/render_view.h"
#include "native_mate/dictionary.h"
#include "net/base/filename_util.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"

namespace {
// TODO(bridiver) This is copied from atom_api_renderer_ipc.cc
// and atom_api_v8_util.cc and should be cleaned up
// using
// v8::Local<v8::Value> unused = v8::Undefined(isolate);
// v8::Local<v8::Object> v8_util = v8::Object::New(isolate);
// auto mod = node::get_builtin_module("atom_common_v8_util");
// mod->nm_context_register_func(v8_util, unused, context, nullptr);
// binding.Set("v8_util", v8_util);
// results in an unresolved external symbol error for get_builtin_module
// on windows
content::RenderView* GetCurrentRenderView() {
blink::WebLocalFrame* frame =
blink::WebLocalFrame::frameForCurrentContext();
if (!frame)
return NULL;

blink::WebView* view = frame->view();
if (!view)
return NULL; // can happen during closing.

return content::RenderView::FromWebView(view);
}

void Send(mate::Arguments* args,
const base::string16& channel,
const base::ListValue& arguments) {
content::RenderView* render_view = GetCurrentRenderView();
if (render_view == NULL)
return;

bool success = render_view->Send(new AtomViewHostMsg_Message(
render_view->GetRoutingID(), channel, arguments));

if (!success)
args->ThrowError("Unable to send AtomViewHostMsg_Message");
}

base::string16 SendSync(mate::Arguments* args,
const base::string16& channel,
const base::ListValue& arguments) {
base::string16 json;

content::RenderView* render_view = GetCurrentRenderView();
if (render_view == NULL)
return json;

IPC::SyncMessage* message = new AtomViewHostMsg_Message_Sync(
render_view->GetRoutingID(), channel, arguments, &json);
bool success = render_view->Send(message);

if (!success)
args->ThrowError("Unable to send AtomViewHostMsg_Message_Sync");

return json;
}

v8::Local<v8::Value> GetHiddenValue(v8::Local<v8::Object> object,
v8::Local<v8::String> key) {
return object->GetHiddenValue(key);
}

void SetHiddenValue(v8::Local<v8::Object> object,
v8::Local<v8::String> key,
v8::Local<v8::Value> value) {
object->SetHiddenValue(key, value);
}

// TODO(bridiver) This is mostly copied from node_bindings.cc
// and should be cleaned up
base::FilePath GetResourcesPath() {
auto command_line = base::CommandLine::ForCurrentProcess();
base::FilePath exec_path(command_line->GetProgram());
PathService::Get(base::FILE_EXE, &exec_path);
base::FilePath resources_path =
#if defined(OS_MACOSX)
exec_path.DirName().DirName().DirName().DirName().DirName()
.Append("Resources");
#else
exec_path.DirName().Append(FILE_PATH_LITERAL("resources"));
#endif
return resources_path;
}

std::string ExceptionToString(const v8::TryCatch& try_catch) {
std::string str;
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
v8::String::Utf8Value exception(try_catch.Exception());
v8::Local<v8::Message> message(try_catch.Message());
if (message.IsEmpty()) {
str.append(base::StringPrintf("%s\n", *exception));
} else {
v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
int linenum = message->GetLineNumber();
int colnum = message->GetStartColumn();
str.append(base::StringPrintf(
"%s:%i:%i %s\n", *filename, linenum, colnum, *exception));
v8::String::Utf8Value sourceline(message->GetSourceLine());
str.append(base::StringPrintf("%s\n", *sourceline));
}
return str;
}

v8::Handle<v8::Value> ExecuteScriptFile(v8::Isolate* isolate,
base::FilePath script_path,
std::string script_source) {
v8::Local<v8::String> source =
v8::String::NewFromUtf8(isolate,
script_source.data(),
v8::String::kNormalString,
script_source.size());

std::string script_name = script_path.AsUTF8Unsafe();
v8::Local<v8::String> name =
v8::String::NewFromUtf8(isolate,
script_name.data(),
v8::String::kNormalString,
script_name.size());

v8::TryCatch try_catch;
v8::Local<v8::Script> script = v8::Script::Compile(source, name);
if (script.IsEmpty() || try_catch.HasCaught()) {
LOG(FATAL) << "Failed to parse script file " << script_name;
LOG(FATAL) << ExceptionToString(try_catch);
exit(3);
}

v8::Local<v8::Value> result = script->Run();
if (result.IsEmpty() || try_catch.HasCaught()) {
LOG(FATAL) << "Failed to execute script file " << script_name;
LOG(FATAL) << ExceptionToString(try_catch);
exit(4);
}

return result;
}

base::LazyInstance<std::vector<std::pair<base::FilePath, std::string>>>
scripts = LAZY_INSTANCE_INITIALIZER;

} // namespace

namespace atom {

JavascriptBindings::JavascriptBindings() {
}

JavascriptBindings::~JavascriptBindings() {
}

void JavascriptBindings::PreSandboxStartup() {
// Load everything
base::FilePath resources_path = GetResourcesPath();
base::FilePath script_path =
resources_path.Append(FILE_PATH_LITERAL("atom.asar"))
.Append(FILE_PATH_LITERAL("renderer"))
.Append(FILE_PATH_LITERAL("lib"))
.Append(FILE_PATH_LITERAL("init-without-node.js"));

std::string script_source;
asar::ReadFileToString(script_path, &script_source);
scripts.Get().push_back(std::make_pair(script_path, script_source));

// Load supplied contentScripts
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (cmd_line->HasSwitch(switches::kContentScripts)) {
std::stringstream ss(cmd_line->
GetSwitchValueASCII(switches::kContentScripts));

std::string name;
while (std::getline(ss, name, ',')) {
base::FilePath script_path;
net::FileURLToFilePath(GURL(name), &script_path);

asar::ReadFileToString(script_path, &script_source);
scripts.Get().push_back(std::make_pair(script_path, script_source));
}
}
}

// bind native functions
void JavascriptBindings::BindTo(v8::Isolate* isolate,
v8::Local<v8::Object> process) {
mate::Dictionary binding(isolate, v8::Object::New(isolate));

mate::Dictionary v8_util(isolate, v8::Object::New(isolate));
v8_util.SetMethod("setHiddenValue", &SetHiddenValue);
v8_util.SetMethod("getHiddenValue", &GetHiddenValue);
binding.Set("v8_util", v8_util.GetHandle());

mate::Dictionary ipc(isolate, v8::Object::New(isolate));
ipc.SetMethod("send", &Send);
ipc.SetMethod("sendSync", &SendSync);
binding.Set("ipc", ipc.GetHandle());

mate::Dictionary web_frame(isolate, v8::Object::New(isolate));
web_frame.Set("webFrame", api::WebFrame::Create(isolate));
binding.Set("web_frame", web_frame);

mate::Dictionary dict(isolate, process);
dict.Set("binding", binding);

// store in the global scope
v8::Local<v8::String> process_key = mate::StringToV8(isolate, "process");
process->CreationContext()->Global()->Set(process_key, process);

for (std::vector<std::pair<base::FilePath, std::string>>::iterator i =
scripts.Get().begin();
i != scripts.Get().end();
++i) {
ExecuteScriptFile(isolate, i->first, i->second);
}

// remove process object from the global scope
process->CreationContext()->Global()->Delete(process_key);
}

} // namespace atom
28 changes: 28 additions & 0 deletions atom/common/javascript_bindings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#ifndef ATOM_COMMON_JAVASCRIPT_BINDINGS_H_
#define ATOM_COMMON_JAVASCRIPT_BINDINGS_H_

#include "base/files/file_path.h"
#include "v8/include/v8.h"

namespace atom {

class JavascriptBindings {
public:
JavascriptBindings();
virtual ~JavascriptBindings();

static void PreSandboxStartup();

void BindTo(v8::Isolate* isolate, v8::Local<v8::Object> process);

private:
DISALLOW_COPY_AND_ASSIGN(JavascriptBindings);
};

} // namespace atom

#endif // ATOM_COMMON_JAVASCRIPT_BINDINGS_H_
Loading

0 comments on commit c794907

Please sign in to comment.