-
Notifications
You must be signed in to change notification settings - Fork 1.9k
JS: Do not taint whole array when storing into ArrayElement #18790
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
Changes from all commits
283954d
d79f429
e8d1703
d87534c
a74b203
33ab7db
352924f
08b9d93
4e325d9
6e074c3
a54f0a7
c958702
e610683
82a4b17
7486742
804a1a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,7 @@ | |
| private import javascript | ||
| private import semmle.javascript.dataflow.internal.DataFlowNode | ||
| private import semmle.javascript.dataflow.FlowSummary | ||
| private import Arrays | ||
| private import FlowSummaryUtil | ||
|
|
||
| class At extends SummarizedCallable { | ||
|
|
@@ -41,15 +42,18 @@ class At extends SummarizedCallable { | |
| } | ||
|
|
||
| class Concat extends SummarizedCallable { | ||
| Concat() { this = "Array#concat / String#concat" } | ||
| Concat() { this = "Array#concat / String#concat / Buffer.concat" } | ||
|
|
||
| override InstanceCall getACallSimple() { result.getMethodName() = "concat" } | ||
|
|
||
| override predicate propagatesFlow(string input, string output, boolean preservesValue) { | ||
| // Array#concat. | ||
| // Also models Buffer.concat as this happens to out work well with our toString() model. | ||
| preservesValue = true and | ||
| input = "Argument[this,0..].ArrayElement" and | ||
| output = "ReturnValue.ArrayElement" | ||
| or | ||
| // String#concat | ||
| preservesValue = false and | ||
| input = "Argument[this,0..]" and | ||
| output = "ReturnValue" | ||
|
|
@@ -149,3 +153,20 @@ class Values extends SummarizedCallable { | |
| output = "ReturnValue.IteratorElement" | ||
| } | ||
| } | ||
|
|
||
| class ToString extends SummarizedCallable { | ||
| ToString() { this = "Object#toString / Array#toString" } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a model of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was a bit torn about what to name the summary. It applies to all method calls to The "correct" model for |
||
|
|
||
| override InstanceCall getACallSimple() { | ||
| result.(DataFlow::MethodCallNode).getMethodName() = "toString" | ||
| or | ||
| result = arrayConstructorRef().getAPropertyRead("prototype").getAMemberCall("toString") | ||
| } | ||
|
|
||
| override predicate propagatesFlow(string input, string output, boolean preservesValue) { | ||
| preservesValue = false and | ||
| // Arrays stringify their contents and joins by "," | ||
| input = "Argument[this].ArrayElementDeep" and | ||
| output = "ReturnValue" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| category: majorAnalysis | ||
| --- | ||
| * Improved precision of data flow through arrays, fixing some spurious flows | ||
| that would sometimes cause the `length` property of an array to be seen as tainted. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import 'dummy'; | ||
|
|
||
| function t1() { | ||
| const b1 = Buffer.from(source("t1.1")); | ||
| const b2 = Buffer.from(source("t1.2")); | ||
| sink(Buffer.concat([b1, b2]).toString("utf8")); // $ hasTaintFlow=t1.1 hasTaintFlow=t1.2 | ||
| } |
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 found this usage example:
_.sortBy(users, [function(o) { return o.user; }]);Seems the relevant value is the first parameter.
Also, you can specify an array of functions, but I'm not sure we need to model that.
Uh oh!
There was an error while loading. Please reload this page.
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.
Good catch, fixed the parameter index. I was just trying to reach parity with the old model, but without jump steps.
We need a more scalable way to make tests for libraries like lodash. I actually started writing tests for these but realised I was basically writing the same code twice in two different forms and would be likely to repeat the same mistakes in both places. I tried a rather simple use of copilot auto completion to generate tests, but it did not work well.