From 314333f7ed40a50d7f6eb79c29b93495e5c7a201 Mon Sep 17 00:00:00 2001 From: Stephan Brandauer Date: Wed, 30 Mar 2022 13:24:30 +0200 Subject: [PATCH] add functionInterfacesInFile and surroundingFunctionParameters features --- .../EndpointFeatures.qll | 90 ++++++++++++++++++- .../FeatureValue.expected | 54 ++++++++--- .../test/generic_feature_testing/test.js | 6 ++ 3 files changed, 137 insertions(+), 13 deletions(-) diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll index ead5f28e57f..216ea3cb791 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll @@ -219,7 +219,7 @@ predicate tokenFeatures(DataFlow::Node endpoint, string featureName, string feat } /** - * See EndpointFeauture + * See EndpointFeature */ private newtype TEndpointFeature = TEnclosingFunctionName() or @@ -234,7 +234,9 @@ private newtype TEndpointFeature = TCalleeImports() or TCalleeFlexibleAccessPath() or TInputAccessPathFromCallee() or - TInputArgumentIndex() + TInputArgumentIndex() or + TContextFunctionInterfacesInFile() or + TContextSurroundingFunctionParametersInFile() /** * An implementation of an endpoint feature: produces feature names and values for used in ML. @@ -440,6 +442,30 @@ class FileImports extends EndpointFeature, TFileImports { } } +/** + * The feature for the function parameters of the functions that enclose an endpoint. + */ +class ContextSurroundingFunctionParametersInFile extends EndpointFeature, + TContextSurroundingFunctionParametersInFile { + override string getName() { result = "contextSurroundingFunctionParametersInFile" } + + Function getRelevantFunction(DataFlow::Node endpoint) { + result = endpoint.asExpr().getEnclosingFunction*() + } + + override string getValue(DataFlow::Node endpoint) { + result = + concat(string functionParameterLine, Function f | + f = getRelevantFunction(endpoint) and + functionParameterLine = SyntacticUtilities::getFunctionParametersFeatureComponent(f) + | + functionParameterLine, "\n" + order by + f.getLocation().getStartLine(), f.getLocation().getStartColumn() + ) + } +} + /** * The feature for the imports used in the callee of an invocation. * @@ -475,6 +501,18 @@ class CalleeImports extends EndpointFeature, TCalleeImports { } } +/* + * The feature for the interfaces of all named functions in the same file as the endpoint. + */ + +class ContextFunctionInterfacesInFile extends EndpointFeature, TContextFunctionInterfacesInFile { + override string getName() { result = "contextFunctionInterfacesInFile" } + + override string getValue(DataFlow::Node endpoint) { + result = SyntacticUtilities::getFunctionInterfacesForFile(endpoint.getFile()) + } +} + /** * Syntactic utilities for feature value computation. */ @@ -484,6 +522,54 @@ private module SyntacticUtilities { result = any(Import imp | imp.getFile() = file).getImportedPath().getValue() } + /** + * Gets the feature component for the parameters of a function. + * + * ```javascript + * function f(a, b, c) { // will return "(a, b, c)" for this function + * return a + b + c; + * } + * + * async function g(a) { // will return "(a)" for this function + * return 2*a + * }; + * + * const h = (b) => 3*b; // will return "(b)" for this function + * ``` + */ + string getFunctionParametersFeatureComponent(Function f) { + result = + "(" + + concat(string parameter, int i | + parameter = f.getParameter(i).getName() + | + parameter, ", " order by i + ) + ")" + } + + /** + * Gets the function interfaces of all named functions in a file, concatenated together. + * + * ```javascript + * // Will return: "f(a, b, c)\ng(x, y, z)\nh(u, v)" for this file. + * function f(a, b, c) { ... } + * + * function g(x, y, z) { + * function h(u, v) { ... } + * ... + * } + */ + string getFunctionInterfacesForFile(File file) { + result = + concat(Function func, string line | + func.getFile() = file and + exists(func.getName()) and + line = func.getName() + getFunctionParametersFeatureComponent(func) + | + line, "\n" order by line + ) + } + /** * Gets a property initializer value in a an object literal or one of its nested object literals. */ 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 bb897cbaeb5..6014d9df208 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/FeatureValue.expected +++ b/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/FeatureValue.expected @@ -4,6 +4,8 @@ | test.html:2:61:2:68 | endpoint | calleeAccessPath | | | test.html:2:61:2:68 | endpoint | calleeAccessPathWithStructuralInfo | | | test.html:2:61:2:68 | endpoint | calleeName | item | +| test.html:2:61:2:68 | endpoint | contextFunctionInterfacesInFile | | +| test.html:2:61:2:68 | endpoint | contextSurroundingFunctionParametersInFile | | | test.html:2:61:2:68 | endpoint | fileImports | | | test.js:6:7:6:14 | endpoint | CalleeFlexibleAccessPath | f | | test.js:6:7:6:14 | endpoint | InputArgumentIndex | 0 | @@ -11,8 +13,10 @@ | test.js:6:7:6:14 | endpoint | calleeAccessPath | lib3 | | test.js:6:7:6:14 | endpoint | calleeAccessPathWithStructuralInfo | lib3 instanceorreturn | | test.js:6:7:6:14 | endpoint | calleeApiName | lib3 | -| test.js:6:7:6:14 | endpoint | calleeImports | lib3 | +| test.js:6:7:6:14 | endpoint | calleeImports | ? lib3 | | test.js:6:7:6:14 | endpoint | calleeName | f | +| test.js:6:7:6:14 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:6:7:6:14 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:6:7:6:14 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:6:7:6:14 | endpoint | enclosingFunctionName | | | test.js:6:7:6:14 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -21,7 +25,9 @@ | test.js:7:11:7:18 | endpoint | InputArgumentIndex | 0 | | test.js:7:11:7:18 | endpoint | calleeAccessPath | | | test.js:7:11:7:18 | endpoint | calleeAccessPathWithStructuralInfo | | -| test.js:7:11:7:18 | endpoint | calleeImports | lib3 | +| test.js:7:11:7:18 | endpoint | calleeImports | ? lib3 | +| test.js:7:11:7:18 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:7:11:7:18 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:7:11:7:18 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:7:11:7:18 | endpoint | enclosingFunctionName | | | test.js:7:11:7:18 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -30,7 +36,9 @@ | test.js:8:15:8:22 | endpoint | InputArgumentIndex | 0 | | test.js:8:15:8:22 | endpoint | calleeAccessPath | | | test.js:8:15:8:22 | endpoint | calleeAccessPathWithStructuralInfo | | -| test.js:8:15:8:22 | endpoint | calleeImports | lib3 | +| test.js:8:15:8:22 | endpoint | calleeImports | ? lib3 | +| test.js:8:15:8:22 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:8:15:8:22 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:8:15:8:22 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:8:15:8:22 | endpoint | enclosingFunctionName | | | test.js:8:15:8:22 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -40,8 +48,10 @@ | test.js:9:9:9:16 | endpoint | calleeAccessPath | lib2 m | | test.js:9:9:9:16 | endpoint | calleeAccessPathWithStructuralInfo | lib2 member m instanceorreturn | | test.js:9:9:9:16 | endpoint | calleeApiName | lib2 | -| test.js:9:9:9:16 | endpoint | calleeImports | lib2 | +| test.js:9:9:9:16 | endpoint | calleeImports | ? lib2 | | test.js:9:9:9:16 | endpoint | calleeName | m | +| test.js:9:9:9:16 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:9:9:9:16 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:9:9:9:16 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:9:9:9:16 | endpoint | enclosingFunctionName | | | test.js:9:9:9:16 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -51,7 +61,9 @@ | test.js:10:13:10:20 | endpoint | InputArgumentIndex | 0 | | test.js:10:13:10:20 | endpoint | calleeAccessPath | | | test.js:10:13:10:20 | endpoint | calleeAccessPathWithStructuralInfo | | -| test.js:10:13:10:20 | endpoint | calleeImports | lib2 | +| test.js:10:13:10:20 | endpoint | calleeImports | ? lib2 | +| test.js:10:13:10:20 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:10:13:10:20 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:10:13:10:20 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:10:13:10:20 | endpoint | enclosingFunctionName | | | test.js:10:13:10:20 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -60,7 +72,9 @@ | test.js:11:17:11:24 | endpoint | InputArgumentIndex | 0 | | test.js:11:17:11:24 | endpoint | calleeAccessPath | | | test.js:11:17:11:24 | endpoint | calleeAccessPathWithStructuralInfo | | -| test.js:11:17:11:24 | endpoint | calleeImports | lib2 | +| test.js:11:17:11:24 | endpoint | calleeImports | ? lib2 | +| test.js:11:17:11:24 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:11:17:11:24 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:11:17:11:24 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:11:17:11:24 | endpoint | enclosingFunctionName | | | test.js:11:17:11:24 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -69,6 +83,8 @@ | test.js:12:11:12:18 | endpoint | calleeAccessPath | | | test.js:12:11:12:18 | endpoint | calleeAccessPathWithStructuralInfo | | | test.js:12:11:12:18 | endpoint | calleeImports | lib1 | +| test.js:12:11:12:18 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:12:11:12:18 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:12:11:12:18 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:12:11:12:18 | endpoint | enclosingFunctionName | | | test.js:12:11:12:18 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -78,8 +94,10 @@ | test.js:13:17:13:24 | endpoint | calleeAccessPath | lib2 m m m | | test.js:13:17:13:24 | endpoint | calleeAccessPathWithStructuralInfo | lib2 member m instanceorreturn member m instanceorreturn member m instanceorreturn | | test.js:13:17:13:24 | endpoint | calleeApiName | lib2 | -| test.js:13:17:13:24 | endpoint | calleeImports | lib2 | +| test.js:13:17:13:24 | endpoint | calleeImports | ? lib2 | | test.js:13:17:13:24 | endpoint | calleeName | m | +| test.js:13:17:13:24 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:13:17:13:24 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:13:17:13:24 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:13:17:13:24 | endpoint | enclosingFunctionName | | | test.js:13:17:13:24 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -89,7 +107,9 @@ | test.js:14:9:14:16 | endpoint | calleeAccessPath | lib3 | | test.js:14:9:14:16 | endpoint | calleeAccessPathWithStructuralInfo | lib3 instanceorreturn instanceorreturn | | test.js:14:9:14:16 | endpoint | calleeApiName | lib3 | -| test.js:14:9:14:16 | endpoint | calleeImports | lib3 | +| test.js:14:9:14:16 | endpoint | calleeImports | ? lib3 | +| test.js:14:9:14:16 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:14:9:14:16 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:14:9:14:16 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:14:9:14:16 | endpoint | enclosingFunctionName | | | test.js:14:9:14:16 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -99,8 +119,10 @@ | test.js:15:12:15:19 | endpoint | calleeAccessPath | lib2 m | | test.js:15:12:15:19 | endpoint | calleeAccessPathWithStructuralInfo | lib2 member member m instanceorreturn | | test.js:15:12:15:19 | endpoint | calleeApiName | lib2 | -| test.js:15:12:15:19 | endpoint | calleeImports | lib2 | +| test.js:15:12:15:19 | endpoint | calleeImports | ? lib2 | | test.js:15:12:15:19 | endpoint | calleeName | m | +| test.js:15:12:15:19 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:15:12:15:19 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:15:12:15:19 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:15:12:15:19 | endpoint | enclosingFunctionName | | | test.js:15:12:15:19 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -110,8 +132,10 @@ | test.js:16:16:16:23 | endpoint | calleeAccessPath | lib2 m p m | | test.js:16:16:16:23 | endpoint | calleeAccessPathWithStructuralInfo | lib2 member m member member p member m instanceorreturn | | test.js:16:16:16:23 | endpoint | calleeApiName | lib2 | -| test.js:16:16:16:23 | endpoint | calleeImports | lib2 | +| test.js:16:16:16:23 | endpoint | calleeImports | ? lib2 | | test.js:16:16:16:23 | endpoint | calleeName | m | +| test.js:16:16:16:23 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:16:16:16:23 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:16:16:16:23 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:16:16:16:23 | endpoint | enclosingFunctionName | | | test.js:16:16:16:23 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -122,6 +146,8 @@ | test.js:17:15:17:22 | endpoint | calleeAccessPathWithStructuralInfo | lib1 member p instanceorreturn | | test.js:17:15:17:22 | endpoint | calleeApiName | lib1 | | test.js:17:15:17:22 | endpoint | calleeImports | lib1 | +| test.js:17:15:17:22 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:17:15:17:22 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:17:15:17:22 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:17:15:17:22 | endpoint | enclosingFunctionName | | | test.js:17:15:17:22 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -133,6 +159,8 @@ | test.js:18:27:18:34 | endpoint | calleeApiName | foo | | test.js:18:27:18:34 | endpoint | calleeImports | foo | | test.js:18:27:18:34 | endpoint | calleeName | baz | +| test.js:18:27:18:34 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:18:27:18:34 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:18:27:18:34 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:18:27:18:34 | endpoint | enclosingFunctionName | | | test.js:18:27:18:34 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -144,6 +172,8 @@ | test.js:20:13:20:20 | endpoint | calleeApiName | lib1 | | test.js:20:13:20:20 | endpoint | calleeImports | lib1 | | test.js:20:13:20:20 | endpoint | calleeName | bar | +| test.js:20:13:20:20 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:20:13:20:20 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:20:13:20:20 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:20:13:20:20 | endpoint | enclosingFunctionName | | | test.js:20:13:20:20 | endpoint | fileImports | foo lib1 lib2 lib3 | @@ -152,7 +182,9 @@ | test.js:22:21:22:28 | endpoint | calleeAccessPath | lib3 | | test.js:22:21:22:28 | endpoint | calleeAccessPathWithStructuralInfo | lib3 instanceorreturn | | test.js:22:21:22:28 | endpoint | calleeApiName | lib3 | -| test.js:22:21:22:28 | endpoint | calleeImports | lib2 lib3 | +| test.js:22:21:22:28 | endpoint | calleeImports | ? lib2 lib3 | +| test.js:22:21:22:28 | endpoint | contextFunctionInterfacesInFile | f(endpoint)\nfoo()\ng()\nm() | +| test.js:22:21:22:28 | endpoint | contextSurroundingFunctionParametersInFile | () | | test.js:22:21:22:28 | endpoint | enclosingFunctionBody | f endpoint f p endpoint f p q endpoint o m endpoint o m p endpoint o m p q endpoint F endpoint o m m m endpoint f endpoint o x m endpoint o m x p m endpoint p endpoint foo bar baz endpoint foo bar endpoint f f o m endpoint | | test.js:22:21:22:28 | endpoint | enclosingFunctionName | | | test.js:22:21:22:28 | endpoint | fileImports | foo lib1 lib2 lib3 | diff --git a/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/test.js b/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/test.js index ded708d5b9c..92bb10d58f9 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/test.js +++ b/javascript/ql/experimental/adaptivethreatmodeling/test/generic_feature_testing/test.js @@ -21,3 +21,9 @@ const f = require('lib3'); } (f() ? f : o.m)(endpoint); }); + +function f(endpoint) {} + +const g = async () => undefined; + +const o = { m: () => undefined }