feat: expose missing process APIs in sandboxed renderers (#13505)
This commit is contained in:
parent
f82f89b2a3
commit
fc85d02786
11 changed files with 95 additions and 35 deletions
|
@ -59,7 +59,7 @@ void AtomBindings::BindTo(v8::Isolate* isolate, v8::Local<v8::Object> process) {
|
||||||
dict.SetMethod("getCreationTime", &GetCreationTime);
|
dict.SetMethod("getCreationTime", &GetCreationTime);
|
||||||
dict.SetMethod("getSystemMemoryInfo", &GetSystemMemoryInfo);
|
dict.SetMethod("getSystemMemoryInfo", &GetSystemMemoryInfo);
|
||||||
dict.SetMethod("getCPUUsage", base::Bind(&AtomBindings::GetCPUUsage,
|
dict.SetMethod("getCPUUsage", base::Bind(&AtomBindings::GetCPUUsage,
|
||||||
base::Unretained(this)));
|
base::Unretained(metrics_.get())));
|
||||||
dict.SetMethod("getIOCounters", &GetIOCounters);
|
dict.SetMethod("getIOCounters", &GetIOCounters);
|
||||||
#if defined(OS_POSIX)
|
#if defined(OS_POSIX)
|
||||||
dict.SetMethod("setFdLimit", &base::SetFdLimit);
|
dict.SetMethod("setFdLimit", &base::SetFdLimit);
|
||||||
|
@ -220,17 +220,19 @@ v8::Local<v8::Value> AtomBindings::GetSystemMemoryInfo(v8::Isolate* isolate,
|
||||||
return dict.GetHandle();
|
return dict.GetHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> AtomBindings::GetCPUUsage(v8::Isolate* isolate) {
|
// static
|
||||||
|
v8::Local<v8::Value> AtomBindings::GetCPUUsage(base::ProcessMetrics* metrics,
|
||||||
|
v8::Isolate* isolate) {
|
||||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||||
dict.SetHidden("simple", true);
|
dict.SetHidden("simple", true);
|
||||||
int processor_count = base::SysInfo::NumberOfProcessors();
|
int processor_count = base::SysInfo::NumberOfProcessors();
|
||||||
dict.Set("percentCPUUsage",
|
dict.Set("percentCPUUsage",
|
||||||
metrics_->GetPlatformIndependentCPUUsage() / processor_count);
|
metrics->GetPlatformIndependentCPUUsage() / processor_count);
|
||||||
|
|
||||||
// NB: This will throw NOTIMPLEMENTED() on Windows
|
// NB: This will throw NOTIMPLEMENTED() on Windows
|
||||||
// For backwards compatibility, we'll return 0
|
// For backwards compatibility, we'll return 0
|
||||||
#if !defined(OS_WIN)
|
#if !defined(OS_WIN)
|
||||||
dict.Set("idleWakeupsPerSecond", metrics_->GetIdleWakeupsPerSecond());
|
dict.Set("idleWakeupsPerSecond", metrics->GetIdleWakeupsPerSecond());
|
||||||
#else
|
#else
|
||||||
dict.Set("idleWakeupsPerSecond", 0);
|
dict.Set("idleWakeupsPerSecond", 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -40,7 +40,8 @@ class AtomBindings {
|
||||||
static v8::Local<v8::Value> GetCreationTime(v8::Isolate* isolate);
|
static v8::Local<v8::Value> GetCreationTime(v8::Isolate* isolate);
|
||||||
static v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate,
|
static v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate,
|
||||||
mate::Arguments* args);
|
mate::Arguments* args);
|
||||||
v8::Local<v8::Value> GetCPUUsage(v8::Isolate* isolate);
|
static v8::Local<v8::Value> GetCPUUsage(base::ProcessMetrics* metrics,
|
||||||
|
v8::Isolate* isolate);
|
||||||
static v8::Local<v8::Value> GetIOCounters(v8::Isolate* isolate);
|
static v8::Local<v8::Value> GetIOCounters(v8::Isolate* isolate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "base/base_paths.h"
|
#include "base/base_paths.h"
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "base/environment.h"
|
#include "base/environment.h"
|
||||||
#include "base/files/file_path.h"
|
|
||||||
#include "base/path_service.h"
|
#include "base/path_service.h"
|
||||||
#include "base/run_loop.h"
|
#include "base/run_loop.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
@ -195,6 +194,10 @@ bool NodeBindings::IsInitialized() {
|
||||||
return g_is_initialized;
|
return g_is_initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::FilePath::StringType NodeBindings::GetHelperResourcesPath() {
|
||||||
|
return GetResourcesPath(false).value();
|
||||||
|
}
|
||||||
|
|
||||||
void NodeBindings::Initialize() {
|
void NodeBindings::Initialize() {
|
||||||
// Open node's error reporting system for browser process.
|
// Open node's error reporting system for browser process.
|
||||||
node::g_standalone_mode = browser_env_ == BROWSER;
|
node::g_standalone_mode = browser_env_ == BROWSER;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#ifndef ATOM_COMMON_NODE_BINDINGS_H_
|
#ifndef ATOM_COMMON_NODE_BINDINGS_H_
|
||||||
#define ATOM_COMMON_NODE_BINDINGS_H_
|
#define ATOM_COMMON_NODE_BINDINGS_H_
|
||||||
|
|
||||||
|
#include "base/files/file_path.h"
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "base/memory/weak_ptr.h"
|
#include "base/memory/weak_ptr.h"
|
||||||
#include "base/single_thread_task_runner.h"
|
#include "base/single_thread_task_runner.h"
|
||||||
|
@ -33,6 +34,7 @@ class NodeBindings {
|
||||||
static NodeBindings* Create(BrowserEnvironment browser_env);
|
static NodeBindings* Create(BrowserEnvironment browser_env);
|
||||||
static void RegisterBuiltinModules();
|
static void RegisterBuiltinModules();
|
||||||
static bool IsInitialized();
|
static bool IsInitialized();
|
||||||
|
static base::FilePath::StringType GetHelperResourcesPath();
|
||||||
|
|
||||||
virtual ~NodeBindings();
|
virtual ~NodeBindings();
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/path_service.h"
|
#include "base/path_service.h"
|
||||||
|
#include "base/process/process_handle.h"
|
||||||
#include "chrome/renderer/printing/print_web_view_helper.h"
|
#include "chrome/renderer/printing/print_web_view_helper.h"
|
||||||
#include "content/public/renderer/render_frame.h"
|
#include "content/public/renderer/render_frame.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
|
@ -96,27 +97,6 @@ v8::Local<v8::Value> CreatePreloadScript(v8::Isolate* isolate,
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeBindings(v8::Local<v8::Object> binding,
|
|
||||||
v8::Local<v8::Context> context) {
|
|
||||||
auto* isolate = context->GetIsolate();
|
|
||||||
mate::Dictionary b(isolate, binding);
|
|
||||||
b.SetMethod("get", GetBinding);
|
|
||||||
b.SetMethod("createPreloadScript", CreatePreloadScript);
|
|
||||||
b.SetMethod("crash", AtomBindings::Crash);
|
|
||||||
b.SetMethod("hang", AtomBindings::Hang);
|
|
||||||
b.SetMethod("getArgv", GetArgv);
|
|
||||||
b.SetMethod("getExecPath", GetExecPath);
|
|
||||||
b.SetMethod("getHeapStatistics", &AtomBindings::GetHeapStatistics);
|
|
||||||
b.SetMethod("getProcessMemoryInfo", &AtomBindings::GetProcessMemoryInfo);
|
|
||||||
b.SetMethod("getSystemMemoryInfo", &AtomBindings::GetSystemMemoryInfo);
|
|
||||||
|
|
||||||
// Pass in CLI flags needed to setup the renderer
|
|
||||||
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
|
||||||
if (command_line->HasSwitch(switches::kGuestInstanceID))
|
|
||||||
b.Set(options::kGuestInstanceID,
|
|
||||||
command_line->GetSwitchValueASCII(switches::kGuestInstanceID));
|
|
||||||
}
|
|
||||||
|
|
||||||
class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver {
|
class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver {
|
||||||
public:
|
public:
|
||||||
AtomSandboxedRenderFrameObserver(content::RenderFrame* render_frame,
|
AtomSandboxedRenderFrameObserver(content::RenderFrame* render_frame,
|
||||||
|
@ -152,10 +132,38 @@ class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver {
|
||||||
AtomSandboxedRendererClient::AtomSandboxedRendererClient() {
|
AtomSandboxedRendererClient::AtomSandboxedRendererClient() {
|
||||||
// Explicitly register electron's builtin modules.
|
// Explicitly register electron's builtin modules.
|
||||||
NodeBindings::RegisterBuiltinModules();
|
NodeBindings::RegisterBuiltinModules();
|
||||||
|
metrics_ = base::ProcessMetrics::CreateCurrentProcessMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomSandboxedRendererClient::~AtomSandboxedRendererClient() {}
|
AtomSandboxedRendererClient::~AtomSandboxedRendererClient() {}
|
||||||
|
|
||||||
|
void AtomSandboxedRendererClient::InitializeBindings(
|
||||||
|
v8::Local<v8::Object> binding,
|
||||||
|
v8::Local<v8::Context> context) {
|
||||||
|
auto* isolate = context->GetIsolate();
|
||||||
|
mate::Dictionary b(isolate, binding);
|
||||||
|
b.SetMethod("get", GetBinding);
|
||||||
|
b.SetMethod("createPreloadScript", CreatePreloadScript);
|
||||||
|
b.SetMethod("crash", AtomBindings::Crash);
|
||||||
|
b.SetMethod("hang", AtomBindings::Hang);
|
||||||
|
b.SetMethod("getArgv", GetArgv);
|
||||||
|
b.SetMethod("getExecPath", GetExecPath);
|
||||||
|
b.SetMethod("getPid", &base::GetCurrentProcId);
|
||||||
|
b.SetMethod("getResourcesPath", &NodeBindings::GetHelperResourcesPath);
|
||||||
|
b.SetMethod("getHeapStatistics", &AtomBindings::GetHeapStatistics);
|
||||||
|
b.SetMethod("getProcessMemoryInfo", &AtomBindings::GetProcessMemoryInfo);
|
||||||
|
b.SetMethod("getSystemMemoryInfo", &AtomBindings::GetSystemMemoryInfo);
|
||||||
|
b.SetMethod("getCPUUsage", base::Bind(&AtomBindings::GetCPUUsage,
|
||||||
|
base::Unretained(metrics_.get())));
|
||||||
|
b.SetMethod("getIOCounters", &AtomBindings::GetIOCounters);
|
||||||
|
|
||||||
|
// Pass in CLI flags needed to setup the renderer
|
||||||
|
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
||||||
|
if (command_line->HasSwitch(switches::kGuestInstanceID))
|
||||||
|
b.Set(options::kGuestInstanceID,
|
||||||
|
command_line->GetSwitchValueASCII(switches::kGuestInstanceID));
|
||||||
|
}
|
||||||
|
|
||||||
void AtomSandboxedRendererClient::RenderFrameCreated(
|
void AtomSandboxedRendererClient::RenderFrameCreated(
|
||||||
content::RenderFrame* render_frame) {
|
content::RenderFrame* render_frame) {
|
||||||
new AtomSandboxedRenderFrameObserver(render_frame, this);
|
new AtomSandboxedRenderFrameObserver(render_frame, this);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "atom/renderer/renderer_client_base.h"
|
#include "atom/renderer/renderer_client_base.h"
|
||||||
|
#include "base/process/process_metrics.h"
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
|
@ -16,6 +17,8 @@ class AtomSandboxedRendererClient : public RendererClientBase {
|
||||||
AtomSandboxedRendererClient();
|
AtomSandboxedRendererClient();
|
||||||
~AtomSandboxedRendererClient() override;
|
~AtomSandboxedRendererClient() override;
|
||||||
|
|
||||||
|
void InitializeBindings(v8::Local<v8::Object> binding,
|
||||||
|
v8::Local<v8::Context> context);
|
||||||
void InvokeIpcCallback(v8::Handle<v8::Context> context,
|
void InvokeIpcCallback(v8::Handle<v8::Context> context,
|
||||||
const std::string& callback_name,
|
const std::string& callback_name,
|
||||||
std::vector<v8::Handle<v8::Value>> args);
|
std::vector<v8::Handle<v8::Value>> args);
|
||||||
|
@ -30,6 +33,8 @@ class AtomSandboxedRendererClient : public RendererClientBase {
|
||||||
void RenderViewCreated(content::RenderView*) override;
|
void RenderViewCreated(content::RenderView*) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<base::ProcessMetrics> metrics_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AtomSandboxedRendererClient);
|
DISALLOW_COPY_AND_ASSIGN(AtomSandboxedRendererClient);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,19 @@ In sandboxed renderers the `process` object contains only a subset of the APIs:
|
||||||
- `getHeapStatistics()`
|
- `getHeapStatistics()`
|
||||||
- `getProcessMemoryInfo()`
|
- `getProcessMemoryInfo()`
|
||||||
- `getSystemMemoryInfo()`
|
- `getSystemMemoryInfo()`
|
||||||
|
- `getCPUUsage()`
|
||||||
|
- `getIOCounters()`
|
||||||
- `argv`
|
- `argv`
|
||||||
- `execPath`
|
- `execPath`
|
||||||
- `env`
|
- `env`
|
||||||
|
- `pid`
|
||||||
|
- `arch`
|
||||||
- `platform`
|
- `platform`
|
||||||
|
- `resourcesPath`
|
||||||
|
- `sandboxed`
|
||||||
|
- `type`
|
||||||
|
- `version`
|
||||||
|
- `versions`
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|
||||||
|
@ -68,6 +77,11 @@ instead of the `--no-deprecation` command line flag.
|
||||||
|
|
||||||
A `String` representing the path to the resources directory.
|
A `String` representing the path to the resources directory.
|
||||||
|
|
||||||
|
### `process.sandboxed`
|
||||||
|
|
||||||
|
A `Boolean`. When the renderer process is sandboxed, this property is `true`,
|
||||||
|
otherwise it is `undefined`.
|
||||||
|
|
||||||
### `process.throwDeprecation`
|
### `process.throwDeprecation`
|
||||||
|
|
||||||
A `Boolean` that controls whether or not deprecation warnings will be thrown as
|
A `Boolean` that controls whether or not deprecation warnings will be thrown as
|
||||||
|
|
|
@ -452,9 +452,14 @@ ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event.returnValue = {
|
event.returnValue = {
|
||||||
preloadSrc,
|
preloadSrc: preloadSrc,
|
||||||
preloadError,
|
preloadError: preloadError,
|
||||||
platform: process.platform,
|
process: {
|
||||||
env: process.env
|
arch: process.arch,
|
||||||
|
platform: process.platform,
|
||||||
|
env: process.env,
|
||||||
|
version: process.version,
|
||||||
|
versions: process.versions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -36,7 +36,7 @@ const loadedModules = new Map([
|
||||||
])
|
])
|
||||||
|
|
||||||
const {
|
const {
|
||||||
preloadSrc, preloadError, platform, env
|
preloadSrc, preloadError, process: processProps
|
||||||
} = electron.ipcRenderer.sendSync('ELECTRON_BROWSER_SANDBOX_LOAD')
|
} = electron.ipcRenderer.sendSync('ELECTRON_BROWSER_SANDBOX_LOAD')
|
||||||
|
|
||||||
require('../renderer/web-frame-init')()
|
require('../renderer/web-frame-init')()
|
||||||
|
@ -49,10 +49,16 @@ preloadProcess.hang = () => binding.hang()
|
||||||
preloadProcess.getHeapStatistics = () => binding.getHeapStatistics()
|
preloadProcess.getHeapStatistics = () => binding.getHeapStatistics()
|
||||||
preloadProcess.getProcessMemoryInfo = () => binding.getProcessMemoryInfo()
|
preloadProcess.getProcessMemoryInfo = () => binding.getProcessMemoryInfo()
|
||||||
preloadProcess.getSystemMemoryInfo = () => binding.getSystemMemoryInfo()
|
preloadProcess.getSystemMemoryInfo = () => binding.getSystemMemoryInfo()
|
||||||
|
preloadProcess.getCPUUsage = () => binding.getCPUUsage()
|
||||||
|
preloadProcess.getIOCounters = () => binding.getIOCounters()
|
||||||
preloadProcess.argv = process.argv = binding.getArgv()
|
preloadProcess.argv = process.argv = binding.getArgv()
|
||||||
preloadProcess.execPath = process.execPath = binding.getExecPath()
|
preloadProcess.execPath = process.execPath = binding.getExecPath()
|
||||||
preloadProcess.platform = process.platform = platform
|
preloadProcess.pid = process.pid = binding.getPid()
|
||||||
preloadProcess.env = process.env = env
|
preloadProcess.resourcesPath = binding.getResourcesPath()
|
||||||
|
preloadProcess.sandboxed = true
|
||||||
|
preloadProcess.type = 'renderer'
|
||||||
|
Object.assign(preloadProcess, processProps)
|
||||||
|
Object.assign(process, processProps)
|
||||||
|
|
||||||
process.on('exit', () => preloadProcess.emit('exit'))
|
process.on('exit', () => preloadProcess.emit('exit'))
|
||||||
|
|
||||||
|
|
|
@ -1617,9 +1617,16 @@ describe('BrowserWindow module', () => {
|
||||||
|
|
||||||
it('validates process APIs access in sandboxed renderer', (done) => {
|
it('validates process APIs access in sandboxed renderer', (done) => {
|
||||||
ipcMain.once('answer', function (event, test) {
|
ipcMain.once('answer', function (event, test) {
|
||||||
|
assert.equal(test.pid, w.webContents.getOSProcessId())
|
||||||
|
assert.equal(test.arch, remote.process.arch)
|
||||||
assert.equal(test.platform, remote.process.platform)
|
assert.equal(test.platform, remote.process.platform)
|
||||||
assert.deepEqual(test.env, remote.process.env)
|
assert.deepEqual(test.env, remote.process.env)
|
||||||
assert.equal(test.execPath, remote.process.helperExecPath)
|
assert.equal(test.execPath, remote.process.helperExecPath)
|
||||||
|
assert.equal(test.resourcesPath, remote.process.resourcesPath)
|
||||||
|
assert.equal(test.sandboxed, true)
|
||||||
|
assert.equal(test.type, 'renderer')
|
||||||
|
assert.equal(test.version, remote.process.version)
|
||||||
|
assert.deepEqual(test.versions, remote.process.versions)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
remote.process.env.sandboxmain = 'foo'
|
remote.process.env.sandboxmain = 'foo'
|
||||||
|
|
9
spec/fixtures/module/preload-sandbox.js
vendored
9
spec/fixtures/module/preload-sandbox.js
vendored
|
@ -11,7 +11,14 @@
|
||||||
window.test = {
|
window.test = {
|
||||||
env: process.env,
|
env: process.env,
|
||||||
execPath: process.execPath,
|
execPath: process.execPath,
|
||||||
platform: process.platform
|
pid: process.pid,
|
||||||
|
arch: process.arch,
|
||||||
|
platform: process.platform,
|
||||||
|
resourcesPath: process.resourcesPath,
|
||||||
|
sandboxed: process.sandboxed,
|
||||||
|
type: process.type,
|
||||||
|
version: process.version,
|
||||||
|
versions: process.versions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (location.href !== 'about:blank') {
|
} else if (location.href !== 'about:blank') {
|
||||||
|
|
Loading…
Reference in a new issue