JS: Add decorator edges in API graphs and corresponding MaD tokens

This commit is contained in:
Asger Feldthaus
2022-03-23 18:05:44 +01:00
parent e5f2b830f3
commit cf596a1856
7 changed files with 404 additions and 4 deletions

View File

@@ -0,0 +1,9 @@
import * as testlib from 'testlib';
// parameter decorators are only valid in TypeScript so this test is in a .ts file
class C {
decoratedParamSource(@testlib.ParamDecorator x) {
sink(x) // NOT OK
}
}

View File

@@ -1,5 +1,6 @@
consistencyIssue
taintFlow
| paramDecorator.ts:6:48:6:48 | x | paramDecorator.ts:7:10:7:10 | x |
| test.js:5:30:5:37 | source() | test.js:5:8:5:38 | testlib ... urce()) |
| test.js:6:22:6:29 | source() | test.js:6:8:6:30 | preserv ... urce()) |
| test.js:7:41:7:48 | source() | test.js:7:8:7:49 | require ... urce()) |
@@ -35,6 +36,25 @@ taintFlow
| test.js:97:17:97:24 | source() | test.js:97:17:97:24 | source() |
| test.js:102:16:102:34 | testlib.getSource() | test.js:103:8:103:13 | source |
| test.js:102:16:102:34 | testlib.getSource() | test.js:104:8:104:24 | source.continue() |
| test.js:111:12:111:19 | source() | test.js:111:12:111:19 | source() |
| test.js:113:17:113:17 | x | test.js:114:10:114:10 | x |
| test.js:132:10:132:25 | this.fieldSource | test.js:132:10:132:25 | this.fieldSource |
| test.js:133:10:133:37 | OtherCl ... dSource | test.js:133:10:133:37 | OtherCl ... dSource |
| test.js:134:22:134:29 | source() | test.js:134:22:134:29 | source() |
| test.js:135:34:135:41 | source() | test.js:135:34:135:41 | source() |
| test.js:144:16:144:23 | source() | test.js:144:16:144:23 | source() |
| test.js:147:29:147:36 | source() | test.js:147:29:147:36 | source() |
| test.js:150:19:150:19 | x | test.js:151:10:151:10 | x |
| test.js:152:12:152:19 | source() | test.js:152:12:152:19 | source() |
| test.js:156:32:156:32 | x | test.js:157:10:157:10 | x |
| test.js:158:12:158:19 | source() | test.js:158:12:158:19 | source() |
| test.js:162:20:162:20 | x | test.js:163:10:163:10 | x |
| test.js:164:12:164:19 | source() | test.js:164:12:164:19 | source() |
| test.js:172:12:172:19 | source() | test.js:172:12:172:19 | source() |
| test.js:176:23:176:23 | x | test.js:177:10:177:10 | x |
| test.js:182:12:182:19 | source() | test.js:182:12:182:19 | source() |
| test.js:187:31:187:31 | x | test.js:189:10:189:10 | x |
| test.js:203:32:203:39 | source() | test.js:203:32:203:39 | source() |
isSink
| test.js:54:18:54:25 | source() | test-sink |
| test.js:55:22:55:29 | source() | test-sink |
@@ -81,6 +101,18 @@ isSink
| test.js:95:17:95:24 | source() | test-sink |
| test.js:96:17:96:24 | source() | test-sink |
| test.js:97:17:97:24 | source() | test-sink |
| test.js:111:12:111:19 | source() | test-sink |
| test.js:134:22:134:29 | source() | test-sink |
| test.js:135:34:135:41 | source() | test-sink |
| test.js:144:16:144:23 | source() | test-sink |
| test.js:147:29:147:36 | source() | test-sink |
| test.js:152:12:152:19 | source() | test-sink |
| test.js:158:12:158:19 | source() | test-sink |
| test.js:164:12:164:19 | source() | test-sink |
| test.js:172:12:172:19 | source() | test-sink |
| test.js:182:12:182:19 | source() | test-sink |
| test.js:196:12:196:29 | this._wrappedField | test-sink |
| test.js:203:32:203:39 | source() | test-sink |
syntaxErrors
| Member[foo |
| Member[foo] .Member[bar] |

View File

@@ -104,3 +104,102 @@ function testFlowThroughReceiver() {
sink(source.continue()); // NOT OK
sink(source.blah()); // OK
}
@testlib.ClassDecorator
class DecoratedClass {
returnValueIsSink() {
return source(); // NOT OK
}
inputIsSource(x) {
sink(x); // NOT OK
}
}
class OtherClass {
@testlib.FieldDecoratorSink
fieldSink;
@testlib.FieldDecoratorSink
static staticFieldSink;
@testlib.FieldDecoratorSource
fieldSource;
@testlib.FieldDecoratorSource
static staticFieldSource;
useFields() {
sink(this.fieldSource); // NOT OK
sink(OtherClass.staticFieldSource); // NOT OK
this.fieldSink = source(); // NOT OK
OtherClass.staticFieldSink = source(); // NOT OK
sink(this.staticFieldSource); // OK - not a valid field access
sink(OtherClass.fieldSource); // OK - not a valid field access
this.staticFieldSink = source(); // OK - not a valid field access
OtherClass.fieldSink = source(); // OK - not a valid field access
}
@testlib.FieldDecoratorSink
fieldSink2 = source(); // NOT OK
@testlib.FieldDecoratorSink
static staticFieldSink2 = source(); // NOT OK
@testlib.MethodDecorator
decoratedMethod(x) {
sink(x); // NOT OK
return source(); // NOT OK
}
@testlib.MethodDecorator
static decoratedStaticMethod(x) {
sink(x); // NOT OK
return source(); // NOT OK
}
@testlib.MethodDecoratorWithArgs({ something: true })
decoratedMethod2(x) {
sink(x); // NOT OK
return source(); // NOT OK
}
@testlib.FieldDecoratorSink
get sinkViaGetter() {
// If a field with this decorator should be seen as a sink it generally means the framework
// will read it and pass it to an underlying sink. Therefore the return value of its getter
// should be seen as a sink as well.
return source(); // NOT OK
}
@testlib.FieldDecoratorSource
set sourceViaSetter(x) {
sink(x); // NOT OK
}
get sinkViaGetterIndirect() {
// Same as 'sinkViaGetter', but where the decorator is placed on the corresponding setter
return source(); // NOT OK
}
@testlib.FieldDecoratorSink // indirectly decorate the getter above
set sinkViaGetterIndirect(x) {}
set sourceViaSetterIndirect(x) {
// Same as 'sourceViaSetter', but where the decorator is placed on the corresponding getter
sink(x); // NOT OK
}
@testlib.FieldDecoratorSource // indirectly decorate the setter above
get sourceViaSetterIndirect() {}
@testlib.FieldDecoratorSink
get accessorAroundField() {
return this._wrappedField; // OK - the alert occurs at the assignment to 'accessorAroundField'
}
set accessorAroundField(x) {
this._wrappedField = x;
}
useWrappedField() {
this.accessorAroundField = source(); // NOT OK
}
}

View File

@@ -33,12 +33,26 @@ class Sinks extends ModelInput::SinkModelCsv {
"testlib;;Member[mySinkExceptLast].Argument[0..N-2];test-sink",
"testlib;;Member[mySinkIfArityTwo].WithArity[2].Argument[0];test-sink",
"testlib;;Member[sink1, sink2, sink3 ].Argument[0];test-sink",
"testlib;;Member[ClassDecorator].DecoratedClass.Instance.Member[returnValueIsSink].ReturnValue;test-sink",
"testlib;;Member[FieldDecoratorSink].DecoratedMember;test-sink",
"testlib;;Member[MethodDecorator].DecoratedMember.ReturnValue;test-sink",
"testlib;;Member[MethodDecoratorWithArgs].ReturnValue.DecoratedMember.ReturnValue;test-sink",
]
}
}
class Sources extends ModelInput::SourceModelCsv {
override predicate row(string row) { row = "testlib;;Member[getSource].ReturnValue;test-source" }
override predicate row(string row) {
row =
[
"testlib;;Member[getSource].ReturnValue;test-source",
"testlib;;Member[ClassDecorator].DecoratedClass.Instance.Member[inputIsSource].Parameter[0];test-source",
"testlib;;Member[FieldDecoratorSource].DecoratedMember;test-source",
"testlib;;Member[ParamDecorator].DecoratedParameter;test-source",
"testlib;;Member[MethodDecorator].DecoratedMember.Parameter[0];test-source",
"testlib;;Member[MethodDecoratorWithArgs].ReturnValue.DecoratedMember.Parameter[0];test-source",
]
}
}
class BasicTaintTracking extends TaintTracking::Configuration {