WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
154144
The parser doesn't properly protect against global variable references in builtins
https://bugs.webkit.org/show_bug.cgi?id=154144
Summary
The parser doesn't properly protect against global variable references in bui...
Saam Barati
Reported
2016-02-11 17:42:19 PST
...
Attachments
patch
(8.85 KB, patch)
2016-02-11 19:00 PST
,
Saam Barati
no flags
Details
Formatted Diff
Diff
patch
(22.28 KB, patch)
2016-02-12 15:41 PST
,
Saam Barati
no flags
Details
Formatted Diff
Diff
patch
(22.16 KB, patch)
2016-02-12 15:43 PST
,
Saam Barati
ggaren
: review+
Details
Formatted Diff
Diff
Show Obsolete
(2)
View All
Add attachment
proposed patch, testcase, etc.
Saam Barati
Comment 1
2016-02-11 19:00:04 PST
Created
attachment 271119
[details]
patch
Oliver Hunt
Comment 2
2016-02-11 19:12:46 PST
Comment on
attachment 271119
[details]
patch IIRC correctly the purpose of this logic wasn't to be correct wrt language semantics, just correct-enough to ensure that we didn't accidentally try to capture from the global object. It was essentially a safety thing for builtins.
Saam Barati
Comment 3
2016-02-11 19:20:52 PST
(In reply to
comment #2
)
> Comment on
attachment 271119
[details]
> patch > > IIRC correctly the purpose of this logic wasn't to be correct wrt language > semantics, just correct-enough to ensure that we didn't accidentally try to > capture from the global object. It was essentially a safety thing for > builtins.
Which logic are you talking about?
Saam Barati
Comment 4
2016-02-11 19:25:47 PST
I think you're probably talking about this loop: - if (!capturedVariables.isEmpty()) { - for (const auto& capturedVariable : capturedVariables) { - if (scope->hasDeclaredVariable(capturedVariable)) - continue; - - if (scope->hasDeclaredParameter(capturedVariable)) - continue; - - RELEASE_ASSERT_NOT_REACHED(); - } - } And if so, we want the logic to be something like: ``` if (m_parsingBuiltin) RELEASE_ASSERT(capturedVariableCandidates().isEmpty()); ``` Out of curiosity, why do we enforce this? Is it just that global properties can be changed by user code?
Oliver Hunt
Comment 5
2016-02-11 19:29:25 PST
(In reply to
comment #3
)
> (In reply to
comment #2
) > > Comment on
attachment 271119
[details]
> > patch > > > > IIRC correctly the purpose of this logic wasn't to be correct wrt language > > semantics, just correct-enough to ensure that we didn't accidentally try to > > capture from the global object. It was essentially a safety thing for > > builtins. > > Which logic are you talking about?
Literally the entirety of what you just removed. Again, this is very much an "IIRC", and all I can recall is that the particular set of rules it ended up enforcing were those necessary to disallow capturing global variables. I agree the mismatched naming vs. semantics warrant fixing, but with this change it becomes possible to accidentally capture unprivileged global variables, e.g. Object vs @Object. Given the testing we could also change the logic that achieves this to be at bytecode generation time to fail out on any non-local resolve (which is probably a more sensible way to do it).
Oliver Hunt
Comment 6
2016-02-11 19:30:19 PST
(In reply to
comment #4
)
> I think you're probably talking about this loop: > - if (!capturedVariables.isEmpty()) { > - for (const auto& capturedVariable : capturedVariables) { > - if (scope->hasDeclaredVariable(capturedVariable)) > - continue; > - > - if (scope->hasDeclaredParameter(capturedVariable)) > - continue; > - > - RELEASE_ASSERT_NOT_REACHED(); > - } > - } > > And if so, we want the logic to be something like: > ``` > if (m_parsingBuiltin) > RELEASE_ASSERT(capturedVariableCandidates().isEmpty()); > ``` > > Out of curiosity, why do we enforce this? Is it just that > global properties can be changed by user code?
Yup, which (among other things) leads to sadness in language semantics, as well as potential security issues.
Saam Barati
Comment 7
2016-02-12 11:03:40 PST
(In reply to
comment #5
)
> (In reply to
comment #3
) > > (In reply to
comment #2
) > > > Comment on
attachment 271119
[details]
> > > patch > > > > > > IIRC correctly the purpose of this logic wasn't to be correct wrt language > > > semantics, just correct-enough to ensure that we didn't accidentally try to > > > capture from the global object. It was essentially a safety thing for > > > builtins. > > > > Which logic are you talking about? > > Literally the entirety of what you just removed. > > Again, this is very much an "IIRC", and all I can recall is that the > particular set of rules it ended up enforcing were those necessary to > disallow capturing global variables. I agree the mismatched naming vs. > semantics warrant fixing, but with this change it becomes possible to > accidentally capture unprivileged global variables, e.g. Object vs @Object. > > Given the testing we could also change the logic that achieves this to be at > bytecode generation time to fail out on any non-local resolve (which is > probably a more sensible way to do it).
Okay. I agree that we should enforce this. I was just observing when reading the code that the code doesn't do anything. We need to come up with some rules that work. I don't think this can be done from the BytecodeGenerator. It would be possible to do during Bytecode linking, though. I think solving this in the parser still might be easiest. I think the logic would go something like this. ``` after parsing is complete, do: if (weAreParsingAProgram()) { if (captureVariableCandidates() \ definedVariables() != emptySet) crash() } ```
Saam Barati
Comment 8
2016-02-12 11:04:27 PST
Comment on
attachment 271119
[details]
patch View in context:
https://bugs.webkit.org/attachment.cgi?id=271119&action=review
> Source/JavaScriptCore/builtins/BuiltinExecutables.cpp:-115 > - for (const auto& closedVariable : program->closedVariables()) { > - if (closedVariable == vm.propertyNames->arguments.impl()) > - continue; > - > - if (closedVariable == vm.propertyNames->undefinedKeyword.impl()) > - continue; > - }
Oliver, do you remember why we had this here? Instead of strictly being in the parser? This is a very curious loop, it looks like it's probably been edited to death.
Saam Barati
Comment 9
2016-02-12 11:09:36 PST
I wonder if we have any errors that have slipped through here.
Saam Barati
Comment 10
2016-02-12 11:57:49 PST
(In reply to
comment #9
)
> I wonder if we have any errors that have slipped through here.
Yup. We totally do!
Saam Barati
Comment 11
2016-02-12 15:01:01 PST
(In reply to
comment #10
)
> (In reply to
comment #9
) > > I wonder if we have any errors that have slipped through here. > > Yup. We totally do!
Oh man, we get it wrong in so many places :/
Saam Barati
Comment 12
2016-02-12 15:41:49 PST
Created
attachment 271238
[details]
patch
WebKit Commit Bot
Comment 13
2016-02-12 15:42:25 PST
Attachment 271238
[details]
did not pass style-queue: ERROR: Source/JavaScriptCore/parser/Parser.cpp:304: Should have a space between // and comment [whitespace/comments] [4] ERROR: Source/JavaScriptCore/parser/Parser.cpp:305: Should have a space between // and comment [whitespace/comments] [4] ERROR: Source/WebCore/bindings/js/JSDOMGlobalObject.cpp:36: Alphabetical sorting problem. [build/include_order] [4] Total errors found: 3 in 15 files If any of these errors are false positives, please file a bug against check-webkit-style.
Saam Barati
Comment 14
2016-02-12 15:43:05 PST
Created
attachment 271239
[details]
patch
WebKit Commit Bot
Comment 15
2016-02-12 15:44:57 PST
Attachment 271239
[details]
did not pass style-queue: ERROR: Source/WebCore/bindings/js/JSDOMGlobalObject.cpp:36: Alphabetical sorting problem. [build/include_order] [4] Total errors found: 1 in 15 files If any of these errors are false positives, please file a bug against check-webkit-style.
Geoffrey Garen
Comment 16
2016-02-12 15:45:06 PST
Comment on
attachment 271239
[details]
patch View in context:
https://bugs.webkit.org/attachment.cgi?id=271239&action=review
r=me
> Source/JavaScriptCore/parser/Parser.cpp:334 > + if (!lexicalVariables.contains(candidate) && !varDeclarations.contains(candidate) && !builtinNames.isPrivateName(*candidate.get())) { > + dataLog("Bad global capture in builtin: '", candidate, "'\n"); > + dataLog(m_source->view()); > + CRASH(); > }
Can we make this an ASSERT instead?
Mark Lam
Comment 17
2016-02-12 15:46:31 PST
Comment on
attachment 271239
[details]
patch View in context:
https://bugs.webkit.org/attachment.cgi?id=271239&action=review
> Source/JavaScriptCore/parser/Parser.cpp:302 > + scope->getCapturedVars(capturedVariables, modifiedParameter, modifiedArguments); // FIXME: make this just find out modifedParamerer/modifiedArguments
Maybe you should file a bug for this (and include the bug url here)?
Saam Barati
Comment 18
2016-02-12 15:56:03 PST
Comment on
attachment 271239
[details]
patch View in context:
https://bugs.webkit.org/attachment.cgi?id=271239&action=review
>> Source/JavaScriptCore/parser/Parser.cpp:302 >> + scope->getCapturedVars(capturedVariables, modifiedParameter, modifiedArguments); // FIXME: make this just find out modifedParamerer/modifiedArguments > > Maybe you should file a bug for this (and include the bug url here)?
oops, this FIXME should just be removed. I was anticipating rewriting this function but I didn't
Saam Barati
Comment 19
2016-02-12 16:06:01 PST
Comment on
attachment 271239
[details]
patch View in context:
https://bugs.webkit.org/attachment.cgi?id=271239&action=review
>> Source/JavaScriptCore/parser/Parser.cpp:334 >> } > > Can we make this an ASSERT instead?
I think this reporting is actually very helpful. I'm going to keep it. I'm going to put the whole loop under #ifndef NDEBUG
Saam Barati
Comment 20
2016-02-12 16:13:14 PST
landed in:
http://trac.webkit.org/changeset/196525
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug