Add "sandboxed" option to "webPreferences".
When "sandboxed" is passed as a web preference for `BrowserWindow`, the newly created renderer won't run any node.js code/integration, only communicating with the system via the IPC API of the content module. This is a requirement for running the renderer under chrome OS-level sandbox. Beyond that, certain behaviors of AtomBrowserClient are modified when dealing with sandboxed renderers: - `OverrideSiteInstanceNavigation` no longer create a new `SiteInstance` for every navigation. Instead, it reuses the source `SiteInstance` when not navigating to a different site. - `CanCreateWindow` will return true and allow javascript access.
This commit is contained in:
parent
90c5972fce
commit
c783ec72bc
7 changed files with 104 additions and 8 deletions
|
@ -11,6 +11,7 @@
|
|||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/relauncher.h"
|
||||
#include "atom/common/google_api_key.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "atom/renderer/atom_renderer_client.h"
|
||||
#include "atom/utility/atom_content_utility_client.h"
|
||||
#include "base/command_line.h"
|
||||
|
@ -29,7 +30,7 @@ namespace {
|
|||
const char* kRelauncherProcess = "relauncher";
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -72,7 +73,7 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
|||
|
||||
// Only enable logging when --enable-logging is specified.
|
||||
std::unique_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);
|
||||
|
@ -115,17 +116,17 @@ void AtomMainDelegate::PreSandboxStartup() {
|
|||
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
std::string process_type = command_line->GetSwitchValueASCII(
|
||||
switches::kProcessType);
|
||||
::switches::kProcessType);
|
||||
|
||||
// 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);
|
||||
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.
|
||||
|
@ -140,7 +141,13 @@ content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() {
|
|||
|
||||
content::ContentRendererClient*
|
||||
AtomMainDelegate::CreateContentRendererClient() {
|
||||
renderer_client_.reset(new AtomRendererClient);
|
||||
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kEnableSandbox)) {
|
||||
renderer_client_.reset(new content::ContentRendererClient);
|
||||
} else {
|
||||
renderer_client_.reset(new AtomRendererClient);
|
||||
}
|
||||
|
||||
return renderer_client_.get();
|
||||
}
|
||||
|
||||
|
|
|
@ -99,6 +99,44 @@ content::WebContents* AtomBrowserClient::GetWebContentsFromProcessID(
|
|||
return WebContentsPreferences::GetWebContentsFromProcessID(process_id);
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::ShouldCreateNewSiteInstance(
|
||||
content::BrowserContext* browser_context,
|
||||
content::SiteInstance* current_instance,
|
||||
const GURL& url) {
|
||||
|
||||
if (url.SchemeIs(url::kJavaScriptScheme))
|
||||
// "javacript:" scheme should always use same SiteInstance
|
||||
return false;
|
||||
|
||||
if (!IsRendererSandboxed(current_instance->GetProcess()->GetID()))
|
||||
// non-sandboxed renderers should always create a new SiteInstance
|
||||
return true;
|
||||
|
||||
// Create new a SiteInstance if navigating to a different site.
|
||||
auto src_url = current_instance->GetSiteURL();
|
||||
return
|
||||
!content::SiteInstance::IsSameWebSite(browser_context, src_url, url) &&
|
||||
// `IsSameWebSite` doesn't seem to work for some URIs such as `file:`,
|
||||
// handle these scenarios by comparing only the site as defined by
|
||||
// `GetSiteForURL`.
|
||||
content::SiteInstance::GetSiteForURL(browser_context, url) != src_url;
|
||||
}
|
||||
|
||||
void AtomBrowserClient::AddSandboxedRendererId(int process_id) {
|
||||
base::AutoLock auto_lock(sandboxed_renderers_lock_);
|
||||
sandboxed_renderers_.insert(process_id);
|
||||
}
|
||||
|
||||
void AtomBrowserClient::RemoveSandboxedRendererId(int process_id) {
|
||||
base::AutoLock auto_lock(sandboxed_renderers_lock_);
|
||||
sandboxed_renderers_.erase(process_id);
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::IsRendererSandboxed(int process_id) {
|
||||
base::AutoLock auto_lock(sandboxed_renderers_lock_);
|
||||
return sandboxed_renderers_.count(process_id);
|
||||
}
|
||||
|
||||
void AtomBrowserClient::RenderProcessWillLaunch(
|
||||
content::RenderProcessHost* host) {
|
||||
int process_id = host->GetID();
|
||||
|
@ -106,6 +144,13 @@ void AtomBrowserClient::RenderProcessWillLaunch(
|
|||
host->AddFilter(new TtsMessageFilter(process_id, host->GetBrowserContext()));
|
||||
host->AddFilter(
|
||||
new WidevineCdmMessageFilter(process_id, host->GetBrowserContext()));
|
||||
|
||||
content::WebContents* web_contents = GetWebContentsFromProcessID(process_id);
|
||||
if (WebContentsPreferences::IsSandboxed(web_contents)) {
|
||||
AddSandboxedRendererId(host->GetID());
|
||||
// ensure the sandboxed renderer id is removed later
|
||||
host->AddObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
content::SpeechRecognitionManagerDelegate*
|
||||
|
@ -155,8 +200,7 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation(
|
|||
return;
|
||||
}
|
||||
|
||||
// Restart renderer process for all navigations except "javacript:" scheme.
|
||||
if (url.SchemeIs(url::kJavaScriptScheme))
|
||||
if (!ShouldCreateNewSiteInstance(browser_context, current_instance, url))
|
||||
return;
|
||||
|
||||
scoped_refptr<content::SiteInstance> site_instance =
|
||||
|
@ -281,6 +325,11 @@ bool AtomBrowserClient::CanCreateWindow(
|
|||
bool* no_javascript_access) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
|
||||
if (IsRendererSandboxed(render_process_id)) {
|
||||
*no_javascript_access = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (delegate_) {
|
||||
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&api::App::OnCreateWindow,
|
||||
|
@ -338,6 +387,7 @@ void AtomBrowserClient::RenderProcessHostDestroyed(
|
|||
break;
|
||||
}
|
||||
}
|
||||
RemoveSandboxedRendererId(process_id);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -108,8 +109,19 @@ class AtomBrowserClient : public brightray::BrowserClient,
|
|||
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
|
||||
|
||||
private:
|
||||
bool ShouldCreateNewSiteInstance(content::BrowserContext* browser_context,
|
||||
content::SiteInstance* current_instance,
|
||||
const GURL& dest_url);
|
||||
// Add/remove a process id to `sandboxed_renderers_`.
|
||||
void AddSandboxedRendererId(int process_id);
|
||||
void RemoveSandboxedRendererId(int process_id);
|
||||
bool IsRendererSandboxed(int process_id);
|
||||
|
||||
// pending_render_process => current_render_process.
|
||||
std::map<int, int> pending_processes_;
|
||||
// Set that contains the process ids of all sandboxed renderers
|
||||
std::set<int> sandboxed_renderers_;
|
||||
base::Lock sandboxed_renderers_lock_;
|
||||
|
||||
std::unique_ptr<AtomResourceDispatcherHostDelegate>
|
||||
resource_dispatcher_host_delegate_;
|
||||
|
|
|
@ -97,6 +97,12 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
|
|||
command_line->AppendSwitchASCII(switches::kNodeIntegration,
|
||||
node_integration ? "true" : "false");
|
||||
|
||||
// If the `sandbox` option was passed to the BrowserWindow's webPreferences,
|
||||
// pass `--enable-sandbox` to the renderer so it won't have any node.js
|
||||
// integration.
|
||||
if (IsSandboxed(web_contents))
|
||||
command_line->AppendSwitch(switches::kEnableSandbox);
|
||||
|
||||
// The preload script.
|
||||
base::FilePath::StringType preload;
|
||||
if (web_preferences.GetString(options::kPreloadScript, &preload)) {
|
||||
|
@ -194,6 +200,21 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
|
|||
command_line->AppendSwitch(cc::switches::kEnableBeginFrameScheduling);
|
||||
}
|
||||
|
||||
bool WebContentsPreferences::IsSandboxed(content::WebContents* web_contents) {
|
||||
WebContentsPreferences* self;
|
||||
if (!web_contents)
|
||||
return false;
|
||||
|
||||
self = FromWebContents(web_contents);
|
||||
if (!self)
|
||||
return false;
|
||||
|
||||
base::DictionaryValue& web_preferences = self->web_preferences_;
|
||||
bool sandboxed = false;
|
||||
web_preferences.GetBoolean("sandbox", &sandboxed);
|
||||
return sandboxed;
|
||||
}
|
||||
|
||||
// static
|
||||
void WebContentsPreferences::OverrideWebkitPrefs(
|
||||
content::WebContents* web_contents, content::WebPreferences* prefs) {
|
||||
|
|
|
@ -36,6 +36,8 @@ class WebContentsPreferences
|
|||
static void AppendExtraCommandLineSwitches(
|
||||
content::WebContents* web_contents, base::CommandLine* command_line);
|
||||
|
||||
static bool IsSandboxed(content::WebContents* web_contents);
|
||||
|
||||
// Modify the WebPreferences according to |web_contents|'s preferences.
|
||||
static void OverrideWebkitPrefs(
|
||||
content::WebContents* web_contents, content::WebPreferences* prefs);
|
||||
|
|
|
@ -117,6 +117,9 @@ const char kDisableBlinkFeatures[] = "disableBlinkFeatures";
|
|||
|
||||
namespace switches {
|
||||
|
||||
// Enable chromium sandbox.
|
||||
const char kEnableSandbox[] = "enable-sandbox";
|
||||
|
||||
// Enable plugins.
|
||||
const char kEnablePlugins[] = "enable-plugins";
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ extern const char kDisableBlinkFeatures[];
|
|||
|
||||
namespace switches {
|
||||
|
||||
extern const char kEnableSandbox[];
|
||||
extern const char kEnablePlugins[];
|
||||
extern const char kPpapiFlashPath[];
|
||||
extern const char kPpapiFlashVersion[];
|
||||
|
|
Loading…
Reference in a new issue