Blink-in-JavaScript

876 views
Skip to first unread message

Kentaro Hara

unread,
Jan 16, 2014, 10:42:29 PM1/16/14
to blink-dev, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org, aba...@chromium.org
Hi

I'm planning to implement a mechanism to enable developers to write Blink features in JavaScript (a.k.a. Blink-in-JavaScript).

- An example CL to move C++ implementation of Window.atob()/btoa() to JavaScript: https://codereview.chromium.org/138223002/

The basic idea of Blink-in-JavaScript is that we want to implement only the core part of Blink in C++ and implement other parts in JavaScript on top of existing, web-exposed JavaScript APIs. By implementing more things in JavaScript, we can improve security, maintainability and programmability of Blink. Blink-in-JavaScript is executed in the same security model as content scripts of Chrome extensions. For more details, look at the design document.

At the moment, I'm thinking about Document.execCommand() as a first target of Blink-in-JavaScript. Currently Document.execCommand() complicates the architecture of editing/, so we want to factor out the complexity from C++. Most editing commands of Document.execCommand() can be implemented on top of web-exposed JavaScript APIs. The editing team already started rewriting Document.execCommand() in JavaScript.

I'd be happy if you could tell me more use cases and improve the design. Comments are appreciated!

--
Kentaro Hara, Tokyo, Japan

Chris Evans

unread,
Jan 16, 2014, 10:45:49 PM1/16/14
to Kentaro Hara, blink-dev, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org, aba...@chromium.org
On Thu, Jan 16, 2014 at 7:42 PM, Kentaro Hara <har...@chromium.org> wrote:
Hi

I'm planning to implement a mechanism to enable developers to write Blink features in JavaScript (a.k.a. Blink-in-JavaScript).

- An example CL to move C++ implementation of Window.atob()/btoa() to JavaScript: https://codereview.chromium.org/138223002/

The basic idea of Blink-in-JavaScript is that we want to implement only the core part of Blink in C++ and implement other parts in JavaScript on top of existing, web-exposed JavaScript APIs. By implementing more things in JavaScript, we can improve security, maintainability and programmability of Blink. Blink-in-JavaScript is executed in the same security model as content scripts of Chrome extensions. For more details, look at the design document.

At the moment, I'm thinking about Document.execCommand() as a first target of Blink-in-JavaScript.

Oh, cool, that's exciting. This area has historically been quite buggy so hoisting it into JavaScript would be great for security.


Cheers
Chris
 
Currently Document.execCommand() complicates the architecture of editing/, so we want to factor out the complexity from C++. Most editing commands of Document.execCommand() can be implemented on top of web-exposed JavaScript APIs. The editing team already started rewriting Document.execCommand() in JavaScript.

I'd be happy if you could tell me more use cases and improve the design. Comments are appreciated!

--
Kentaro Hara, Tokyo, Japan

To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.

Adam Barth

unread,
Jan 16, 2014, 11:23:01 PM1/16/14
to Kentaro Hara, blink-dev, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org
If you want a challenge problem, you might try to implement XSLTProcessor using Blink-in-JavaScript.  You'll probably need to compile libxslt and libxml using Emscripten and load that into the isolated world.  Bonus points if you implement the XSLT processing directive using Blink-in-JavaScript.  :)

Adam



On Thu, Jan 16, 2014 at 7:42 PM, Kentaro Hara <har...@chromium.org> wrote:

Rik Cabanier

unread,
Jan 16, 2014, 11:49:57 PM1/16/14
to Adam Barth, Kentaro Hara, blink-dev, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org
On Thu, Jan 16, 2014 at 8:23 PM, Adam Barth <aba...@chromium.org> wrote:
If you want a challenge problem, you might try to implement XSLTProcessor using Blink-in-JavaScript.  You'll probably need to compile libxslt and libxml using Emscripten and load that into the isolated world.  Bonus points if you implement the XSLT processing directive using Blink-in-JavaScript.  :)

Implementing a xslt processor in JS will likely be a large javascript library.

Are there plans to build in some sort of deferred initialization so the browser doesn't have to parse all that code for every document? (From the design document, it seems like that could already be the case.)
 

On Thu, Jan 16, 2014 at 7:42 PM, Kentaro Hara <har...@chromium.org> wrote:
Hi

I'm planning to implement a mechanism to enable developers to write Blink features in JavaScript (a.k.a. Blink-in-JavaScript).

- An example CL to move C++ implementation of Window.atob()/btoa() to JavaScript: https://codereview.chromium.org/138223002/

The basic idea of Blink-in-JavaScript is that we want to implement only the core part of Blink in C++ and implement other parts in JavaScript on top of existing, web-exposed JavaScript APIs. By implementing more things in JavaScript, we can improve security, maintainability and programmability of Blink. Blink-in-JavaScript is executed in the same security model as content scripts of Chrome extensions. For more details, look at the design document.

At the moment, I'm thinking about Document.execCommand() as a first target of Blink-in-JavaScript. Currently Document.execCommand() complicates the architecture of editing/, so we want to factor out the complexity from C++. Most editing commands of Document.execCommand() can be implemented on top of web-exposed JavaScript APIs. The editing team already started rewriting Document.execCommand() in JavaScript.

I'd be happy if you could tell me more use cases and improve the design. Comments are appreciated!

--
Kentaro Hara, Tokyo, Japan

Kentaro Hara

unread,
Jan 16, 2014, 11:58:17 PM1/16/14
to Rik Cabanier, Adam Barth, blink-dev, Mads Sig Ager, bak, Erik Arvidsson, yosin
Are there plans to build in some sort of deferred initialization so the browser doesn't have to parse all that code for every document? (From the design document, it seems like that could already be the case.)

Blink-in-JavaScript is compiled lazily on a class-by-class basis (A class is a unit installed by an installClass() method. See an example in the document). At the first time user's JavaScript accesses window.atob(), WindowBase64.js is compiled and the compiled code is cached. At the second time user's JavaScript accesses window.atob(), the compiled code is used.

Adam Barth

unread,
Jan 17, 2014, 12:17:31 AM1/17/14
to Kentaro Hara, Rik Cabanier, blink-dev, Mads Sig Ager, bak, Erik Arvidsson, yosin
On Thu, Jan 16, 2014 at 8:58 PM, Kentaro Hara <har...@chromium.org> wrote:
Are there plans to build in some sort of deferred initialization so the browser doesn't have to parse all that code for every document? (From the design document, it seems like that could already be the case.)

Blink-in-JavaScript is compiled lazily on a class-by-class basis (A class is a unit installed by an installClass() method. See an example in the document). At the first time user's JavaScript accesses window.atob(), WindowBase64.js is compiled and the compiled code is cached. At the second time user's JavaScript accesses window.atob(), the compiled code is used.

In my dream world, we'd even lazily load libxslt.js over the network the first time it's used.

Adam

dca...@chromium.org

unread,
Jan 17, 2014, 3:54:00 AM1/17/14
to blin...@chromium.org, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org, aba...@chromium.org
I'd argue that you'd be introducing potential security problems.

It's not true that we do not leak objects between worlds.  We don't do it intentionally, but bugs are bound to creep in, as they have in the past.  Currently, though, those bugs are exposed only to user extensions, whereas what you propose could be executed by any js on the web, making the bugs significantly more serious/exploitable.

I think you should consider the following counterproposal to mitigate the security risk:
  1. install a native callback for the function, as we do now, but make that function be a generic one (called lazyInstallProperty or something) with a data argument that is a the name of a script to execute
  2. on first execution of that function, do this
    • compile the js needed for property
    • overwrite the old property with the new property and run the function again
This has a number of advantages over what you propose:
  1. no wrapping required
  2. no security risks above what any user can already do
  3. slightly faster than what you propose, although that's kind of irrelevant
  4. no need to reason about what is happening between isolated worlds
  5. unused functions would be garbage collected instead of kept alive forever in the blinkjs cache
v8's internal compile cache should take of not duplicating the code everywhere, so that's not an issue

The only disadvantage I can think of is that the people writing the js have to be extremely careful not to use global variables on the page, which is very hard to do in js.  We'd probably need to have support from v8 to ensure that.  Emscripten'd code could be trivially made safe.

Lastly, I know you mention memory bloat and speed degradation several times, but this can't be stressed enough.  There will be very significant blowups.  You should seriously consider not porting anything to javascript that might commonly run in a mobile environment.

Mads Sig Ager

unread,
Jan 17, 2014, 4:16:31 AM1/17/14
to dca...@chromium.org, blink-dev, b...@chromium.org, Erik Arvidsson, yo...@chromium.org, aba...@chromium.org
On Fri, Jan 17, 2014 at 9:54 AM, <dca...@chromium.org> wrote:
I'd argue that you'd be introducing potential security problems.

It's not true that we do not leak objects between worlds.  We don't do it intentionally, but bugs are bound to creep in, as they have in the past.  Currently, though, those bugs are exposed only to user extensions, whereas what you propose could be executed by any js on the web, making the bugs significantly more serious/exploitable.

I think you should consider the following counterproposal to mitigate the security risk:
  1. install a native callback for the function, as we do now, but make that function be a generic one (called lazyInstallProperty or something) with a data argument that is a the name of a script to execute
  2. on first execution of that function, do this
    • compile the js needed for property
    • overwrite the old property with the new property and run the function again
This has a number of advantages over what you propose:
  1. no wrapping required
  2. no security risks above what any user can already do
  3. slightly faster than what you propose, although that's kind of irrelevant
  4. no need to reason about what is happening between isolated worlds
  5. unused functions would be garbage collected instead of kept alive forever in the blinkjs cache
v8's internal compile cache should take of not duplicating the code everywhere, so that's not an issue

The only disadvantage I can think of is that the people writing the js have to be extremely careful not to use global variables on the page, which is very hard to do in js.  We'd probably need to have support from v8 to ensure that.  Emscripten'd code could be trivially made safe.

This is something that the V8 team has been struggling with a lot. Writing JavaScript code that will be run in the users context in a safe way is extremely difficult. Parts of the V8 libraries are written in JavaScript and it has been a huge pain. The code that we have ended up with is not exactly simple and easy to maintain. I would strongly discourage going down the route of having JS code running in the user context to implement Blink features. JavaScript as a language is just too hard to control to have any confidence that you are not messing something up or leaking information. Have a look at the V8 "JavaScript" files to see where the path of implementing library routines in JS took us in V8. :-(

I don't have enough experience with the content script security model to chime in on whether that is secure enough as an alternative or not.

Aaron Boodman

unread,
Jan 17, 2014, 4:30:46 AM1/17/14
to dca...@chromium.org, blink-dev, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org, aba...@chromium.org
On Fri, Jan 17, 2014 at 12:54 AM, <dca...@chromium.org> wrote:
I think you should consider the following counterproposal to mitigate the security risk:
  1. install a native callback for the function, as we do now, but make that function be a generic one (called lazyInstallProperty or something) with a data argument that is a the name of a script to execute
  2. on first execution of that function, do this
    • compile the js needed for property
    • overwrite the old property with the new property and run the function again

I don't see how this helps anything. Once you replace the C++ native callback with a JS function, you have a direct bridge between privileged and unprivileged code.
 
- a

Kentaro Hara

unread,
Jan 17, 2014, 4:32:18 AM1/17/14
to Dan Carney, blink-dev, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, Yoshifumi Inoue, aba...@chromium.org
Thanks Dan!

I'd argue that you'd be introducing potential security problems. 
 
It's not true that we do not leak objects between worlds.  We don't do it intentionally, but bugs are bound to creep in, as they have in the past.  Currently, though, those bugs are exposed only to user extensions, whereas what you propose could be executed by any js on the web, making the bugs significantly more serious/exploitable.

This is a valid concern. I think we've already fixed all object leaks between isolated worlds, and we should add more ASSERTs in order not to produce new leaks.

whereas what you propose could be executed by any js on the web, making the bugs significantly more serious/exploitable.

This is not quite true. Blink-in-JavaScript executes only JavaScripts that are developed and reviewed by Blink developers. Blink-in-JavaScript is not a thing that executes any untrusted JavaScripts on the web.


I think you should consider the following counterproposal to mitigate the security risk: 
 
1. install a native callback for the function, as we do now, but make that function be a generic one (called lazyInstallProperty or something) with a data argument that is a the name of a script to execute
2. on first execution of that function, do this
- compile the js needed for property
- overwrite the old property with the new property and run the function again 
 
This has a number of advantages over what you propose:
1. no wrapping required
2. no security risks above what any user can already do
3. slightly faster than what you propose, although that's kind of irrelevant
4. no need to reason about what is happening between isolated worlds
5. unused functions would be garbage collected instead of kept alive forever in the blinkjs cache

I don't fully understand what you're proposing. It seems to me that your proposal just removes isolated worlds from my proposal.

If I'm understanding your proposal correctly, in your proposal Blink-in-JavaScript and user's script will run in the same isolated world. Then, for example, what happens if user's script hijacks String.prototype.substr, and Blink-in-JavaScript calls String.prototype.substr with strings that should not be exposed to outside?

// user's script
String.prototype.substr = function (position, length) {
  console.log(this);
}

// Blink-in-JavaScript
installClass("HTMLInputElement", function() {
  function someMethod() {
    ...;
    this.filename_.substr(0, 2);  // The filename of the input element should not be exposed to outside.
  }
});

Similar problems can happen if we don't re-wrap DOM wrappers between Blink-in-JavaScript and user's script.

In general, in order to guarantee the security of Blink-in-JavaScript, we need to guarantee that JavaScript objects in Blink-in-JavaScript are never accessible from user's scripts. This means that we need to use a dedicated isolated world for Blink-in-JavaScript.

dca...@chromium.org

unread,
Jan 17, 2014, 4:42:38 AM1/17/14
to blin...@chromium.org, dca...@chromium.org, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org, aba...@chromium.org
how is pure js privileged?  If you want blinkjs to have callbacks into privileged c++ functions, sure, but that didn't seem to be the gist of haraken's proposal, and even if it were, we could use symbols to make those callbacks inaccessible from external callers.

dca...@chromium.org

unread,
Jan 17, 2014, 4:49:47 AM1/17/14
to blin...@chromium.org, Dan Carney, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, Yoshifumi Inoue, aba...@chromium.org

This is not quite true. Blink-in-JavaScript executes only JavaScripts that are developed and reviewed by Blink developers. Blink-in-JavaScript is not a thing that executes any untrusted JavaScripts on the web.

I'm not suggesting that the blinkjs code would be problematic, but that you can now execute js in an isolated world from any page, and if there happened to be an isolated world leak somewhere, it might become exploitable indirectly by executing code that calls atob()
 
If I'm understanding your proposal correctly, in your proposal Blink-in-JavaScript and user's script will run in the same isolated world. Then, for example, what happens if user's script hijacks String.prototype.substr, and Blink-in-JavaScript calls String.prototype.substr with strings that should not be exposed to outside?

you would have to use internally symbolized versions of all such functions.  it would suck. i know, that's what Mads is talking about and it's why i suggested my proposal wouldn't work.  chrome extensions have the same problem.  v8 has the same problem internally.

I just consider the security risk to be much higher than you suggest and thus a bad idea

Aaron Boodman

unread,
Jan 17, 2014, 4:49:13 AM1/17/14
to dca...@chromium.org, blink-dev, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org, aba...@chromium.org
From the doc: "Blink-in-JavaScript can have internal information of Blink which must not be exposed to user’s JavaScript.".

In general, there's very little that's interesting you can do in pure javascript. For example, you can implement atob, but you can't implement execCommand(). As soon as you expose some private function to BlinkInJS in order to make execCommand() possible, then you're back to the situation of not wanting to leak that function to user JS. You can try to hide access to the name via various mechanisms, but it is hard to keep that kind of approach correct as the complexity of the codebase scales.

Stepping back, I guess I'm not sure what security risk you are trying to guard against with your proposal if you weren't expecting the BlinkInJS to have any increased privileges.

- a

dca...@chromium.org

unread,
Jan 17, 2014, 5:08:20 AM1/17/14
to blin...@chromium.org, dca...@chromium.org, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org, aba...@chromium.org
Stepping back, I guess I'm not sure what security risk you are trying to guard against with your proposal if you weren't expecting the BlinkInJS to have any increased privileges.

Calling into an isolated world is an edge case that receives very little testing and does not have sufficient guards against cross context leaks.  BlinkInJs would allow someone to call code which, even if only executing dom functions on isolated worlds, could potentially leak a wrapper from some other world.  If that world happened to be a main world that it not your own, it would be a security leak.  I'm not saying it's likely to happen, just that it adds a lot more pressure on isolated worlds to be secure than they've had before.  If we had a way to guarantee their security, then they would certainly be better than what I proposed.

Robin Berjon

unread,
Jan 17, 2014, 5:16:18 AM1/17/14
to Adam Barth, Kentaro Hara, blink-dev, Mads Sig Ager, b...@chromium.org, Erik Arvidsson, yo...@chromium.org
On 17/01/2014 05:23 , Adam Barth wrote:
> If you want a challenge problem, you might try to
> implement XSLTProcessor using Blink-in-JavaScript. You'll probably need
> to compile libxslt and libxml using Emscripten and load that into the
> isolated world.

That sounds awfully heavy and complicated. If someone wants to try their
hand at this, I reckon http://frameless.io/xslt/ might be a good place
to start.

--
Robin Berjon - http://berjon.com/ - @robinberjon

Kentaro Hara

unread,
Jan 17, 2014, 5:18:39 AM1/17/14
to Dan Carney, blink-dev, Mads Sig Ager, bak, Erik Arvidsson, Yoshifumi Inoue, aba...@chromium.org
Calling into an isolated world is an edge case that receives very little testing and does not have sufficient guards against cross context leaks.  BlinkInJs would allow someone to call code which, even if only executing dom functions on isolated worlds, could potentially leak a wrapper from some other world.  If that world happened to be a main world that it not your own, it would be a security leak.  I'm not saying it's likely to happen, just that it adds a lot more pressure on isolated worlds to be secure than they've had before.

Your concern is valid and I agree with you. However, I think that the right thing to do is to fix security issues around isolated worlds (whether we have Blink-in-JavaScript or not).


On Fri, Jan 17, 2014 at 7:08 PM, <dca...@chromium.org> wrote:
Stepping back, I guess I'm not sure what security risk you are trying to guard against with your proposal if you weren't expecting the BlinkInJS to have any increased privileges.

Calling into an isolated world is an edge case that receives very little testing and does not have sufficient guards against cross context leaks.  BlinkInJs would allow someone to call code which, even if only executing dom functions on isolated worlds, could potentially leak a wrapper from some other world.  If that world happened to be a main world that it not your own, it would be a security leak.  I'm not saying it's likely to happen, just that it adds a lot more pressure on isolated worlds to be secure than they've had before.  If we had a way to guarantee their security, then they would certainly be better than what I proposed.



Aaron Boodman

unread,
Jan 17, 2014, 5:25:39 AM1/17/14
to Mads Sig Ager, dca...@chromium.org, blink-dev, b...@chromium.org, Erik Arvidsson, yo...@chromium.org, aba...@chromium.org
On Fri, Jan 17, 2014 at 1:16 AM, Mads Sig Ager <ag...@chromium.org> wrote:
I don't have enough experience with the content script security model to chime in on whether that is secure enough as an alternative or not.
 
I can't speak to whether this idea it is practical or good from Blink's point of view, but I think it's fun, and have thought down these roads in the past myself.

I have two thoughts on the design:

1) Back when we introduced content scripts, we had the idea that there could be low-level CHECK's that code from one isolated world could never touch objects from another world. I'm not sure if it was ever implemented though. If that existed, then I think it would increase confidence in relying on isolated worlds for security.

2) There is a generalization of the your idea that would both increase its flexibility and perhaps allay security concerns, particularly if the CHECKs in (1) are not possible for some reason:

The only reason you need isolated worlds at all is because you want to be able to pass DOM wrappers between user JavaScript and BlinkInJavaScript. If it weren't for this fact, then you wouldn't need isolated worlds because the only other types you propose that the C++ bindings layer would allow through are primitives. Your bindings layer is providing some isolation, but it only works for primitives.

Instead of relying on isolated worlds for the complex objects case, you could teach the C++ bindings layer to do isolation for them too. Basically for every object and function implemented in BlinkInJS exposed to user JS, there would be a C++ proxy representing the target object. When user JS tried to access a property of the target, or call a function, the C++ proxy would actually receive the access, delegate to the target object, and marshall values back and forth. The proxies would be recursive, so this would work for arbitrary data structures. As before, you could just allow primitive JS values through, so there would not be serialization overhead.

The same would of course work in reverse, when user JS wants to pass a complex objects to BlinkInJS.

DOM objects would come along with this design for free since they already have JS wrappers.

- a

Kentaro Hara

unread,
Jan 17, 2014, 5:48:24 AM1/17/14
to Aaron Boodman, Mads Sig Ager, Dan Carney, blink-dev, bak, Erik Arvidsson, Yoshifumi Inoue, aba...@chromium.org
Thanks aaron!

1) Back when we introduced content scripts, we had the idea that there could be low-level CHECK's that code from one isolated world could never touch objects from another world. I'm not sure if it was ever implemented though. If that existed, then I think it would increase confidence in relying on isolated worlds for security.

Yes, this would be the best. It's possible to insert the check, but it's never trivial to insert the check without adding any performance overhead. We have to insert the check to all points where we return DOM wrappers to JavaScript. But it's worth considering.


2) There is a generalization of the your idea that would both increase its flexibility and perhaps allay security concerns, particularly if the CHECKs in (1) are not possible for some reason: 
 
The only reason you need isolated worlds at all is because you want to be able to pass DOM wrappers between user JavaScript and BlinkInJavaScript. If it weren't for this fact, then you wouldn't need isolated worlds because the only other types you propose that the C++ bindings layer would allow through are primitives. Your bindings layer is providing some isolation, but it only works for primitives.

Right. To support primitive values, we just need to isolate contexts. To support DOM wrappers, we need to introduce isolated worlds in addition.

Instead of relying on isolated worlds for the complex objects case, you could teach the C++ bindings layer to do isolation for them too. Basically for every object and function implemented in BlinkInJS exposed to user JS, there would be a C++ proxy representing the target object. When user JS tried to access a property of the target, or call a function, the C++ proxy would actually receive the access, delegate to the target object, and marshall values back and forth. The proxies would be recursive, so this would work for arbitrary data structures. As before, you could just allow primitive JS values through, so there would not be serialization overhead.

This sounds interesting, but it seems to me that the C++ proxy objects are doing almost the same thing as isolated worlds. I agree that the C++ proxy objects will allow us to overcome the security concerns of Blink-in-JavaScript even if we have bugs in the current implementation of isolated worlds, but it seems that it is saying "Because the current isolated worlds might have bugs, let's implement another kind of isolated world (i.e., C++ proxy objects) for Blink-in-JavaScript". Then, I still think that we should try our best to harden security of the current isolated worlds instead of introducing another kind of isolated world. (Sorry if I'm missing your point.)

Jochen Eisinger

unread,
Jan 17, 2014, 6:53:38 AM1/17/14
to Kentaro Hara, Aaron Boodman, Mads Sig Ager, Dan Carney, blink-dev, bak, Erik Arvidsson, Yoshifumi Inoue, aba...@chromium.org
On Fri, Jan 17, 2014 at 11:48 AM, Kentaro Hara <har...@chromium.org> wrote:
Thanks aaron!

1) Back when we introduced content scripts, we had the idea that there could be low-level CHECK's that code from one isolated world could never touch objects from another world. I'm not sure if it was ever implemented though. If that existed, then I think it would increase confidence in relying on isolated worlds for security.

Yes, this would be the best. It's possible to insert the check, but it's never trivial to insert the check without adding any performance overhead. We have to insert the check to all points where we return DOM wrappers to JavaScript. But it's worth considering.

We added a check to the dom wrapper map that, and it constantly triggered, however, we didn't find the root cause, so the check was reverted again :-/

I guess it's safe to assume that right now, objects leak more or less freely between worlds.

best
-jochen

Erik Arvidsson

unread,
Jan 17, 2014, 11:01:57 AM1/17/14
to Kentaro Hara, Aaron Boodman, Mads Sig Ager, Dan Carney, blink-dev, bak, Yoshifumi Inoue, aba...@chromium.org, Jochen Eisinger
Haraken,

How is this related to V8 extensions?

I believe Dan Carney suggestion is a better way forward than what you are proposing.

A few other random comments. Most of the things I wanted to ask/suggest has been said already.

V8 now has private symbols, an extension to ES6 unique symbols that provide true private state. With these it will become easier to do the right thing.

The normal way of storing the primordials early on would not work if we compile things lazily. To get around that we would need to provide access to the primordials in some other way. An ES6 module or a V8 extension seems booth plausible.

Mozilla has been using JS proxy objects for the membrane pattern with some success.

--
erik


Jochen Eisinger

unread,
Jan 17, 2014, 11:06:07 AM1/17/14
to Erik Arvidsson, Kentaro Hara, Aaron Boodman, Mads Sig Ager, Dan Carney, blink-dev, bak, Yoshifumi Inoue, aba...@chromium.org
On Fri, Jan 17, 2014 at 5:01 PM, Erik Arvidsson <a...@chromium.org> wrote:
Haraken,

How is this related to V8 extensions?

v8 extension are agnostic to isolated worlds, they're always executed. Also, they're slowing down startup, so I'm working on removing them (tracked in crbug.com/334679)

best
-jochen

Adam Barth

unread,
Jan 17, 2014, 12:38:54 PM1/17/14
to Erik Arvidsson, Kentaro Hara, Aaron Boodman, Mads Sig Ager, Dan Carney, blink-dev, bak, Yoshifumi Inoue, Jochen Eisinger
JavaScript proxy object as massively more difficult to implement correctly than isolated worlds.  If you don't believe our isolated worlds implementation is correct, then you shouldn't believe we could implement JS proxy objects correctly.  :)

IMHO, we should just fix whatever bugs remain in the isolated worlds mechanism and add some more RELEASE_ASSERTs.  That's beneficial both for Chrome extensions and for this mechanism.  Perhaps we could start by running the RELEASE_ASSERT for the Blink-in-JavaScript isolated world.  That way we'd be assured there aren't any leaks for those scripts and we'll have a useful bisect data if/when we trigger the assert in the future.

Adam

Aaron Boodman

unread,
Jan 17, 2014, 1:01:51 PM1/17/14
to Kentaro Hara, Mads Sig Ager, Dan Carney, blink-dev, bak, Erik Arvidsson, Yoshifumi Inoue, aba...@chromium.org
On Fri, Jan 17, 2014 at 2:48 AM, Kentaro Hara <har...@chromium.org> wrote:
Thanks aaron!

1) Back when we introduced content scripts, we had the idea that there could be low-level CHECK's that code from one isolated world could never touch objects from another world. I'm not sure if it was ever implemented though. If that existed, then I think it would increase confidence in relying on isolated worlds for security.

Yes, this would be the best. It's possible to insert the check, but it's never trivial to insert the check without adding any performance overhead. We have to insert the check to all points where we return DOM wrappers to JavaScript. But it's worth considering.


2) There is a generalization of the your idea that would both increase its flexibility and perhaps allay security concerns, particularly if the CHECKs in (1) are not possible for some reason: 
 
The only reason you need isolated worlds at all is because you want to be able to pass DOM wrappers between user JavaScript and BlinkInJavaScript. If it weren't for this fact, then you wouldn't need isolated worlds because the only other types you propose that the C++ bindings layer would allow through are primitives. Your bindings layer is providing some isolation, but it only works for primitives.

Right. To support primitive values, we just need to isolate contexts. To support DOM wrappers, we need to introduce isolated worlds in addition.

Instead of relying on isolated worlds for the complex objects case, you could teach the C++ bindings layer to do isolation for them too. Basically for every object and function implemented in BlinkInJS exposed to user JS, there would be a C++ proxy representing the target object. When user JS tried to access a property of the target, or call a function, the C++ proxy would actually receive the access, delegate to the target object, and marshall values back and forth. The proxies would be recursive, so this would work for arbitrary data structures. As before, you could just allow primitive JS values through, so there would not be serialization overhead.

This sounds interesting, but it seems to me that the C++ proxy objects are doing almost the same thing as isolated worlds. I agree that the C++ proxy objects will allow us to overcome the security concerns of Blink-in-JavaScript even if we have bugs in the current implementation of isolated worlds, but it seems that it is saying "Because the current isolated worlds might have bugs, let's implement another kind of isolated world (i.e., C++ proxy objects) for Blink-in-JavaScript". Then, I still think that we should try our best to harden security of the current isolated worlds instead of introducing another kind of isolated world. (Sorry if I'm missing your point.)

The advantage of the proxy design is that it allows you to also pass complex objects that are implemented in JavaScript between two JS environments and maintain isolation. For example, in your doc you say that you cannot return objects, arrays, or functions. The proxy design would fix that.

Or, another example (sorry if my WebIDL is rusty):

[BlinkInJavaScript]
interface Foo {
  DOMString getBar();
  void setBar(DOMString s);
};

[supplemental]
interface FooWindow {
  Foo getFoo();
};

Can you do this in your design? It's not clear how it would be accomplished from the doc.

I think that the proxy object design has a higher up-front implementation cost but it's a one time cost for a general solution that works and is secure for anything WebIDL can express. It effectively makes JS a first-class language for implementing WebIDL bindings. Two implementations of WebIDL interfaces could talk to each other and not even know what language the other is implemented in.


On Fri, Jan 17, 2014 at 9:38 AM, Adam Barth <aba...@chromium.org> wrote:
JavaScript proxy object as massively more difficult to implement correctly than isolated worlds.  If you don't believe our isolated worlds implementation is correct, then you shouldn't believe we could implement JS proxy objects correctly.  :)

I think that the proxy objects in Mozilla are more complicated because of the fact that their goal -- at least the ones I have seen -- is not to do full isolation, but to allow a kind of one-way membrane. I don't see why it is so hard to do full isolation with proxies. Can you provide a concrete example?


Adam Barth

unread,
Jan 17, 2014, 1:09:40 PM1/17/14
to Aaron Boodman, Kentaro Hara, Mads Sig Ager, Dan Carney, blink-dev, bak, Erik Arvidsson, Yoshifumi Inoue
On Fri, Jan 17, 2014 at 10:01 AM, Aaron Boodman <a...@chromium.org> wrote:
On Fri, Jan 17, 2014 at 9:38 AM, Adam Barth <aba...@chromium.org> wrote:
JavaScript proxy object as massively more difficult to implement correctly than isolated worlds.  If you don't believe our isolated worlds implementation is correct, then you shouldn't believe we could implement JS proxy objects correctly.  :)

I think that the proxy objects in Mozilla are more complicated because of the fact that their goal -- at least the ones I have seen -- is not to do full isolation, but to allow a kind of one-way membrane. I don't see why it is so hard to do full isolation with proxies. Can you provide a concrete example?

WebKit used to have an implementation in JavaScriptCore for the inspector.  It wasn't hard to keep breaking it until I convinced folks to rip it out.  There isn't a simple example that looks nice in email.  It's all insanity whereby the author of the JavaScript thinks they're doing one thing but because of some obscure edge case in the language, they actually ended up doing something completely different.

Mozilla's implementation had the same trouble.  For years, every security release of Firefox contained fixes for "wrapper pollution."  They invested the effort and eventually fixed all the bugs (hopefully?).  We haven't invested that effort, and it's kind of a daunting task.  Your isolated worlds design is orders of magnitude better.

Adam

Aaron Boodman

unread,
Jan 17, 2014, 1:55:49 PM1/17/14
to Adam Barth, Kentaro Hara, Mads Sig Ager, Dan Carney, blink-dev, bak, Erik Arvidsson, Yoshifumi Inoue
I talked to Adam offline and realized that we are proposing mostly the same thing.

Nevermind, I support both the proposal and the notion of fixing the bugs in isolated worlds. :)

- a

Kentaro Hara

unread,
Jan 19, 2014, 8:59:35 PM1/19/14
to Aaron Boodman, Adam Barth, Mads Sig Ager, Dan Carney, blink-dev, bak, Erik Arvidsson, Yoshifumi Inoue
Thanks all for the input!

I think the summary of the discussions so far would be as follows:

- Using isolated worlds for Blink-in-JavaScript is a good approach.
- However, our current implementation of isolated worlds is fragile and might have bugs. So if we use isolated worlds for Blink-in-JavaScript, we'll open a whole new set of possible attacks based on the bugs of isolated worlds.


abarth:
IMHO, we should just fix whatever bugs remain in the isolated worlds mechanism and add some more RELEASE_ASSERTs.  That's beneficial both for Chrome extensions and for this mechanism.  Perhaps we could start by running the RELEASE_ASSERT for the Blink-in-JavaScript isolated world.  That way we'd be assured there aren't any leaks for those scripts and we'll have a useful bisect data if/when we trigger the assert in the future.

Completely agreed.

As far as I scan bindings/, I can find a couple of potential DOM wrapper leaks between isolated worlds. One of the reasons why we have these bugs is that the architecture of isolated worlds, contexts etc are complicated and thus it's hard for Blink developers to implement those correctly. I'll consider how to improve the architecture and harden the security.


aaron:
Or, another example (sorry if my WebIDL is rusty):
[BlinkInJavaScript]
interface Foo {
  DOMString getBar();
  void setBar(DOMString s);
};
[supplemental]
interface FooWindow {
  Foo getFoo();
};
Can you do this in your design? It's not clear how it would be accomplished from the doc.

If I'm understanding correctly, we can do this. WindowBase64.js in the design doc is already doing this. WindowBase64.js is a partial interface of Window.



Kentaro Hara

unread,
Feb 5, 2014, 9:02:59 AM2/5/14
to Aaron Boodman, Adam Barth, Mads Sig Ager, Dan Carney, blink-dev, bak, Erik Arvidsson, Yoshifumi Inoue
I started working on implementing Blink-in-JavaScript. I'm planning to proceed with the following steps:

Step 1: Refactor V8 binding code around isolated worlds.
Step 2: Make sure that DOM wrappers never leak between isolated worlds. This work is also important to harden security of content scripts of Chrome extensions.
Step 3: Implement Blink-in-JavaScript.
Step 4: Move things to Blink-in-JavaScript. Document::execCommand() is the first target. XSLTProcessor would be a next, challenging target.

If you're interested in the progress, please follow this bug: https://code.google.com/p/chromium/issues/detail?id=341031

Thanks!


Reply all
Reply to author
Forward
0 new messages