RESOLVED FIXED 53244
CVE-2011-1194 A user gesture bug which can bypass popup blocker using iframe SRC
https://bugs.webkit.org/show_bug.cgi?id=53244
Summary A user gesture bug which can bypass popup blocker using iframe SRC
Johnny(Jianning) Ding
Reported 2011-01-27 09:09:19 PST
Created attachment 80338 [details] test case1 According to the description in crbug.com/70885. the following code can bypass popup blocker. (1) <iframe src="javascript:window.open('http://www.google.com' target=_new>pop</iframe> (2) <iframe src="javascript:window.open('http://www.google.com','','height=200,width=200' target=_new>pop</iframe> The bug reporter did a investigation and found it's because sourceURL->isNull()==true when window.open is used with iframe, the following is the code snippet. bool ScriptController::processingUserGesture() { ... if (sourceURL && sourceURL->isNull() && !activeProxy->timerCallback()) { // This is the <a href="javascript:window.open('...')> case -> we let it through. return true; } I was curious why sourceURL->isNull() was true, it should be "about:blank" when loading the iframe, so I did my investigation and the following is my analysis. According to https://svn.webkit.org/changeset/35050 and https://svn.webkit.org/changeset/55674, Darin and Adam introduced a way to look at the sourceURL to figure out whether we're running a script tag or a hyperlink. It does guarantee that the empty sourceURL does mean the we are running the scripts from a hyper-link. Please refer to https://svn.webkit.org/browser/trunk/WebCore/bindings/ScriptControllerBase.cpp#L49 https://svn.webkit.org/browser/trunk/WebCore/bindings/js/ScriptController.cpp#L497 So the protocols is all user-initiated javascript URLs are handled with forceUserGesture true in WebKit. For example, in WebFrameImpl::loadJavaScriptURL (WebKit/chromium port), it passed forceUserGesture=true to ScriptController::executeScript(const String& script, bool forceUserGesture, ShouldAllowXSS shouldAllowXSS) to explicitly tell WebCore we are running the scripts from a hyper-link. In this bug, the iframe SRC is not a hyper-link, so we should not set forceUserGesture parameter as true when calling ScriptController::executeScript, but currently it did happen, In function SubframeLoader::requestFrame, it calls ScriptController::executeIfJavaScriptURL to execute the SRC scrip. In function ScriptController::executeIfJavaScriptURL (line 93), it use the return value of processingUserGesture() to set forceUserGesture parameter, since the iframe is loaded by main frame, there is not active frame, the processingUserGesture() returns true, so ScriptController::executeScript set the sourceURL to NULL. For my perspective, the "forceUserGesture" parameter should be only used when you are definitely sure that the running script is from a hyper-link, what is why we add this parameter. We should not set it according to current gesture status from processingUserGesture(), they are not relevant. Even the "forceUserGesture" is set to false, the other functions still can get right gesture status from ScriptController::processingUserGesture(). In here, I propose two ways which changes ScriptController::executeIfJavaScriptURL to fix this bug. (1)always set "forceUserGesture" to false in ScriptController::executeIfJavaScriptURL. For situation of running a script from a hyperlink, we already handle it in WebKit ports (for example, WebFrameImpl::loadJavaScriptURL) (2)add a new boolean-type parameter, useCurrentGestureStatus, to indicates whether we want to use current gesture status to set the "forceUserGesture" parameter. then in SubframeLoader::requestFrame, call ScriptController::executeIfJavaScriptURL(url, false, ...) The webkit used not to have this bug, it's because we explicitly set the forceUserGesture to false in old code, you can refer to https://bugs.webkit.org/attachment.cgi?id=70970&action=diff from bug 47777. In old code, ScriptController::executeIfJavaScriptURL set userGesture to false as default value, and the SubframeLoader::requestFrame used the default value. @Adam, what do you think?
Attachments
test case1 (116 bytes, text/html)
2011-01-27 09:09 PST, Johnny(Jianning) Ding
no flags
test case2 (142 bytes, text/html)
2011-01-27 09:09 PST, Johnny(Jianning) Ding
no flags
patch v1 (4.33 KB, patch)
2011-01-27 10:21 PST, Johnny(Jianning) Ding
no flags
Johnny(Jianning) Ding
Comment 1 2011-01-27 09:09:47 PST
Created attachment 80339 [details] test case2
Johnny(Jianning) Ding
Comment 2 2011-01-27 10:21:08 PST
Created attachment 80344 [details] patch v1 This patch uses way 1.
Adam Barth
Comment 3 2011-01-27 10:28:00 PST
Can we just remove that parameter entirely? Now that we keep the gesture state in a static variable, we shouldn't need to pass it around explicitly.
Johnny(Jianning) Ding
Comment 4 2011-01-27 10:41:56 PST
(In reply to comment #3) > Can we just remove that parameter entirely? Now that we keep the gesture state in a static variable, we shouldn't need to pass it around explicitly. Currently when you type javascript URL in address bar and press Enter, the WebKit port will directly call ScriptController::executeScript(url, true, ...). So you mean we can change all those calls to the following way, { UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); ScriptController::executeScript(url, ...); } I think we can do that, but I need to re-check all related code and it will change lots of code. I think we may need to file another bug for removing "forceUserGesture" parameter. Does it make sense?
Adam Barth
Comment 5 2011-01-27 11:03:06 PST
> Does it make sense? Yep. Sounds like a good follow-up patch.
Johnny(Jianning) Ding
Comment 6 2011-01-28 01:03:01 PST
Filed bug 53286 to track the patch of removing the "forceUserGesture" parameter of function ScriptController::executeScript. Adam, would you please review my patch for this bug? We want to get it fixed asap. Thanks!
Adam Barth
Comment 7 2011-01-28 11:17:27 PST
Comment on attachment 80344 [details] patch v1 Looks reasonable. I'm most excited about the test. :)
Chris Evans
Comment 8 2011-01-28 17:23:07 PST
Can we land this on trunk? We can handle merging it as appropriate :)
Adam Barth
Comment 9 2011-01-28 17:24:52 PST
Comment on attachment 80344 [details] patch v1 Sure.
WebKit Commit Bot
Comment 10 2011-01-28 23:04:20 PST
The commit-queue encountered the following flaky tests while processing attachment 80344 [details]: http/tests/xmlhttprequest/basic-auth-nopassword.html bug 53170 The commit-queue is continuing to process your patch.
WebKit Commit Bot
Comment 11 2011-01-28 23:07:14 PST
Comment on attachment 80344 [details] patch v1 Clearing flags on attachment: 80344 Committed r77049: <http://trac.webkit.org/changeset/77049>
WebKit Commit Bot
Comment 12 2011-01-28 23:07:18 PST
All reviewed patches have been landed. Closing bug.
Chris Evans
Comment 13 2011-03-10 00:04:13 PST
Note You need to log in before you can comment on or make changes to this bug.