From 937d6b1f3e124a7b04193dc4da749dc339135613 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 30 Mar 2022 23:57:00 +0200 Subject: [PATCH] add more features --- .../EndpointFeatures.qll | 82 +++++++++++++++++-- .../FeatureValue.expected | 26 ++++++ 2 files changed, 99 insertions(+), 9 deletions(-) diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll index 77c4c7c4521..bfe81880281 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll @@ -233,7 +233,9 @@ private newtype TEndpointFeature = TCalleeAccessPathWithStructuralInfo() or TEnclosingFunctionBody() or TCalleeAccessPathSimpleFromArgumentTraversal() or - TParameterAccessPathSimpleFromArgumentTraversal() + TParameterAccessPathSimpleFromArgumentTraversal() or + TPropertyAccessPathSimpleFromArgumentTraversal() or + TArgumentIndexFromArgumentTraversal() /** * An implementation of an endpoint feature: produces feature names and values for used in ML. @@ -438,14 +440,25 @@ private module SyntacticUtilities { string getSimpleParameterAccessPath(DataFlow::Node node) { if exists(DataFlow::CallNode call | node = call.getArgument(_)) then exists(DataFlow::CallNode call, int i | node = call.getArgument(i) | result = i + "") - else - if exists(ObjectExpr o | o.getAProperty().getInit().getUnderlyingValue() = node.asExpr()) - then - exists(DataFlow::PropWrite w | - w.getRhs() = node and - result = getSimpleParameterAccessPath(w.getBase()) + "." + getPropertyNameOrUnknown(w) - ) - else result = "?" + else result = getSimplePropertyAccessPath(node) + } + + /** + * Computes a simple access path for how a user can refer to a value that appears in an (nested) object. + * + * Supports: + * - properties of (nested) objects + * + * Unknown cases and property names results in `?`. + */ + string getSimplePropertyAccessPath(DataFlow::Node node) { + if exists(ObjectExpr o | o.getAProperty().getInit().getUnderlyingValue() = node.asExpr()) + then + exists(DataFlow::PropWrite w | + w.getRhs() = node and + result = getSimpleParameterAccessPath(w.getBase()) + "." + getPropertyNameOrUnknown(w) + ) + else result = "?" } /** @@ -565,3 +578,54 @@ class ParameterAccessPathSimpleFromArgumentTraversal extends EndpointFeature, ) } } + +/** + * The feature for how a callee can refer to a the endpoint that is "contained" in a some argument to a call + * + * "Containment" is syntactic, and currently means that the endpoint is an argument to the call, or that the endpoint is a (nested) property value of an argument. + * + * This feature is intended as a superior version of the `ArgumentIndexFeature`. + */ +class PropertyAccessPathSimpleFromArgumentTraversal extends EndpointFeature, + TPropertyAccessPathSimpleFromArgumentTraversal { + override string getName() { result = "PropertyAccessPathSimpleFromArgumentTraversal" } + + private string getValueMaybe(DataFlow::Node endpoint) { + exists(DataFlow::InvokeNode invk | + result = SyntacticUtilities::getSimpleParameterAccessPath(endpoint) and + SyntacticUtilities::getANestedInitializerValue(invk.getAnArgument() + .asExpr() + .getUnderlyingValue()).flow() = endpoint + ) + } + + override string getValue(DataFlow::Node endpoint) { + if exists(this.getValueMaybe(endpoint)) + then result = this.getValueMaybe(endpoint) + else result = "" + } +} + +/** + * The feature for how the index of an argument that "contains" and endpoint. + * + * "Containment" is syntactic, and currently means that the endpoint is an argument to the call, or that the endpoint is a (nested) property value of an argument. + * + * This feature is intended as a superior version of the `ArgumentIndexFeature`. + */ +class ArgumentIndexFromArgumentTraversal extends EndpointFeature, + TArgumentIndexFromArgumentTraversal { + override string getName() { result = "ArgumentIndexFromArgumentTraversal" } + + override string getValue(DataFlow::Node endpoint) { + exists(DataFlow::InvokeNode invk, DataFlow::Node arg, int i | arg = invk.getArgument(i) | + result = i + "" and + ( + invk.getAnArgument() = endpoint + or + SyntacticUtilities::getANestedInitializerValue(arg.asExpr().getUnderlyingValue()).flow() = + endpoint + ) + ) + } +} diff --git a/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/FeatureValue.expected b/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/FeatureValue.expected index 1577c7aee41..60db997dd49 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/FeatureValue.expected +++ b/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/FeatureValue.expected @@ -1,66 +1,92 @@ +| test.html:2:61:2:68 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.html:2:61:2:68 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0 | +| test.html:2:61:2:68 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | | | test.html:2:61:2:68 | endpoint | argumentIndex | 0 | | test.html:2:61:2:68 | endpoint | calleeAccessPath | | | test.html:2:61:2:68 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | $event.target.files.item | | test.html:2:61:2:68 | endpoint | calleeAccessPathWithStructuralInfo | | | test.html:2:61:2:68 | endpoint | calleeName | item | +| test.js:2:7:2:14 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:2:7:2:14 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0 | +| test.js:2:7:2:14 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | | | test.js:2:7:2:14 | endpoint | argumentIndex | 0 | | test.js:2:7:2:14 | endpoint | calleeAccessPath | | | test.js:2:7:2:14 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | f | | test.js:2:7:2:14 | endpoint | calleeAccessPathWithStructuralInfo | | | test.js:2:7:2:14 | endpoint | calleeName | f | +| test.js:3:11:3:18 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:3:11:3:18 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0.p | +| test.js:3:11:3:18 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | 0.p | | test.js:3:11:3:18 | endpoint | calleeAccessPath | | | test.js:3:11:3:18 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | f | | test.js:3:11:3:18 | endpoint | calleeAccessPathWithStructuralInfo | | +| test.js:4:15:4:22 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:4:15:4:22 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0.p.q | +| test.js:4:15:4:22 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | 0.p.q | | test.js:4:15:4:22 | endpoint | calleeAccessPath | | | test.js:4:15:4:22 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | f | | test.js:4:15:4:22 | endpoint | calleeAccessPathWithStructuralInfo | | +| test.js:5:9:5:16 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:5:9:5:16 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0 | +| test.js:5:9:5:16 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | | | test.js:5:9:5:16 | endpoint | argumentIndex | 0 | | test.js:5:9:5:16 | endpoint | calleeAccessPath | | | test.js:5:9:5:16 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | o.m | | test.js:5:9:5:16 | endpoint | calleeAccessPathWithStructuralInfo | | | test.js:5:9:5:16 | endpoint | calleeName | m | | test.js:5:9:5:16 | endpoint | receiverName | o | +| test.js:6:13:6:20 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:6:13:6:20 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0.p | +| test.js:6:13:6:20 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | 0.p | | test.js:6:13:6:20 | endpoint | calleeAccessPath | | | test.js:6:13:6:20 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | o.m | | test.js:6:13:6:20 | endpoint | calleeAccessPathWithStructuralInfo | | +| test.js:7:17:7:24 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:7:17:7:24 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0.p.q | +| test.js:7:17:7:24 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | 0.p.q | | test.js:7:17:7:24 | endpoint | calleeAccessPath | | | test.js:7:17:7:24 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | o.m | | test.js:7:17:7:24 | endpoint | calleeAccessPathWithStructuralInfo | | +| test.js:8:11:8:18 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:8:11:8:18 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | ? | +| test.js:8:11:8:18 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | | | test.js:8:11:8:18 | endpoint | calleeAccessPath | | | test.js:8:11:8:18 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | F | | test.js:8:11:8:18 | endpoint | calleeAccessPathWithStructuralInfo | | +| test.js:9:17:9:24 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:9:17:9:24 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0 | +| test.js:9:17:9:24 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | | | test.js:9:17:9:24 | endpoint | argumentIndex | 0 | | test.js:9:17:9:24 | endpoint | calleeAccessPath | | | test.js:9:17:9:24 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | o.m().m().m | | test.js:9:17:9:24 | endpoint | calleeAccessPathWithStructuralInfo | | | test.js:9:17:9:24 | endpoint | calleeName | m | +| test.js:10:9:10:16 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:10:9:10:16 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0 | +| test.js:10:9:10:16 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | | | test.js:10:9:10:16 | endpoint | argumentIndex | 0 | | test.js:10:9:10:16 | endpoint | calleeAccessPath | | | test.js:10:9:10:16 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | f() | | test.js:10:9:10:16 | endpoint | calleeAccessPathWithStructuralInfo | | +| test.js:11:12:11:19 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:11:12:11:19 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0 | +| test.js:11:12:11:19 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | | | test.js:11:12:11:19 | endpoint | argumentIndex | 0 | | test.js:11:12:11:19 | endpoint | calleeAccessPath | | | test.js:11:12:11:19 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | o.?.m | | test.js:11:12:11:19 | endpoint | calleeAccessPathWithStructuralInfo | | | test.js:11:12:11:19 | endpoint | calleeName | m | +| test.js:12:16:12:23 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:12:16:12:23 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0 | +| test.js:12:16:12:23 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | | | test.js:12:16:12:23 | endpoint | argumentIndex | 0 | | test.js:12:16:12:23 | endpoint | calleeAccessPath | | | test.js:12:16:12:23 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | o.m.?.p.m | | test.js:12:16:12:23 | endpoint | calleeAccessPathWithStructuralInfo | | | test.js:12:16:12:23 | endpoint | calleeName | m | +| test.js:13:15:13:22 | endpoint | ArgumentIndexFromArgumentTraversal | 0 | | test.js:13:15:13:22 | endpoint | ParameterAccessPathSimpleFromArgumentTraversal | 0 | +| test.js:13:15:13:22 | endpoint | PropertyAccessPathSimpleFromArgumentTraversal | | | test.js:13:15:13:22 | endpoint | argumentIndex | 0 | | test.js:13:15:13:22 | endpoint | calleeAccessPath | | | test.js:13:15:13:22 | endpoint | calleeAccessPathSimpleFromArgumentTraversal | (await p) |