-
Notifications
You must be signed in to change notification settings - Fork 1.8k
JS: support rest-patterns inside property patterns #3656
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't immediately see why the rest pattern isn't working, but this isn't quite right. The rest pattern should be found by the recursions in lvalAux
and getABindingVarRef
.
Isn't it just a case of us not having a taint step through rest patterns?
Yes, it is recognized, but not with the correct The rest-pattern in the example contains all the properties from the |
And the expected output is breaking a lot because of the change in |
[x, y] = [y, x] There's probably a simpler way to model that, but that's how DefUse.qll operates, and that's why |
…(and removed old incorrect approach)
0c2cc59
to
b8a9ac3
Compare
Thanks for the feedback, I found a good solution. I just needed to add a new |
exists(PropertyPattern pattern | | ||
pred = TPropNode(pattern) and | ||
succ = lvalueNode(pattern.getValuePattern().(ObjectPattern).getRest()) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's just review the runtime behavior of rest patterns:
{ ...args } = x
stores a shallow copy ofx
inargs
.{ p1, p2, ...args } = x
stores a shallow copy ofx
without propertiesp1
,p2
, etc inargs
.
What this change is doing is essentially modelling this copying step via a pure data flow step x -> args
.
There are two issues here:
- How do we best express that step?
- Is it safe to use a pure data flow step for this?
For the first issue, I think the step should go from the object pattern itself to its rest pattern:
exists(ObjectPattern pattern |
pred = lvalueNode(pattern) and
succ = lvalueNode(pattern.getRest())
)
For the second issue, I can completely see how this would work great most of the time, but not always. For example, this would cause getALocalSource
to backtrack through a copy step, making some of our store-steps spuriously propagate back to the original object.
I think the best would be to add it as an AdditionalFlowStep
. Those steps don't affect getALocalSource
but do affect all data-flow configurations. And since the above formulation doesn't depend on any internal predicates it should be a straightforward addition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
The only data-flow related use of rest-patterns I could fine was in DefUse::lvalAux
, I think that threw me off.
I've added it as a default taint-tracking step for now.
Do you think it should be a default data-flow step?
d213373
to
733e04c
Compare
exists(PropertyPattern pattern | | ||
pred.(DataFlow::PropNode).getAstNode() = pattern and | ||
succ = DataFlow::lvalueNode(pattern.getValuePattern().(ObjectPattern).getRest()) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried the version I proposed earlier?
exists(PropertyPattern pattern | | |
pred.(DataFlow::PropNode).getAstNode() = pattern and | |
succ = DataFlow::lvalueNode(pattern.getValuePattern().(ObjectPattern).getRest()) | |
) | |
exists(ObjectPattern pattern | | |
pred = lvalueNode(pattern) and | |
succ = lvalueNode(pattern.getRest()) | |
) |
That should also work for rest patterns that aren't part of a property pattern, like:
let { ...args } = x
let [ { ...args} ] = x;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had not, I should have.
I've implemented your suggestion, but I used DestructuringPattern
instead of ObjectPattern
, that way we also support array-spreads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent! 👍
To support the below case, where a rest-pattern is inside a property-pattern.
I feel that the change in
DataFlow.qll
shouldn't be needed.I'm hoping I overlooked something, and that there's a better way of doing it.
Gets a TP/TN for CVE-2020-8149