8000 Backport #12877 to 2.0 by tarruda · Pull Request #13021 · electron/electron · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Backport #12877 to 2.0 #13021

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Backport #12877 to 2.0 #13021

wants to merge 1 commit into from

Conversation

tarruda
Copy link
Contributor
@tarruda tarruda commented May 21, 2018

@tarruda tarruda requested review from miniak, MarshallOfSound and a team May 21, 2018 14:08
Copy link
Member
@jkleinsc jkleinsc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like builds are failing because /lib/renderer/web-frame-init.js doesn't exist in the 2-0-x branch.

value: webContentsId
})

require('../renderer/web-frame-init')()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tarruda looks like this file doesn't exist in the 2-0-x branch

Copy link
Member
@ckerr ckerr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event, preloadPath) {

I hate to be "that guy" but this seems more like a new feature that happens to also fix a bug.

I like both the feature and the fix, but the feature doesn't seem appropriate for the bugfix-only 2-0-x series -- I'd prefer to see a less intrusive patch.

@tarruda tarruda force-pushed the backport-12877-to-2-0-x branch from a75c5df to 4c8ae6c Compare May 21, 2018 19:26
@tarruda
Copy link
Contributor Author
tarruda commented May 21, 2018

I hate to be "that guy" but this seems more like a new feature that happens to also fix a bug.

I like both the feature and the fix, but the feature doesn't seem appropriate for the bugfix-only 2-0-x series -- I'd prefer to see a less intrusive patch.

I could adapt the RPC call to remove the parts that are not available in 2.0, such as env, and also ensure that sandboxed_renderer/init.js doesn't expose any extra APIs (such as events and process.env).

I see no way to do this without adding the new RPC

@tarruda
Copy link
Contributor Author
tarruda commented May 21, 2018

@ckerr I've added a fixup commit that reduces the amount of public API changes.

@tarruda tarruda force-pushed the backport-12877-to-2-0-x branch from f950825 to b946f46 Compare May 21, 2018 19:39
@tarruda
Copy link
Contributor Author
tarruda commented May 21, 2018

@ckerr just to be clear, is the new RPC handler what you are seeing as a new feature? If so, remember that the RPC methods starting with uppercase are internal to electron, and not part of the public API.

@tarruda tarruda force-pushed the backport-12877-to-2-0-x branch from b946f46 to e51cf36 Compare May 21, 2018 21:15
@miniak
Copy link
Contributor
miniak commented May 21, 2018

If we are backporting this to 2.0, why not 1.8 as well?

Copy link
Member
@ckerr ckerr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments inline

return loadedModules.get(module)
}
if (remoteModules.has(module)) {
return require(module)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me what the criteria is for putting a module in loadedModules vs remoteModules?

If Node caches require(foo) calls s.t. if (remoteModules.has(module)) return require(modules) is cheap, why preload anything at all in loadedModules?

OTOH if this setup exists because require(foo) still has some nonzero cost, why not make loadedModules a lazy-populated map that caches previous require(foo) calls?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Node caches require(foo) calls s.t. if (remoteModules.has(module)) return require(modules) is cheap, why preload anything at all in loadedModules?

This is a browserify require and browserify can only bundle modules specified as string literals.

OTOH if this setup exists because require(foo) still has some nonzero cost, why not make loadedModules a lazy-populated map that caches previous require(foo) calls?

As I said above, it is not about the cost, but I can change it so it returns from loadedModules directly

Copy link
Member
@ckerr ckerr May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion on whether to lazy-cache these in loadedModules. My uninformed guess is that it would be faster than re-requiring a module but I don't know how often we'll hit that use case.

However, I'm still interested in understanding this patch better -- what's the criteria for putting a module in loadedModules vs remoteModules? That is, how to decide which modules to preload and which to lazy-load?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remoteModules are modules which are proxies to node.js modules in the browser process. We do this because the browserify-provided shims for some modules
(child_process, os, fs and path) are not ideal for Electron apps.

Here's how browserify is invoked by Electron build system: https://github.com/electron/electron/blob/master/electron.gyp#L513-L519

These arguments provide replacements for browserify shims, but they also cause electron's remote module to be loaded, which is what we want to avoid in early startup for sandbox

loadedModules are browserify shims that are already available in the renderer process, so it is possible for an Electron app to create a preload bundle and pass -e to exclude from their own bundle, and the require will work since it is provided by loadedModules.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these things should have been discussed in the original PR. this is a backport.

@@ -297,10 +297,13 @@ exports.getCurrentWebContents = () => {

const CONTEXT_ARG = '--context-id='
let initialContext = process.argv.find(arg => arg.startsWith(CONTEXT_ARG))
if (initialContext) {
if (process.webContentsId) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor) if this clause is true then we don't need to look for CONTEXT_ARG in argv at all, so that work should go into an } else { ... block after this block

platform: process.platform,
execPath: process.execPath
}
})
Copy link
Member
@ckerr ckerr May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @miniak and @MarshallOfSound that this is a "read any file plz" API. The consensus in the master PR seems to have been "address that in a followup change" but that's not been written yet so what we're doing here is proposing only the risky bits for a bugfix-only stable release.

I see the value in fixing #12316 for sandboxed mode, but this seems like a risky fix.

Maybe we should wait for this to finish baking in master, then backport it to a future 2-0-x release

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said in previous comments, there's no new risk being introduced here, because renderers currently have unfiltered access to the full range of Electron IPC messages. That means if some code can do IPC, it can do anything such as loading modules remotely and calling arbitrary functions.

Even if I make this change now it won't have any benefit for the reason stated above: Untrusted code can still invoke any function remotely. OTOH I will have to test more scenarios since taking the preloadPath from webPreferences is not guaranteed to work for every webContents (think of windows created with window.open).

This is why I wanted to make another PR for changing the preload path behavior: It is a refactoring change that doesn't have much to do with the bugfix being addressed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case it was not clear, the "read any file plz" API is already available through the IPC messages that implement electron.remote (as well as "write/delete any file plz" APIs, since it is all available through electron.remote.fs)

@tarruda tarruda force-pushed the backport-12877-to-2-0-x branch 2 times, most recently from 689da7b to 26ea586 Compare May 23, 2018 15:04
@tarruda tarruda force-pushed the backport-12877-to-2-0-x branch 2 times, most recently from cde93d6 to 41167ad Compare May 25, 2018 11:42
Use a single synchronous IPC call to retrieve data required by early
sandbox scripts. This has two purposes:

- Optimize preload script initialization by:
  - Using one synchronous IPC call to retrieve preload script,
  webContentsId (more on that later), process.{platform,execPath,env}
  - Lazy loading as many modules as possible.
- Fix #12316 for sandbox. @MarshallOfSound addressed the issue in
  #12342, but it was still present in sandbox mode. By loading
  webContentsId very early and skipping 
6D40
remote module at early
  startup, we fix it for sandbox.
@tarruda tarruda force-pushed the backport-12877-to-2-0-x branch from 41167ad to 931cb29 Compare May 25, 2018 12:15
@emmkimme
Copy link
Contributor

Hi,

sorry, I come very late in this discussion but I would like to raise 2 points

1 - Performance impact
previously the renderer process was in charge to load the preload file, so whatever the size of the preload, master process was not impacted. Here at each window creation, master process will read a file synchronously, I'm afraid it could impact the whole application performance.

2 - Affinity (one process hosting several windows)
Most of the webpreferences options are provided through the process commandline : backgroundcolor, nodeintegration, preload, sandbox, nativewindow....
It introduces issues when the renderer host several windows, no way to have different background (#12211), a different preload... per windows. It always applies args of the process, so the webPreferences of the window which triggers the creation of the process.
Why do not put in place a more general mechanism which is to provide the webPreferences through IPC to the right instance. Not just the preload. This way it will cover all issues.
Keep as args, options that are relevant at renderer process level like sandbox, nodeintegration...

Regards

@MarshallOfSound
Copy link
Member

@emmkimme

  1. We shouldn't have fs operations in a sandboxed renderer, it's effectively punching a hole through the sandbox

  2. As far as I am aware we do not even officially support Affinity, it has several issues that go well beyond the scope of this PR. I was under the impression that API was flagged as experimental, I have raised a PR to do so.

@emmkimme
Copy link
Contributor
emmkimme commented Jun 19, 2018

@MarshallOfSound

  1. Fully agree for fs, but is the security concern to prevent all file system access from the renderer, covers native code as well ?
    Because we can imagine a C++ api like 13032 in charge to load and eval the preload script.
    Else I'm afraid, currently, I have no other option than yours. But loading a preload file (which could be important) and send the whole content through the IPC, all in synchronous way... :,(
  2. Affinity, this feature is used in our product and allows to create hundred of windows with limited impact on CPU/Memory for the user. Experimental perhaps, practical surely ;-)

As far as I know, Chromium can decide to host several windows in the same process: site strategy, js co-location, ... move away from process args could open Electron to new kind of smart strategies.

@MarshallOfSound
Copy link
Member

allows to create hundred of windows

I'd be interested (somewhere else so not to flood this pr) to know your settings and usage of that API, afaik it causes noticeable memory leaks and is very incompatible with lots of node API's and logic that assume single-node-per-process model (E.g. native modules).

@ckerr
Copy link
Member
ckerr commented Jul 22, 2018

Going through the 2.0.x project board and came across this. My apologies for letting it sit as long as it did.

At this point, I think it's better to focus on the 3-0-x branch

@ckerr ckerr closed this Jul 22, 2018
@MarshallOfSound MarshallOfSound deleted the backport-12877-to-2-0-x branch August 22, 2018 17:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants
0