зеркало из https://github.com/github/codeql.git
Merge pull request #115 from esben-semmle/js/composed-function-taint
JS: model composed functions
This commit is contained in:
Коммит
69ca103e06
|
@ -21,6 +21,7 @@
|
|||
* Support for popular libraries has been improved. Consequently, queries may produce more results on code bases that use the following libraries:
|
||||
- [bluebird](https://bluebirdjs.com)
|
||||
- [browserid-crypto](https://github.com/mozilla/browserid-crypto)
|
||||
- [compose-function](https://github.com/stoeffel/compose-function)
|
||||
- [cookie-parser](https://github.com/expressjs/cookie-parser)
|
||||
- [cookie-session](https://github.com/expressjs/cookie-session)
|
||||
- [crypto-js](https://github.com/https://github.com/brix/crypto-js)
|
||||
|
@ -52,6 +53,7 @@
|
|||
- [json-parse-better-errors](https://github.com/zkat/json-parse-better-errors)
|
||||
- [json-parse-safe](https://github.com/joaquimserafim/json-parse-safe)
|
||||
- [json-safe-parse](https://github.com/bahamas10/node-json-safe-parse)
|
||||
- [just-compose](https://github.com/angus-c/just)
|
||||
- [just-extend](https://github.com/angus-c/just)
|
||||
- [lodash](https://lodash.com)
|
||||
- [merge-deep](https://github.com/jonschlinkert/merge-deep)
|
||||
|
|
|
@ -53,6 +53,7 @@ import semmle.javascript.frameworks.AngularJS
|
|||
import semmle.javascript.frameworks.AWS
|
||||
import semmle.javascript.frameworks.Azure
|
||||
import semmle.javascript.frameworks.Babel
|
||||
import semmle.javascript.frameworks.ComposedFunctions
|
||||
import semmle.javascript.frameworks.Credentials
|
||||
import semmle.javascript.frameworks.CryptoLibraries
|
||||
import semmle.javascript.frameworks.DigitalOcean
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* Provides classes for reasoning about composed functions.
|
||||
*/
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* A function composed from a collection of functions.
|
||||
*/
|
||||
private class ComposedFunction extends DataFlow::CallNode {
|
||||
|
||||
ComposedFunction() {
|
||||
exists (string name |
|
||||
name = "just-compose" or
|
||||
name = "compose-function" |
|
||||
this = DataFlow::moduleImport(name).getACall()
|
||||
) or
|
||||
this = LodashUnderscore::member("flow").getACall()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ith function in this composition.
|
||||
*/
|
||||
DataFlow::FunctionNode getFunction(int i) {
|
||||
result.flowsTo(getArgument(i))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step for a composed function.
|
||||
*/
|
||||
private class ComposedFunctionTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
|
||||
ComposedFunction composed;
|
||||
|
||||
DataFlow::CallNode call;
|
||||
|
||||
ComposedFunctionTaintStep() {
|
||||
call = composed.getACall() and
|
||||
this = call
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists (int fnIndex, DataFlow::FunctionNode fn |
|
||||
fn = composed.getFunction(fnIndex) |
|
||||
// flow out of the composed call
|
||||
fnIndex = composed.getNumArgument() - 1 and
|
||||
pred = fn.getAReturn() and
|
||||
succ = this
|
||||
or
|
||||
if fnIndex = 0 then
|
||||
// flow into the first composed function
|
||||
exists (int callArgIndex |
|
||||
pred = call.getArgument(callArgIndex) and
|
||||
succ = fn.getParameter(callArgIndex)
|
||||
)
|
||||
else
|
||||
// flow through the composed functions
|
||||
exists (DataFlow::FunctionNode predFn |
|
||||
predFn = composed.getFunction(fnIndex - 1) |
|
||||
pred = predFn.getAReturn() and
|
||||
succ = fn.getParameter(0)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
| tst.js:10:10:10:15 | source |
|
||||
| tst.js:15:10:15:13 | f1() |
|
||||
| tst.js:20:10:20:23 | compose1(f2)() |
|
||||
| tst.js:28:10:28:27 | compose1(f3, f4)() |
|
||||
| tst.js:33:10:33:28 | compose1(o.f, f5)() |
|
||||
| tst.js:41:10:41:27 | compose1(f6, f7)() |
|
||||
| tst.js:49:10:49:33 | compose ... source) |
|
||||
| tst.js:61:10:61:40 | compose ... source) |
|
||||
| tst.js:66:10:66:30 | compose ... source) |
|
||||
| tst.js:89:10:89:31 | f18(und ... source) |
|
||||
| tst.js:94:10:94:24 | compose2(f19)() |
|
||||
| tst.js:99:10:99:24 | compose3(f20)() |
|
||||
| tst.js:104:10:104:24 | compose4(f21)() |
|
|
@ -0,0 +1,22 @@
|
|||
import javascript
|
||||
|
||||
class ExampleConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
ExampleConfiguration() { this = "ExampleConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(CallExpr).getCalleeName() = "SOURCE"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists (CallExpr callExpr |
|
||||
callExpr.getCalleeName() = "SINK" and
|
||||
DataFlow::valueNode(callExpr.getArgument(0)) = sink
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
from ExampleConfiguration cfg, DataFlow::Node source, DataFlow::Node sink
|
||||
where cfg.hasFlow(source, sink)
|
||||
select sink
|
|
@ -0,0 +1,106 @@
|
|||
import compose1 from 'just-compose';
|
||||
import compose2 from 'compose-function';
|
||||
import compose3 from 'lodash.flow';
|
||||
import _ from 'lodash';
|
||||
var compose4 = _.flow;
|
||||
|
||||
(function(){
|
||||
var source = SOURCE();
|
||||
|
||||
SINK(source);
|
||||
|
||||
function f1(){
|
||||
return source;
|
||||
}
|
||||
SINK(f1());
|
||||
|
||||
function f2(){
|
||||
return source;
|
||||
}
|
||||
SINK(compose1(f2)());
|
||||
|
||||
function f3(){
|
||||
|
||||
}
|
||||
function f4(){
|
||||
return source;
|
||||
}
|
||||
SINK(compose1(f3, f4)());
|
||||
|
||||
function f5(){
|
||||
return source;
|
||||
}
|
||||
SINK(compose1(o.f, f5)());
|
||||
|
||||
function f6(){
|
||||
return source;
|
||||
}
|
||||
function f7(x){
|
||||
return x;
|
||||
}
|
||||
SINK(compose1(f6, f7)());
|
||||
|
||||
function f8(x){
|
||||
return x;
|
||||
}
|
||||
function f9(x){
|
||||
return x;
|
||||
}
|
||||
SINK(compose1(f8, f9)(source));
|
||||
|
||||
|
||||
function f10(x){
|
||||
return x;
|
||||
}
|
||||
function f11(x){
|
||||
return x;
|
||||
}
|
||||
function f12(x){
|
||||
return x;
|
||||
}
|
||||
SINK(compose1(f10, f11, f12)(source));
|
||||
|
||||
function f13(x){
|
||||
return x + 'foo' ;
|
||||
}
|
||||
SINK(compose1(f13)(source));
|
||||
|
||||
function f14(){
|
||||
return undefined;
|
||||
}
|
||||
SINK(f14()); // NO FLOW
|
||||
|
||||
function f15(){
|
||||
return source;
|
||||
}
|
||||
function f16(){
|
||||
return undefined;
|
||||
}
|
||||
SINK(compose1(f15, f16)()); // NO FLOW
|
||||
|
||||
function f17(x, y){
|
||||
return y;
|
||||
}
|
||||
SINK(f17(source)); // NO FLOW
|
||||
|
||||
function f18(x, y){
|
||||
return y;
|
||||
}
|
||||
SINK(f18(undefined, source));
|
||||
|
||||
function f19(){
|
||||
return source;
|
||||
}
|
||||
SINK(compose2(f19)());
|
||||
|
||||
function f20(){
|
||||
return source;
|
||||
}
|
||||
SINK(compose3(f20)());
|
||||
|
||||
function f21(){
|
||||
return source;
|
||||
}
|
||||
SINK(compose4(f21)());
|
||||
|
||||
})();
|
Загрузка…
Ссылка в новой задаче