RESOLVED FIXED Bug 97398
Script run from an isolated world should be able to bypass a page's CSP (V8 side).
https://bugs.webkit.org/show_bug.cgi?id=97398
Summary Script run from an isolated world should be able to bypass a page's CSP (V8 s...
Mike West
Reported 2012-09-22 14:30:14 PDT
Content Security Policy shouldn't block script run in an isolated world (a Chrome extension, for instance) from loading resources. Aaron suggested checking which world is topmost in the stack at the time a resource is loaded, and canceling the CSP check entirely if it's an isolated world. That seems worth checking out. The patch I'll upload in a moment depends on some refactoring work being done in bug 96637, so I'm not going to hand it to the bots, as it'll simply explode.
Attachments
WIP (10.73 KB, patch)
2012-09-22 14:37 PDT, Mike West
no flags
Patch (20.91 KB, patch)
2012-09-28 07:39 PDT, Mike West
no flags
WDYT? (26.07 KB, patch)
2012-09-29 02:56 PDT, Mike West
no flags
Patch (26.67 KB, patch)
2012-10-18 06:17 PDT, Mike West
no flags
Patch (27.22 KB, patch)
2012-10-25 07:16 PDT, Mike West
no flags
Rebased. (27.11 KB, patch)
2012-10-30 03:38 PDT, Mike West
no flags
Patch for landing (27.33 KB, patch)
2012-10-31 01:39 PDT, Mike West
no flags
Mike West
Comment 1 2012-09-22 14:37:31 PDT
Adam Barth
Comment 2 2012-09-24 10:52:32 PDT
I wonder if this isn't quite the right check. We might use isolated worlds for many things, but it's only really extensions that we want to be able to bypass the CSP checks. Perhaps we need to ask the ScriptController something more semantic...
Mike West
Comment 3 2012-09-24 11:10:36 PDT
(In reply to comment #2) > I wonder if this isn't quite the right check. We might use isolated worlds for many things, but it's only really extensions that we want to be able to bypass the CSP checks. Perhaps we need to ask the ScriptController something more semantic... It seems like what we really want is something like Chromium's UserScriptSlave::GetExtensionIdForIsolatedWorld. If the isolated world is an extension's isolated world, then do something. Could we do something clever in Chromium's UserScriptSlave::InitializeIsolatedWorld to tag the world as bypassing CSP, and store that as a flag on the world itself?
Adam Barth
Comment 4 2012-09-24 11:36:27 PDT
Yeah, we probably want the embedder to tell us that this particular isolated world should ignore CSP when it creates it.
Mike West
Comment 5 2012-09-25 08:29:33 PDT
(In reply to comment #4) > Yeah, we probably want the embedder to tell us that this particular isolated world should ignore CSP when it creates it. I'll sit down with Dan at some point in the near future (Hi, Dan!) to talk about how I might go about implementing this.
Aaron Boodman
Comment 6 2012-09-25 08:58:31 PDT
If you're going to go to the work of adding API to push down "Ignore main world CSP for world X", can you instead push down "This is the CSP to use for world X". That would allow us to implement support for using the extension's own CSP in its content script.
Mike West
Comment 7 2012-09-28 07:39:19 PDT
Mike West
Comment 8 2012-09-28 07:40:27 PDT
(In reply to comment #6) > If you're going to go to the work of adding API to push down "Ignore main world CSP for world X", can you instead push down "This is the CSP to use for world X". > > That would allow us to implement support for using the extension's own CSP in its content script. I'll take a stab at something like this. As a first step, we can accept a string and store it on the world. I have no idea how we'd make the world use a separate CSP than the main world; I'll have to talk with Adam about how something like that might look.
Adam Barth
Comment 9 2012-09-28 09:07:00 PDT
Comment on attachment 166251 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=166251&action=review > Source/WebCore/bindings/v8/ScriptController.h:122 > + virtual void setIsolatedWorldContentSecurityPolicy(int worldID, const String&); No need for virtual here. ScriptController doesn't have any subclasses.
Mike West
Comment 10 2012-09-29 02:56:41 PDT
Mike West
Comment 11 2012-09-29 02:58:18 PDT
Comment on attachment 166357 [details] WDYT? Now that Dan's changes landed, I've cleaned up the patch, and I'd appreciate you taking a look Adam. It's V8-only right now, which might or might not be acceptable. Does this approach make sense? How do you think we could support a full-blown CSP-override in the future? Thanks!
WebKit Review Bot
Comment 12 2012-09-29 02:59:47 PDT
Please wait for approval from abarth@webkit.org, dglazkov@chromium.org, fishd@chromium.org, jamesr@chromium.org or tkent@chromium.org before submitting, as this patch contains changes to the Chromium public API. See also https://trac.webkit.org/wiki/ChromiumWebKitAPI.
WebKit Review Bot
Comment 13 2012-09-29 03:00:12 PDT
Attachment 166357 [details] did not pass style-queue: Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'LayoutTests/ChangeLog', u'LayoutTests/http..." exit_code: 1 LayoutTests/platform/wincairo/TestExpectations:1: No port uses path LayoutTests/platform/wincairo/TestExpectations for test_expectations [test/expectations] [5] Total errors found: 1 in 21 files If any of these errors are false positives, please file a bug against check-webkit-style.
Dan Carney
Comment 14 2012-09-29 13:00:26 PDT
(In reply to comment #11) > (From update of attachment 166357 [details]) > Now that Dan's changes landed, I've cleaned up the patch, and I'd appreciate you taking a look Adam. It's V8-only right now, which might or might not be acceptable. > > Does this approach make sense? How do you think we could support a full-blown CSP-override in the future? > > Thanks! Assuming that you are just setting the csp once per world, you can set this more easily at the DOMWrapperWorld level. It would then probably be more appropriate there instead of setting it a the per frame/per world level. Currently, the SecurityOrigin are set like this, but I've got an upcoming patch to push those to DOMWrapperWorld as well.
Dan Carney
Comment 15 2012-10-17 04:43:00 PDT
you can drop dependence on 96637 and add one for 99582 as discussed
Mike West
Comment 16 2012-10-17 04:46:10 PDT
(In reply to comment #15) > you can drop dependence on 96637 and add one for 99582 as discussed Cool, thanks Dan. I'll rework this patch on top of that one.
Mike West
Comment 17 2012-10-18 06:17:20 PDT
Mike West
Comment 18 2012-10-18 06:21:09 PDT
(In reply to comment #17) > Created an attachment (id=169401) [details] > Patch This patch creates another HashMap on DOMWrapperWorld to store Content Security Policies, in the same way Dan's patch did for SecurityOrigins. Given his refactoring, there's no particular reason for the bits on WebFrame, other than the fact that we need some way of exposing the DOMWrapperWorld API to the code on the other side (DRT, for instance). Would it make sense to create some new class there to store these sorts of things in another patch? WebDOMWrapperWorld?
Mike West
Comment 19 2012-10-24 05:31:04 PDT
Friendly ping, Adam. Would you mind taking a look at this to validate the approach?
Adam Barth
Comment 20 2012-10-24 23:16:35 PDT
Comment on attachment 169401 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=169401&action=review This looks great. I'd keep the API as a String, but I would use a bool in WebCore to represent this state. We can always elaborate the WebCore state if/when we want to support a full CSP policy. Sorry for the delay in reviewing this patch. For some reason I was hesitating to review it, but now I see that my hesitation was misplaced. > Source/WebCore/bindings/v8/DOMWrapperWorld.cpp:152 > +typedef HashMap<int, String> IsolatedWorldContentSecurityPolicyMap; > +static IsolatedWorldContentSecurityPolicyMap& isolatedWorldContentSecurityPolicies() > +{ > + ASSERT(isMainThread()); > + DEFINE_STATIC_LOCAL(IsolatedWorldContentSecurityPolicyMap, map, ()); > + return map; > +} I really dislike these maps keyed on the world ID. I know you're just following the pattern here, but this should really just be a bool on DOMWrapperWord. > Source/WebCore/bindings/v8/ScriptController.h:113 > + // Returns true if the current world is isolated, and has its own Content > + // Security Policy. In this case, the policy of the main world should be > + // ignored when evaluating resources injected into the DOM. > + bool shouldBypassMainWorldContentSecurityPolicy(); This API should take a DOMWrapperWorld* argument and the caller should call it with currentWorld(). You can look at how the other functions that take DOMWrapperWorld* arguments work in JSC. We'd like to switch over to using an approach more like JSC, but for now we do things a bit differently. Given that ScriptController is a shared interface with JSC, we should do things the JSC way. > Source/WebCore/loader/cache/CachedResourceLoader.cpp:307 > + bool shouldBypassMainWorldContentSecurityPolicy = (document()->frame() && document()->frame()->script()->shouldBypassMainWorldContentSecurityPolicy()); There's already a frame() accessor that you can use on CachedResourceLoader
Mike West
Comment 21 2012-10-25 00:03:54 PDT
Thanks! (In reply to comment #20) > This looks great. I'd keep the API as a String, but I would use a bool in WebCore to represent this state. We can always elaborate the WebCore state if/when we want to support a full CSP policy. Makes sense. The other open question I had is whether it's worth doing a JSC implementation. We haven't done one for SecurityOrigin, but I'm not sure it's a good idea to continue to add properties that other ports won't be able to make use of. Should we ping some JSC folks to see if they're interested? > > Source/WebCore/bindings/v8/DOMWrapperWorld.cpp:152 > > +typedef HashMap<int, String> IsolatedWorldContentSecurityPolicyMap; > > +static IsolatedWorldContentSecurityPolicyMap& isolatedWorldContentSecurityPolicies() > > +{ > > + ASSERT(isMainThread()); > > + DEFINE_STATIC_LOCAL(IsolatedWorldContentSecurityPolicyMap, map, ()); > > + return map; > > +} > > I really dislike these maps keyed on the world ID. I know you're just following the pattern here, but this should really just be a bool on DOMWrapperWord. I've talked to Dan about this, he's saying there are good reasons that it can't be a bool on the world itself, as the world might or might not actually exist at various points in time. I don't know enough about the lifecycle to weigh in here. Dan, can you add some context?
Adam Barth
Comment 22 2012-10-25 00:42:17 PDT
> Makes sense. The other open question I had is whether it's worth doing a JSC implementation. We haven't done one for SecurityOrigin, but I'm not sure it's a good idea to continue to add properties that other ports won't be able to make use of. Should we ping some JSC folks to see if they're interested? Yeah, let's ask them what they'd like. The main question is whether they want to use it in Safari for Safari's extension system. My guess is "yes", but it seems silly to have all the code without an API to use it. In any case, we can do the JSC and the V8 change in separate patches. > I've talked to Dan about this, he's saying there are good reasons that it can't be a bool on the world itself, as the world might or might not actually exist at various points in time. I don't know enough about the lifecycle to weigh in here. Dan, can you add some context? Yeah, I think he's right, but that's what I'd like to change. I don't think that should hold up your change though.
Dan Carney
Comment 23 2012-10-25 04:47:23 PDT
(In reply to comment #22) > > Makes sense. The other open question I had is whether it's worth doing a JSC implementation. We haven't done one for SecurityOrigin, but I'm not sure it's a good idea to continue to add properties that other ports won't be able to make use of. Should we ping some JSC folks to see if they're interested? > > Yeah, let's ask them what they'd like. The main question is whether they want to use it in Safari for Safari's extension system. My guess is "yes", but it seems silly to have all the code without an API to use it. > > In any case, we can do the JSC and the V8 change in separate patches. > > > I've talked to Dan about this, he's saying there are good reasons that it can't be a bool on the world itself, as the world might or might not actually exist at various points in time. I don't know enough about the lifecycle to weigh in here. Dan, can you add some context? > > Yeah, I think he's right, but that's what I'd like to change. I don't think that should hold up your change though. Just to jump in here. Mike's solution at the moment is the only way to go (unfortunately). There's a whole slew of problems related to having to use worldId in the api everywhere and not having an object on the other side of the chrome api to reference it from: WebDOMWrapperWorld or whatever. I've been meaning to discuss it with you so I know how to go forward, but the following are needed in such a class: securityOrigin setter csp setter static variables for the mainWorldId and uninitializedWorldId in DOMWrapperWorld that would be accessible from chrome a reference to the DOMWrapperWorld for the purpose of keeping it alive in accordance with chrome's need for it as opposed to the current implementation which is to keep it alive as long as a frame has a handle on it then I'd want to: change all the chrome apis to use WebDOMWrapperWorld instead of worldId change all the webkit apis to use DOMWrapperWorld instead of worldId if apple would be okay with it I've been waiting till after m24 to start sending changes in.
Mike West
Comment 24 2012-10-25 05:46:36 PDT
(In reply to comment #20) > (From update of attachment 169401 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=169401&action=review > > Source/WebCore/bindings/v8/ScriptController.h:113 > > + // Returns true if the current world is isolated, and has its own Content > > + // Security Policy. In this case, the policy of the main world should be > > + // ignored when evaluating resources injected into the DOM. > > + bool shouldBypassMainWorldContentSecurityPolicy(); > > This API should take a DOMWrapperWorld* argument and the caller should call it with currentWorld(). You can look at how the other functions that take DOMWrapperWorld* arguments work in JSC. We'd like to switch over to using an approach more like JSC, but for now we do things a bit differently. Given that ScriptController is a shared interface with JSC, we should do things the JSC way. 'currentWorld' doesn't look like it's used at all outside bindings code at the moment, and requires a ScriptState as a parameter, which I don't think I have any way of getting a pointer to from within CachedResourceLoader. And actually, it doesn't look like it's implemented at all in the V8 bindings. I'll upload a patch with the other issues addressed, but I don't see how to make this suggestion work.
Mike West
Comment 25 2012-10-25 07:16:51 PDT
WebKit Review Bot
Comment 26 2012-10-25 07:22:32 PDT
Attachment 170642 [details] did not pass style-queue: Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'LayoutTests/ChangeLog', u'LayoutTests/http..." exit_code: 1 LayoutTests/platform/qt/TestExpectations:2480: Path does not exist. [test/expectations] [5] Total errors found: 1 in 21 files If any of these errors are false positives, please file a bug against check-webkit-style.
Mike West
Comment 27 2012-10-30 03:38:36 PDT
Created attachment 171408 [details] Rebased.
Mike West
Comment 28 2012-10-30 03:40:04 PDT
(In reply to comment #24) > (In reply to comment #20) > > (From update of attachment 169401 [details] [details]) > > View in context: https://bugs.webkit.org/attachment.cgi?id=169401&action=review > > > Source/WebCore/bindings/v8/ScriptController.h:113 > > > + // Returns true if the current world is isolated, and has its own Content > > > + // Security Policy. In this case, the policy of the main world should be > > > + // ignored when evaluating resources injected into the DOM. > > > + bool shouldBypassMainWorldContentSecurityPolicy(); > > > > This API should take a DOMWrapperWorld* argument and the caller should call it with currentWorld(). You can look at how the other functions that take DOMWrapperWorld* arguments work in JSC. We'd like to switch over to using an approach more like JSC, but for now we do things a bit differently. Given that ScriptController is a shared interface with JSC, we should do things the JSC way. > > 'currentWorld' doesn't look like it's used at all outside bindings code at the moment, and requires a ScriptState as a parameter, which I don't think I have any way of getting a pointer to from within CachedResourceLoader. > > And actually, it doesn't look like it's implemented at all in the V8 bindings. > > I'll upload a patch with the other issues addressed, but I don't see how to make this suggestion work. Friendly post-branch point ping. :)
Adam Barth
Comment 29 2012-10-30 15:06:10 PDT
Comment on attachment 171408 [details] Rebased. View in context: https://bugs.webkit.org/attachment.cgi?id=171408&action=review My only hesitation with this patch is that we're leaning on V8's static state to implicitly remember whether we're in an isolated world. That might be tricky to implement in JSC. We should try the JSC implementation soon to make sure we don't need to restructure things too much. > Source/WebCore/bindings/v8/DOMWrapperWorld.h:75 > + > + These blank lines look extra
Adam Barth
Comment 30 2012-10-30 15:08:29 PDT
Please watch the http-bloat perf tests when your change rolls in to Chromium to make sure we don't regress performances. The http-bloat dataset seems to stress CachedResourceLoader for some reason.
Mike West
Comment 32 2012-10-30 23:13:03 PDT
(In reply to comment #29) > (From update of attachment 171408 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=171408&action=review > > My only hesitation with this patch is that we're leaning on V8's static state to implicitly remember whether we're in an isolated world. That might be tricky to implement in JSC. We should try the JSC implementation soon to make sure we don't need to restructure things too much. Filed https://bugs.webkit.org/show_bug.cgi?id=100815 to cover that work. Can you suggest someone familiar with JSC who might be able to help me put together a reasonable implementation? > > Source/WebCore/bindings/v8/DOMWrapperWorld.h:75 > > + > > + > > These blank lines look extra They are indeed. I'll spin a new patch for landing. Thanks!
Mike West
Comment 33 2012-10-31 01:39:01 PDT
Created attachment 171597 [details] Patch for landing
WebKit Review Bot
Comment 34 2012-10-31 03:00:05 PDT
Comment on attachment 171597 [details] Patch for landing Clearing flags on attachment: 171597 Committed r133006: <http://trac.webkit.org/changeset/133006>
WebKit Review Bot
Comment 35 2012-10-31 03:00:11 PDT
All reviewed patches have been landed. Closing bug.
Adam Barth
Comment 36 2012-10-31 10:18:02 PDT
> Filed https://bugs.webkit.org/show_bug.cgi?id=100815 to cover that work. Can you suggest someone familiar with JSC who might be able to help me put together a reasonable implementation? Sam Weinig might be able to help. I'm also pretty familiar with the JSC side. It's probably best if you take first swing at it so folks have a patch to use as a starting point for discussion.
Mike West
Comment 37 2012-11-01 07:08:05 PDT
(In reply to comment #31) > http://build.chromium.org/f/chromium/perf/xp-release-dual-core/bloat-http/report.html?history=50&rev=-1 It's a bit tough to tell, but it doesn't look like anything's changed significantly in those reports.
Note You need to log in before you can comment on or make changes to this bug.