From e1a680cd867b454f34f9f7d7a5cd940e7a17ffaf Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 8 Apr 2020 19:10:35 -0400 Subject: [PATCH 001/111] Address improper URL authorization --- .../CWE-939/IncorrectURLVerification.java | 17 +++++ .../CWE-939/IncorrectURLVerification.qhelp | 30 +++++++++ .../CWE-939/IncorrectURLVerification.ql | 64 +++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 java/ql/src/experimental/CWE-939/IncorrectURLVerification.java create mode 100644 java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp create mode 100644 java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java new file mode 100644 index 00000000000..f7b42b483af --- /dev/null +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java @@ -0,0 +1,17 @@ +public boolean shouldOverrideUrlLoading(WebView view, String url) { + { + Uri uri = Uri.parse(url); + // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification + if (uri.getHost() != null && uri.getHost().endsWith("example.com")) { + return false; + } + } + + { + Uri uri = Uri.parse(url); + // GOOD: full domain match + if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) { + return false; + } + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp new file mode 100644 index 00000000000..d1526456c98 --- /dev/null +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp @@ -0,0 +1,30 @@ + + + + +

Apps that rely on URL Parsing to verify that a given URL is pointing to a trust server may be susceptible to many different ways to get URL parsing and verification wrong, which allows an attacker to register a fake site to break the access control.

+
+ + +

Verify the whole host and domain (FQDN) or check endsWith dot+domain.

+
+ + +

The following example shows two ways of verify host domain. In the 'BAD' case, +verification is implemented as partial domain match. In the 'GOOD' case, full domain is verified.

+ +
+ + +
  • +Common Android app vulnerabilities from Sebastian Porst of Google +
  • +
  • +Common Android app vulnerabilities from bugcrowd +
  • +CWE 939 +
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql new file mode 100644 index 00000000000..eed077ea0b9 --- /dev/null +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -0,0 +1,64 @@ +/** + * @id java/incorrect-url-verification + * @name Insertion of sensitive information into log files + * @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification. + * @kind problem + * @tags security + * external/cwe-939 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking +import DataFlow +import PathGraph + + +/** + * The Java class `android.net.Uri` and `java.net.URL`. + */ +class Uri extends RefType { + Uri() { + hasQualifiedName("android.net", "Uri") or + hasQualifiedName("java.net", "URL") + } +} + +/** + * The method `getHost()` declared in `android.net.Uri` and `java.net.URL`. + */ +class UriGetHostMethod extends Method { + UriGetHostMethod() { + getDeclaringType() instanceof Uri and + hasName("getHost") and + getNumberOfParameters() = 0 + } +} + +/** + * A library method that acts like `String.format` by formatting a number of + * its arguments according to a format string. + */ +class HostVerificationMethodAccess extends MethodAccess { + HostVerificationMethodAccess() { + ( + + this.getMethod().hasName("endsWith") or + this.getMethod().hasName("contains") or + this.getMethod().hasName("indexOf") + ) and + this.getMethod().getNumberOfParameters() = 1 and + ( + this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." or //string constant comparison + this.getArgument(0).(AddExpr).getLeftOperand().(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." or //var1+var2, check var1 starts with "." + this.getArgument(0).(AddExpr).getLeftOperand().(StringLiteral).getRepresentedString().charAt(0) != "." or //"."+var2, check string constant "." + exists (MethodAccess ma | this.getArgument(0) = ma and ma.getMethod().hasName("getString") and ma.getArgument(0).toString().indexOf("R.string") = 0) or //res.getString(R.string.key) + this.getArgument(0).(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." //check variable starts with "." + ) + } +} + +from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma +where hma.getQualifier() = uma and uma.getMethod() = um +select "Potentially improper URL verification with $@ in $@ having $@.", + hma, hma.getFile(), hma.getArgument(0), "user-provided value" \ No newline at end of file From b7f2d32fb0a3578d1022535940fd658151d42d21 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 8 Apr 2020 19:16:22 -0400 Subject: [PATCH 002/111] Address improper URL authorization --- .../CWE-939/IncorrectURLVerification.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java index f7b42b483af..1c06f05bc7e 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java @@ -1,17 +1,17 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { - { - Uri uri = Uri.parse(url); - // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification - if (uri.getHost() != null && uri.getHost().endsWith("example.com")) { - return false; - } - } + { + Uri uri = Uri.parse(url); + // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification + if (uri.getHost() != null && uri.getHost().endsWith("example.com")) { + return false; + } + } - { - Uri uri = Uri.parse(url); - // GOOD: full domain match - if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) { - return false; - } - } -} \ No newline at end of file + { + Uri uri = Uri.parse(url); + // GOOD: full domain match + if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) { + return false; + } + } +} From 46332d4849723561a4a55dd2bccfd72223eeb763 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 30 Apr 2020 12:24:38 +0100 Subject: [PATCH 003/111] C++: Eliminate recursion from toString(). --- cpp/ql/src/semmle/code/cpp/Namespace.qll | 15 ++++--- cpp/ql/src/semmle/code/cpp/Variable.qll | 43 +++++++++++++-------- cpp/ql/src/semmle/code/cpp/XML.qll | 4 +- cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll | 2 +- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index d53fda87c2f..fe112d70177 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -79,7 +79,10 @@ class Namespace extends NameQualifyingElement, @namespace { /** Gets the metric namespace. */ MetricNamespace getMetrics() { result = this } - override string toString() { result = this.getQualifiedName() } + /** Gets a version of the `QualifiedName` that is more suitable for display purposes. */ + string getFriendlyName() { result = this.getQualifiedName() } + + final override string toString() { result = getFriendlyName() } /** Gets a declaration of (part of) this namespace. */ NamespaceDeclarationEntry getADeclarationEntry() { result.getNamespace() = this } @@ -104,7 +107,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { namespace_decls(underlyingElement(this), unresolveElement(result), _, _) } - override string toString() { result = this.getNamespace().toString() } + override string toString() { result = this.getNamespace().getFriendlyName() } /** * Gets the location of the token preceding the namespace declaration @@ -150,7 +153,7 @@ class UsingDeclarationEntry extends UsingEntry { */ Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { result = "using " + this.getDeclaration().toString() } + override string toString() { result = "using declaration" } } /** @@ -169,7 +172,9 @@ class UsingDirectiveEntry extends UsingEntry { */ Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { result = "using namespace " + this.getNamespace().toString() } + override string toString() { + result = "using namespace " + this.getNamespace().getFriendlyName() + } } /** @@ -204,7 +209,7 @@ class GlobalNamespace extends Namespace { */ deprecated string getFullName() { result = this.getName() } - override string toString() { result = "(global namespace)" } + override string getFriendlyName() { result = "(global namespace)" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 4d546a736dc..3fe58cf6ee7 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -260,24 +260,33 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ int getIndex() { param_decl_bind(underlyingElement(this), result, _) } + string getAnonymousParameterDescription() { + not exists(getName()) and + exists(string idx | + idx = + ((getIndex() + 1).toString() + "th") + .replaceAll("1th", "1st") + .replaceAll("2th", "2nd") + .replaceAll("3th", "3rd") + .replaceAll("11st", "11th") + .replaceAll("12nd", "12th") + .replaceAll("13rd", "13th") and + if exists(getCanonicalName()) + then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter" + else result = "declaration of " + idx + " parameter" + ) + } + override string toString() { - if exists(getName()) - then result = super.toString() - else - exists(string idx | - idx = - ((getIndex() + 1).toString() + "th") - .replaceAll("1th", "1st") - .replaceAll("2th", "2nd") - .replaceAll("3th", "3rd") - .replaceAll("11st", "11th") - .replaceAll("12nd", "12th") - .replaceAll("13rd", "13th") - | - if exists(getCanonicalName()) - then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter" - else result = "declaration of " + idx + " parameter" - ) + isDefinition() and + result = "definition of " + getName() + or + not isDefinition() and + if getName() = getCanonicalName() + then result = "declaration of " + getName() + else result = "declaration of " + getCanonicalName() + " as " + getName() + or + result = getAnonymousParameterDescription() } /** diff --git a/cpp/ql/src/semmle/code/cpp/XML.qll b/cpp/ql/src/semmle/code/cpp/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/cpp/ql/src/semmle/code/cpp/XML.qll +++ b/cpp/ql/src/semmle/code/cpp/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll index f634d9239b3..35d0ccb75a0 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll @@ -99,7 +99,7 @@ class Closure extends Class { * ``` */ class LambdaCapture extends Locatable, @lambdacapture { - override string toString() { result = getField().toString() } + override string toString() { result = getField().getName() } override string getCanonicalQLClass() { result = "LambdaCapture" } From 3b1dad84b3126d430d7eb1f125aca8da8d847fb9 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 4 May 2020 07:39:45 -0400 Subject: [PATCH 004/111] The query help builder will interpret and automatically add the reference so this isn't needed here. And one typo is corrected. --- .../experimental/CWE-939/IncorrectURLVerification.qhelp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp index d1526456c98..32bf6785825 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp @@ -12,7 +12,7 @@ -

    The following example shows two ways of verify host domain. In the 'BAD' case, +

    The following example shows two ways of verifying host domain. In the 'BAD' case, verification is implemented as partial domain match. In the 'GOOD' case, full domain is verified.

    @@ -23,8 +23,5 @@ verification is implemented as partial domain match. In the 'GOOD' case, full do
  • Common Android app vulnerabilities from bugcrowd -
  • -CWE 939 -
  • - \ No newline at end of file + From 9fc37d174e7b3d35ad9b56685a76627686d7afd5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 4 May 2020 17:33:52 +0100 Subject: [PATCH 005/111] C++: Update the 'usings' tests. --- cpp/ql/test/library-tests/usings/Usings1.expected | 12 ++++++------ cpp/ql/test/library-tests/usings/Usings2.expected | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cpp/ql/test/library-tests/usings/Usings1.expected b/cpp/ql/test/library-tests/usings/Usings1.expected index 29fc4ebd652..60f6880ee20 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.expected +++ b/cpp/ql/test/library-tests/usings/Usings1.expected @@ -1,7 +1,7 @@ -| templates.cpp:9:5:9:14 | using c | -| usings.cpp:8:1:8:11 | using nf | +| templates.cpp:9:5:9:14 | using declaration | +| usings.cpp:8:1:8:11 | using declaration | | usings.cpp:9:1:9:17 | using namespace N | -| usings.cpp:18:3:18:13 | using bf | -| usings.cpp:21:5:21:14 | using gf | -| usings.cpp:34:3:34:20 | using tbf | -| usings.cpp:42:5:42:22 | using foo | +| usings.cpp:18:3:18:13 | using declaration | +| usings.cpp:21:5:21:14 | using declaration | +| usings.cpp:34:3:34:20 | using declaration | +| usings.cpp:42:5:42:22 | using declaration | diff --git a/cpp/ql/test/library-tests/usings/Usings2.expected b/cpp/ql/test/library-tests/usings/Usings2.expected index bb23b50e41a..d8e0efbe299 100644 --- a/cpp/ql/test/library-tests/usings/Usings2.expected +++ b/cpp/ql/test/library-tests/usings/Usings2.expected @@ -1,7 +1,7 @@ -| templates.cpp:9:5:9:14 | using c | file://:0:0:0:0 | std | -| usings.cpp:8:1:8:11 | using nf | file://:0:0:0:0 | (global namespace) | +| templates.cpp:9:5:9:14 | using declaration | file://:0:0:0:0 | std | +| usings.cpp:8:1:8:11 | using declaration | file://:0:0:0:0 | (global namespace) | | usings.cpp:9:1:9:17 | using namespace N | file://:0:0:0:0 | (global namespace) | -| usings.cpp:18:3:18:13 | using bf | usings.cpp:16:8:16:8 | D | -| usings.cpp:21:5:21:14 | using gf | usings.cpp:20:13:23:3 | { ... } | -| usings.cpp:34:3:34:20 | using tbf | usings.cpp:32:8:32:9 | TD | -| usings.cpp:42:5:42:22 | using foo | usings.cpp:41:11:41:15 | nsbar | +| usings.cpp:18:3:18:13 | using declaration | usings.cpp:16:8:16:8 | D | +| usings.cpp:21:5:21:14 | using declaration | usings.cpp:20:13:23:3 | { ... } | +| usings.cpp:34:3:34:20 | using declaration | usings.cpp:32:8:32:9 | TD | +| usings.cpp:42:5:42:22 | using declaration | usings.cpp:41:11:41:15 | nsbar | From 3d431607e7fe70834234cd7d6f858a36f635b9db Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 4 May 2020 17:24:04 +0100 Subject: [PATCH 006/111] C++: Combine the usings tests and add detail about classes. --- cpp/ql/test/library-tests/usings/Usings1.expected | 14 +++++++------- cpp/ql/test/library-tests/usings/Usings1.ql | 12 +++++++++++- cpp/ql/test/library-tests/usings/Usings2.expected | 7 ------- cpp/ql/test/library-tests/usings/Usings2.ql | 5 ----- 4 files changed, 18 insertions(+), 20 deletions(-) delete mode 100644 cpp/ql/test/library-tests/usings/Usings2.expected delete mode 100644 cpp/ql/test/library-tests/usings/Usings2.ql diff --git a/cpp/ql/test/library-tests/usings/Usings1.expected b/cpp/ql/test/library-tests/usings/Usings1.expected index 60f6880ee20..9add0766111 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.expected +++ b/cpp/ql/test/library-tests/usings/Usings1.expected @@ -1,7 +1,7 @@ -| templates.cpp:9:5:9:14 | using declaration | -| usings.cpp:8:1:8:11 | using declaration | -| usings.cpp:9:1:9:17 | using namespace N | -| usings.cpp:18:3:18:13 | using declaration | -| usings.cpp:21:5:21:14 | using declaration | -| usings.cpp:34:3:34:20 | using declaration | -| usings.cpp:42:5:42:22 | using declaration | +| templates.cpp:9:5:9:14 | using declaration | UsingDeclarationEntry, enclosingElement:std | +| usings.cpp:8:1:8:11 | using declaration | UsingDeclarationEntry, enclosingElement:(global namespace) | +| usings.cpp:9:1:9:17 | using namespace N | UsingDirectiveEntry, enclosingElement:(global namespace) | +| usings.cpp:18:3:18:13 | using declaration | UsingDeclarationEntry, enclosingElement:D | +| usings.cpp:21:5:21:14 | using declaration | UsingDeclarationEntry, enclosingElement:{ ... } | +| usings.cpp:34:3:34:20 | using declaration | UsingDeclarationEntry, enclosingElement:TD | +| usings.cpp:42:5:42:22 | using declaration | UsingDeclarationEntry, enclosingElement:nsbar | diff --git a/cpp/ql/test/library-tests/usings/Usings1.ql b/cpp/ql/test/library-tests/usings/Usings1.ql index 5e374a82059..2011c196571 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.ql +++ b/cpp/ql/test/library-tests/usings/Usings1.ql @@ -1,4 +1,14 @@ import cpp +string describe(UsingEntry ue) { + ue instanceof UsingDeclarationEntry and + result = "UsingDeclarationEntry" + or + ue instanceof UsingDirectiveEntry and + result = "UsingDirectiveEntry" + or + result = "enclosingElement:" + ue.getEnclosingElement().toString() +} + from UsingEntry ue -select ue +select ue, concat(describe(ue), ", ") diff --git a/cpp/ql/test/library-tests/usings/Usings2.expected b/cpp/ql/test/library-tests/usings/Usings2.expected deleted file mode 100644 index d8e0efbe299..00000000000 --- a/cpp/ql/test/library-tests/usings/Usings2.expected +++ /dev/null @@ -1,7 +0,0 @@ -| templates.cpp:9:5:9:14 | using declaration | file://:0:0:0:0 | std | -| usings.cpp:8:1:8:11 | using declaration | file://:0:0:0:0 | (global namespace) | -| usings.cpp:9:1:9:17 | using namespace N | file://:0:0:0:0 | (global namespace) | -| usings.cpp:18:3:18:13 | using declaration | usings.cpp:16:8:16:8 | D | -| usings.cpp:21:5:21:14 | using declaration | usings.cpp:20:13:23:3 | { ... } | -| usings.cpp:34:3:34:20 | using declaration | usings.cpp:32:8:32:9 | TD | -| usings.cpp:42:5:42:22 | using declaration | usings.cpp:41:11:41:15 | nsbar | diff --git a/cpp/ql/test/library-tests/usings/Usings2.ql b/cpp/ql/test/library-tests/usings/Usings2.ql deleted file mode 100644 index bc4a076b0c5..00000000000 --- a/cpp/ql/test/library-tests/usings/Usings2.ql +++ /dev/null @@ -1,5 +0,0 @@ -import cpp - -from UsingEntry ue, Element e -where e = ue.getEnclosingElement() -select ue, e From 511d7c91997958f08d56f4422b69b306d5efc1bc Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 4 May 2020 15:07:32 +0100 Subject: [PATCH 007/111] C++: Improve solution for UsingDeclarationEntry. --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 7 ++++++- cpp/ql/src/semmle/code/cpp/Namespace.qll | 2 +- cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll | 2 +- cpp/ql/test/library-tests/usings/Usings1.expected | 12 ++++++------ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 840705b01b5..a4a4a4af2e6 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -98,7 +98,12 @@ class Declaration extends Locatable, @declaration { this.hasQualifiedName(namespaceQualifier, "", baseName) } - override string toString() { result = this.getName() } + /** + * Gets a description of this `Declaration` for display purposes. + */ + string getDescription() { result = this.getName() } + + final override string toString() { result = this.getDescription() } /** * Gets the name of this declaration. diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index fe112d70177..da6b1559cfa 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -153,7 +153,7 @@ class UsingDeclarationEntry extends UsingEntry { */ Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { result = "using declaration" } + override string toString() { result = "using " + this.getDeclaration().getDescription() } } /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll index 35d0ccb75a0..4a5b1b21c8d 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll @@ -86,7 +86,7 @@ class Closure extends Class { result.getName() = "operator()" } - override string toString() { result = "decltype([...](...){...})" } + override string getDescription() { result = "decltype([...](...){...})" } } /** diff --git a/cpp/ql/test/library-tests/usings/Usings1.expected b/cpp/ql/test/library-tests/usings/Usings1.expected index 9add0766111..c29cf7dd11f 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.expected +++ b/cpp/ql/test/library-tests/usings/Usings1.expected @@ -1,7 +1,7 @@ -| templates.cpp:9:5:9:14 | using declaration | UsingDeclarationEntry, enclosingElement:std | -| usings.cpp:8:1:8:11 | using declaration | UsingDeclarationEntry, enclosingElement:(global namespace) | +| templates.cpp:9:5:9:14 | using c | UsingDeclarationEntry, enclosingElement:std | +| usings.cpp:8:1:8:11 | using nf | UsingDeclarationEntry, enclosingElement:(global namespace) | | usings.cpp:9:1:9:17 | using namespace N | UsingDirectiveEntry, enclosingElement:(global namespace) | -| usings.cpp:18:3:18:13 | using declaration | UsingDeclarationEntry, enclosingElement:D | -| usings.cpp:21:5:21:14 | using declaration | UsingDeclarationEntry, enclosingElement:{ ... } | -| usings.cpp:34:3:34:20 | using declaration | UsingDeclarationEntry, enclosingElement:TD | -| usings.cpp:42:5:42:22 | using declaration | UsingDeclarationEntry, enclosingElement:nsbar | +| usings.cpp:18:3:18:13 | using bf | UsingDeclarationEntry, enclosingElement:D | +| usings.cpp:21:5:21:14 | using gf | UsingDeclarationEntry, enclosingElement:{ ... } | +| usings.cpp:34:3:34:20 | using tbf | UsingDeclarationEntry, enclosingElement:TD | +| usings.cpp:42:5:42:22 | using foo | UsingDeclarationEntry, enclosingElement:nsbar | From 7b8b4af6d2e4993d50d061006b8aa70b61ecd245 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:49:19 +0200 Subject: [PATCH 008/111] Python: Add test for call.getFunction().refersTo Showing that `call.getFunction().refersTo(func)` gives different results from `call = func.getACall()` --- .../test/library-tests/PointsTo/calls/CallRefersTo.expected | 5 +++++ python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql | 5 +++++ .../PointsTo/calls/{Call.expected => GetACall.expected} | 0 .../library-tests/PointsTo/calls/{Call.ql => GetACall.ql} | 0 4 files changed, 10 insertions(+) create mode 100644 python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql rename python/ql/test/library-tests/PointsTo/calls/{Call.expected => GetACall.expected} (100%) rename python/ql/test/library-tests/PointsTo/calls/{Call.ql => GetACall.ql} (100%) diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected new file mode 100644 index 00000000000..3577ecd8f3d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected @@ -0,0 +1,5 @@ +| 19 | ControlFlowNode for f() | Function f | +| 21 | ControlFlowNode for f() | Function f | +| 25 | ControlFlowNode for Attribute() | Function n | +| 33 | ControlFlowNode for Attribute() | Function foo | +| 34 | ControlFlowNode for Attribute() | Function foo | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql new file mode 100644 index 00000000000..3ec4bab321c --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql @@ -0,0 +1,5 @@ +import python + +from CallNode call, FunctionObject func +where call.getFunction().refersTo(func) +select call.getLocation().getStartLine(), call.toString(), func.toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/Call.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected similarity index 100% rename from python/ql/test/library-tests/PointsTo/calls/Call.expected rename to python/ql/test/library-tests/PointsTo/calls/GetACall.expected diff --git a/python/ql/test/library-tests/PointsTo/calls/Call.ql b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql similarity index 100% rename from python/ql/test/library-tests/PointsTo/calls/Call.ql rename to python/ql/test/library-tests/PointsTo/calls/GetACall.ql From a5289bd708a042a13af1e5b31c589e639488defa Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:49:47 +0200 Subject: [PATCH 009/111] Python: Use Object in CallRefersTo test Since other things than FunctionObject can be called ;) --- .../test/library-tests/PointsTo/calls/CallRefersTo.expected | 5 +++++ python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected index 3577ecd8f3d..4aad2c687f5 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected @@ -1,5 +1,10 @@ | 19 | ControlFlowNode for f() | Function f | | 21 | ControlFlowNode for f() | Function f | +| 22 | ControlFlowNode for C() | class C | +| 23 | ControlFlowNode for Attribute() | Attribute | +| 24 | ControlFlowNode for Attribute() | Attribute | | 25 | ControlFlowNode for Attribute() | Function n | +| 29 | ControlFlowNode for staticmethod() | builtin-class staticmethod | | 33 | ControlFlowNode for Attribute() | Function foo | | 34 | ControlFlowNode for Attribute() | Function foo | +| 34 | ControlFlowNode for D() | class D | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql index 3ec4bab321c..d3fc5903ca2 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql +++ b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql @@ -1,5 +1,5 @@ import python -from CallNode call, FunctionObject func +from CallNode call, Object func where call.getFunction().refersTo(func) select call.getLocation().getStartLine(), call.toString(), func.toString() From 06b67e0d32c37424b50bfcea7efe95460ef5d761 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:49:57 +0200 Subject: [PATCH 010/111] Python: Modernise test/library-tests/PointsTo/calls/* --- .../library-tests/PointsTo/calls/Argument.expected | 12 ++++++------ .../ql/test/library-tests/PointsTo/calls/Argument.ql | 2 +- .../PointsTo/calls/CallPointsTo.expected | 10 ++++++++++ .../calls/{CallRefersTo.ql => CallPointsTo.ql} | 4 ++-- .../PointsTo/calls/CallRefersTo.expected | 10 ---------- .../library-tests/PointsTo/calls/GetACall.expected | 8 ++++---- .../ql/test/library-tests/PointsTo/calls/GetACall.ql | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) create mode 100644 python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected rename python/ql/test/library-tests/PointsTo/calls/{CallRefersTo.ql => CallPointsTo.ql} (55%) delete mode 100644 python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.expected b/python/ql/test/library-tests/PointsTo/calls/Argument.expected index dbc7e586f47..267f817df32 100644 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.expected +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.expected @@ -7,9 +7,9 @@ | 23 | 0 | ControlFlowNode for c | Function f | | 23 | 1 | ControlFlowNode for w | Function f | | 23 | 2 | ControlFlowNode for z | Function f | -| 24 | 0 | ControlFlowNode for c | Function n | -| 24 | 1 | ControlFlowNode for x | Function n | -| 25 | 0 | ControlFlowNode for y | Function n | -| 25 | 1 | ControlFlowNode for z | Function n | -| 33 | 0 | ControlFlowNode for IntegerLiteral | Function foo | -| 34 | 0 | ControlFlowNode for IntegerLiteral | Function foo | +| 24 | 0 | ControlFlowNode for c | Function C.n | +| 24 | 1 | ControlFlowNode for x | Function C.n | +| 25 | 0 | ControlFlowNode for y | Function C.n | +| 25 | 1 | ControlFlowNode for z | Function C.n | +| 33 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | +| 34 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.ql b/python/ql/test/library-tests/PointsTo/calls/Argument.ql index 1678c02c182..d759489aa78 100644 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.ql +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.ql @@ -1,5 +1,5 @@ import python -from ControlFlowNode arg, FunctionObject func, int i +from ControlFlowNode arg, FunctionValue func, int i where arg = func.getArgumentForCall(_, i) select arg.getLocation().getStartLine(), i, arg.toString(), func.toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected new file mode 100644 index 00000000000..cce0d04f29d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -0,0 +1,10 @@ +| 19 | ControlFlowNode for f() | Function f | +| 21 | ControlFlowNode for f() | Function f | +| 22 | ControlFlowNode for C() | class C | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | +| 25 | ControlFlowNode for Attribute() | Function C.n | +| 29 | ControlFlowNode for staticmethod() | builtin-class staticmethod | +| 33 | ControlFlowNode for Attribute() | Function D.foo | +| 34 | ControlFlowNode for Attribute() | Function D.foo | +| 34 | ControlFlowNode for D() | class D | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.ql similarity index 55% rename from python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql rename to python/ql/test/library-tests/PointsTo/calls/CallPointsTo.ql index d3fc5903ca2..10247a98f94 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.ql @@ -1,5 +1,5 @@ import python -from CallNode call, Object func -where call.getFunction().refersTo(func) +from CallNode call, Value func +where call.getFunction().pointsTo(func) select call.getLocation().getStartLine(), call.toString(), func.toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected deleted file mode 100644 index 4aad2c687f5..00000000000 --- a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected +++ /dev/null @@ -1,10 +0,0 @@ -| 19 | ControlFlowNode for f() | Function f | -| 21 | ControlFlowNode for f() | Function f | -| 22 | ControlFlowNode for C() | class C | -| 23 | ControlFlowNode for Attribute() | Attribute | -| 24 | ControlFlowNode for Attribute() | Attribute | -| 25 | ControlFlowNode for Attribute() | Function n | -| 29 | ControlFlowNode for staticmethod() | builtin-class staticmethod | -| 33 | ControlFlowNode for Attribute() | Function foo | -| 34 | ControlFlowNode for Attribute() | Function foo | -| 34 | ControlFlowNode for D() | class D | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 9e9c5646d89..8474a100b5d 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -1,7 +1,7 @@ | 19 | ControlFlowNode for f() | Function f | | 21 | ControlFlowNode for f() | Function f | | 23 | ControlFlowNode for Attribute() | Function f | -| 24 | ControlFlowNode for Attribute() | Function n | -| 25 | ControlFlowNode for Attribute() | Function n | -| 33 | ControlFlowNode for Attribute() | Function foo | -| 34 | ControlFlowNode for Attribute() | Function foo | +| 24 | ControlFlowNode for Attribute() | Function C.n | +| 25 | ControlFlowNode for Attribute() | Function C.n | +| 33 | ControlFlowNode for Attribute() | Function D.foo | +| 34 | ControlFlowNode for Attribute() | Function D.foo | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql index 94c4212cc64..9e0b33a9814 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql @@ -1,5 +1,5 @@ import python -from ControlFlowNode call, FunctionObject func +from ControlFlowNode call, FunctionValue func where call = func.getACall() select call.getLocation().getStartLine(), call.toString(), func.toString() From f624754390850db9b8ead359256e1c8a3a8a73a1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:06 +0200 Subject: [PATCH 011/111] Python: Use Value in GetACAll test That was not possible when using the old Object-API, but in Value-API getACall is defined on all Values. --- .../ql/test/library-tests/PointsTo/calls/GetACall.expected | 5 +++++ python/ql/test/library-tests/PointsTo/calls/GetACall.ql | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 8474a100b5d..9e075ab473b 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -1,7 +1,12 @@ | 19 | ControlFlowNode for f() | Function f | | 21 | ControlFlowNode for f() | Function f | +| 22 | ControlFlowNode for C() | class C | | 23 | ControlFlowNode for Attribute() | Function f | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | | 24 | ControlFlowNode for Attribute() | Function C.n | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | | 25 | ControlFlowNode for Attribute() | Function C.n | +| 29 | ControlFlowNode for staticmethod() | builtin-class staticmethod | | 33 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for Attribute() | Function D.foo | +| 34 | ControlFlowNode for D() | class D | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql index 9e0b33a9814..84f2ab4fb4a 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql @@ -1,5 +1,5 @@ import python -from ControlFlowNode call, FunctionValue func +from ControlFlowNode call, Value func where call = func.getACall() select call.getLocation().getStartLine(), call.toString(), func.toString() From fc0b0221f0d12735871127a5e9e606cf0dcb200d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:14 +0200 Subject: [PATCH 012/111] Python: Add test-cases for BuiltinFunction and BuiltinMethod --- python/ql/test/library-tests/PointsTo/calls/Argument.expected | 3 +++ .../test/library-tests/PointsTo/calls/CallPointsTo.expected | 2 ++ python/ql/test/library-tests/PointsTo/calls/GetACall.expected | 3 +++ python/ql/test/library-tests/PointsTo/calls/test.py | 4 ++++ 4 files changed, 12 insertions(+) diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.expected b/python/ql/test/library-tests/PointsTo/calls/Argument.expected index 267f817df32..6b1df340e6c 100644 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.expected +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.expected @@ -13,3 +13,6 @@ | 25 | 1 | ControlFlowNode for z | Function C.n | | 33 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | | 34 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | +| 37 | 0 | ControlFlowNode for l | builtin method append | +| 37 | 1 | ControlFlowNode for IntegerLiteral | builtin method append | +| 38 | 0 | ControlFlowNode for l | Builtin-function len | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected index cce0d04f29d..f896183ede8 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -8,3 +8,5 @@ | 33 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for D() | class D | +| 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | +| 38 | ControlFlowNode for len() | Builtin-function len | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 9e075ab473b..0006b5a34af 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -10,3 +10,6 @@ | 33 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for D() | class D | +| 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | +| 37 | ControlFlowNode for Attribute() | builtin method append | +| 38 | ControlFlowNode for len() | Builtin-function len | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index 38667a4a6e1..19475ac84b1 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -32,3 +32,7 @@ class D(object): D.foo(1) D().foo(2) + +l = [1,2,3] +l.append(4) +len(l) From 9ec32ee1c1ff1bce6cbc26d16b132b901e0023e5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:19 +0200 Subject: [PATCH 013/111] Python: Add test-cases using keyword arguments --- .../ql/test/library-tests/PointsTo/calls/Argument.expected | 5 +++++ .../test/library-tests/PointsTo/calls/CallPointsTo.expected | 3 +++ .../ql/test/library-tests/PointsTo/calls/GetACall.expected | 4 ++++ python/ql/test/library-tests/PointsTo/calls/test.py | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.expected b/python/ql/test/library-tests/PointsTo/calls/Argument.expected index 6b1df340e6c..8e2ab22f33b 100644 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.expected +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.expected @@ -16,3 +16,8 @@ | 37 | 0 | ControlFlowNode for l | builtin method append | | 37 | 1 | ControlFlowNode for IntegerLiteral | builtin method append | | 38 | 0 | ControlFlowNode for l | Builtin-function len | +| 40 | 0 | ControlFlowNode for IntegerLiteral | Function f | +| 40 | 1 | ControlFlowNode for IntegerLiteral | Function f | +| 40 | 2 | ControlFlowNode for IntegerLiteral | Function f | +| 42 | 0 | ControlFlowNode for IntegerLiteral | Function C.n | +| 42 | 0 | ControlFlowNode for c | Function C.n | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected index f896183ede8..627f433b847 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -10,3 +10,6 @@ | 34 | ControlFlowNode for D() | class D | | 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | | 38 | ControlFlowNode for len() | Builtin-function len | +| 40 | ControlFlowNode for f() | Function f | +| 41 | ControlFlowNode for C() | class C | +| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 0006b5a34af..dc3ac87cdf1 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -13,3 +13,7 @@ | 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | | 37 | ControlFlowNode for Attribute() | builtin method append | | 38 | ControlFlowNode for len() | Builtin-function len | +| 40 | ControlFlowNode for f() | Function f | +| 41 | ControlFlowNode for C() | class C | +| 42 | ControlFlowNode for Attribute() | Function C.n | +| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index 19475ac84b1..0b5a7237e7a 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -36,3 +36,7 @@ D().foo(2) l = [1,2,3] l.append(4) len(l) + +f(arg0=0, arg1=1, arg2=2) +c = C() +c.n(arg1=1) From acb506db21d1de039c77118868fcd07be8971437 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:32 +0200 Subject: [PATCH 014/111] Python: Add test for getNamedArgumentForCall and rename the one for getArgumentForCall --- .../PointsTo/calls/Argument.expected | 23 ------------------- .../library-tests/PointsTo/calls/Argument.ql | 5 ---- .../calls/getArgumentForCall.expected | 23 +++++++++++++++++++ .../PointsTo/calls/getArgumentForCall.ql | 5 ++++ .../calls/getNamedArgumentForCall.expected | 21 +++++++++++++++++ .../PointsTo/calls/getNamedArgumentForCall.ql | 5 ++++ 6 files changed, 54 insertions(+), 28 deletions(-) delete mode 100644 python/ql/test/library-tests/PointsTo/calls/Argument.expected delete mode 100644 python/ql/test/library-tests/PointsTo/calls/Argument.ql create mode 100644 python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql create mode 100644 python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.expected b/python/ql/test/library-tests/PointsTo/calls/Argument.expected deleted file mode 100644 index 8e2ab22f33b..00000000000 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.expected +++ /dev/null @@ -1,23 +0,0 @@ -| 19 | 0 | ControlFlowNode for w | Function f | -| 19 | 1 | ControlFlowNode for x | Function f | -| 19 | 2 | ControlFlowNode for y | Function f | -| 21 | 0 | ControlFlowNode for y | Function f | -| 21 | 1 | ControlFlowNode for w | Function f | -| 21 | 2 | ControlFlowNode for z | Function f | -| 23 | 0 | ControlFlowNode for c | Function f | -| 23 | 1 | ControlFlowNode for w | Function f | -| 23 | 2 | ControlFlowNode for z | Function f | -| 24 | 0 | ControlFlowNode for c | Function C.n | -| 24 | 1 | ControlFlowNode for x | Function C.n | -| 25 | 0 | ControlFlowNode for y | Function C.n | -| 25 | 1 | ControlFlowNode for z | Function C.n | -| 33 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | -| 34 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | -| 37 | 0 | ControlFlowNode for l | builtin method append | -| 37 | 1 | ControlFlowNode for IntegerLiteral | builtin method append | -| 38 | 0 | ControlFlowNode for l | Builtin-function len | -| 40 | 0 | ControlFlowNode for IntegerLiteral | Function f | -| 40 | 1 | ControlFlowNode for IntegerLiteral | Function f | -| 40 | 2 | ControlFlowNode for IntegerLiteral | Function f | -| 42 | 0 | ControlFlowNode for IntegerLiteral | Function C.n | -| 42 | 0 | ControlFlowNode for c | Function C.n | diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.ql b/python/ql/test/library-tests/PointsTo/calls/Argument.ql deleted file mode 100644 index d759489aa78..00000000000 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python - -from ControlFlowNode arg, FunctionValue func, int i -where arg = func.getArgumentForCall(_, i) -select arg.getLocation().getStartLine(), i, arg.toString(), func.toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected new file mode 100644 index 00000000000..a65106bf723 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -0,0 +1,23 @@ +| 19 | ControlFlowNode for f() | Function f | 0 | ControlFlowNode for w | +| 19 | ControlFlowNode for f() | Function f | 1 | ControlFlowNode for x | +| 19 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for y | +| 21 | ControlFlowNode for f() | Function f | 0 | ControlFlowNode for y | +| 21 | ControlFlowNode for f() | Function f | 1 | ControlFlowNode for w | +| 21 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Function f | 0 | ControlFlowNode for c | +| 23 | ControlFlowNode for Attribute() | Function f | 1 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Function f | 2 | ControlFlowNode for z | +| 24 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | +| 24 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for x | +| 25 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for y | +| 25 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for z | +| 33 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral | +| 34 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral | +| 37 | ControlFlowNode for Attribute() | builtin method append | 0 | ControlFlowNode for l | +| 37 | ControlFlowNode for Attribute() | builtin method append | 1 | ControlFlowNode for IntegerLiteral | +| 38 | ControlFlowNode for len() | Builtin-function len | 0 | ControlFlowNode for l | +| 40 | ControlFlowNode for f() | Function f | 0 | ControlFlowNode for IntegerLiteral | +| 40 | ControlFlowNode for f() | Function f | 1 | ControlFlowNode for IntegerLiteral | +| 40 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql new file mode 100644 index 00000000000..de13f0504e8 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql @@ -0,0 +1,5 @@ +import python + +from CallNode call, CallableValue callable, int i +select call.getLocation().getStartLine(), call.toString(), callable.toString(), i, + callable.getArgumentForCall(call, i).toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected new file mode 100644 index 00000000000..fe2759693f0 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -0,0 +1,21 @@ +| 19 | ControlFlowNode for f() | Function f | arg0 | ControlFlowNode for w | +| 19 | ControlFlowNode for f() | Function f | arg1 | ControlFlowNode for x | +| 19 | ControlFlowNode for f() | Function f | arg2 | ControlFlowNode for y | +| 21 | ControlFlowNode for f() | Function f | arg0 | ControlFlowNode for y | +| 21 | ControlFlowNode for f() | Function f | arg1 | ControlFlowNode for w | +| 21 | ControlFlowNode for f() | Function f | arg2 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Function f | arg1 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Function f | arg2 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Function f | self | ControlFlowNode for c | +| 24 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for x | +| 24 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | +| 25 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for z | +| 25 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for y | +| 33 | ControlFlowNode for Attribute() | Function D.foo | arg | ControlFlowNode for IntegerLiteral | +| 34 | ControlFlowNode for Attribute() | Function D.foo | arg | ControlFlowNode for IntegerLiteral | +| 37 | ControlFlowNode for Attribute() | builtin method append | self | ControlFlowNode for l | +| 40 | ControlFlowNode for f() | Function f | arg0 | ControlFlowNode for IntegerLiteral | +| 40 | ControlFlowNode for f() | Function f | arg1 | ControlFlowNode for IntegerLiteral | +| 40 | ControlFlowNode for f() | Function f | arg2 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql new file mode 100644 index 00000000000..c531a9ab57a --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql @@ -0,0 +1,5 @@ +import python + +from CallNode call, CallableValue callable, string name +select call.getLocation().getStartLine(), call.toString(), callable.toString(), name, + callable.getNamedArgumentForCall(call, name).toString() From e9859ad96d261e1ff749e9357f679bb7b1fd3f50 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:56 +0200 Subject: [PATCH 015/111] Python: Fix getArgumentForCall when using keyword arguments Yikes :| --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 2 +- .../library-tests/PointsTo/calls/getArgumentForCall.expected | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 65b3326e602..bc7387e5efc 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -363,7 +363,7 @@ class CallableValue extends Value { or exists(string name | call.getArgByName(name) = result and - this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name + this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name ) or called instanceof BoundMethodObjectInternal and diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected index a65106bf723..baa17fa8f91 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -19,5 +19,5 @@ | 40 | ControlFlowNode for f() | Function f | 0 | ControlFlowNode for IntegerLiteral | | 40 | ControlFlowNode for f() | Function f | 1 | ControlFlowNode for IntegerLiteral | | 40 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for IntegerLiteral | -| 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | +| 42 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for IntegerLiteral | From 96fdb7a5b6e2aeba7ccbd8afef9693dc31e37f16 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:51:04 +0200 Subject: [PATCH 016/111] Python: Add tests for getParameter[byName] These already have results for BoundMethodValue, although 1) it's a bit strange that `getParameter(-1)` has results 2) why does `Method(Function C.n, class C)` exists? this would only be relevant if `n` was a classmethod, but it isn't. It's not a problem that it exsits per se, but curious. --- .../PointsTo/calls/getParameter.expected | 13 +++++++++++++ .../library-tests/PointsTo/calls/getParameter.ql | 4 ++++ .../PointsTo/calls/getParameterByName.expected | 13 +++++++++++++ .../PointsTo/calls/getParameterByName.ql | 4 ++++ 4 files changed, 34 insertions(+) create mode 100644 python/ql/test/library-tests/PointsTo/calls/getParameter.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/getParameter.ql create mode 100644 python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected new file mode 100644 index 00000000000..4aaa45d9662 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected @@ -0,0 +1,13 @@ +| Function C.n | 0 | ControlFlowNode for self | +| Function C.n | 1 | ControlFlowNode for arg1 | +| Function D.foo | 0 | ControlFlowNode for arg | +| Function f | 0 | ControlFlowNode for arg0 | +| Function f | 1 | ControlFlowNode for arg1 | +| Function f | 2 | ControlFlowNode for arg2 | +| Method(Function C.n, C()) | 0 | ControlFlowNode for arg1 | +| Method(Function C.n, C()) | -1 | ControlFlowNode for self | +| Method(Function C.n, class C) | 0 | ControlFlowNode for arg1 | +| Method(Function C.n, class C) | -1 | ControlFlowNode for self | +| Method(Function f, C()) | 0 | ControlFlowNode for arg1 | +| Method(Function f, C()) | 1 | ControlFlowNode for arg2 | +| Method(Function f, C()) | -1 | ControlFlowNode for arg0 | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameter.ql b/python/ql/test/library-tests/PointsTo/calls/getParameter.ql new file mode 100644 index 00000000000..07f12cce36f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getParameter.ql @@ -0,0 +1,4 @@ +import python + +from CallableValue callable, int i +select callable.toString(), i, callable.getParameter(i).toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected new file mode 100644 index 00000000000..c030e46d1dd --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected @@ -0,0 +1,13 @@ +| Function C.n | arg1 | ControlFlowNode for arg1 | +| Function C.n | self | ControlFlowNode for self | +| Function D.foo | arg | ControlFlowNode for arg | +| Function f | arg0 | ControlFlowNode for arg0 | +| Function f | arg1 | ControlFlowNode for arg1 | +| Function f | arg2 | ControlFlowNode for arg2 | +| Method(Function C.n, C()) | arg1 | ControlFlowNode for arg1 | +| Method(Function C.n, C()) | self | ControlFlowNode for self | +| Method(Function C.n, class C) | arg1 | ControlFlowNode for arg1 | +| Method(Function C.n, class C) | self | ControlFlowNode for self | +| Method(Function f, C()) | arg0 | ControlFlowNode for arg0 | +| Method(Function f, C()) | arg1 | ControlFlowNode for arg1 | +| Method(Function f, C()) | arg2 | ControlFlowNode for arg2 | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql new file mode 100644 index 00000000000..d4766b680f7 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql @@ -0,0 +1,4 @@ +import python + +from CallableValue callable, string name +select callable.toString(), name, callable.getParameterByName(name).toString() From bc92c26e125b3dd775bff665b28afaad1acd29c3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:51:12 +0200 Subject: [PATCH 017/111] Python: Add BoundMethodValue --- .../src/semmle/python/objects/Callables.qll | 2 + .../src/semmle/python/objects/ObjectAPI.qll | 38 +++++++++++++++++-- .../calls/getArgumentForCall.expected | 5 +++ .../calls/getNamedArgumentForCall.expected | 4 ++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/objects/Callables.qll b/python/ql/src/semmle/python/objects/Callables.qll index b915e4bd5c2..6c59f7f1e51 100644 --- a/python/ql/src/semmle/python/objects/Callables.qll +++ b/python/ql/src/semmle/python/objects/Callables.qll @@ -448,6 +448,8 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod { override predicate functionAndOffset(CallableObjectInternal function, int offset) { function = this.getFunction() and offset = 1 + or + function = this and offset = 0 } override predicate useOriginAsLegacyObject() { any() } diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index bc7387e5efc..f7f8ab73762 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -363,7 +363,11 @@ class CallableValue extends Value { or exists(string name | call.getArgByName(name) = result and - this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name + ( + this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name + or + this.(BoundMethodObjectInternal).getFunction().getScope().getArg(n+1).getName() = name + ) ) or called instanceof BoundMethodObjectInternal and @@ -382,11 +386,19 @@ class CallableValue extends Value { | exists(int n | call.getArg(n) = result and - this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name + exists(PythonFunctionObjectInternal py | + py = this or py = this.(BoundMethodObjectInternal).getFunction() + | + py.getScope().getArg(n + offset).getName() = name + ) ) or call.getArgByName(name) = result and - exists(this.(PythonFunctionObjectInternal).getScope().getArgByName(name)) + exists(PythonFunctionObjectInternal py | + py = this or py = this.(BoundMethodObjectInternal).getFunction() + | + exists(py.getScope().getArgByName(name)) + ) or called instanceof BoundMethodObjectInternal and offset = 1 and @@ -396,6 +408,26 @@ class CallableValue extends Value { } } +/** + * Class representing bound-methods, such as `o.func`, where `o` is an instance + * of a class that has a callable attribute `func`. + */ +class BoundMethodValue extends CallableValue { + BoundMethodValue() { this instanceof BoundMethodObjectInternal } + + /** + * Gets the callable that will be used when `this` called. + * The actual callable for `func` in `o.func`. + */ + CallableValue getFunction() { result = this.(BoundMethodObjectInternal).getFunction() } + + /** + * Gets the value that will be used for the `self` parameter when `this` is called. + * The value for `o` in `o.func`. + */ + Value getSelf() { result = this.(BoundMethodObjectInternal).getSelf() } +} + /** * Class representing classes in the Python program, both Python and built-in. */ diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected index baa17fa8f91..54e4ef8dafc 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -7,12 +7,16 @@ | 23 | ControlFlowNode for Attribute() | Function f | 0 | ControlFlowNode for c | | 23 | ControlFlowNode for Attribute() | Function f | 1 | ControlFlowNode for w | | 23 | ControlFlowNode for Attribute() | Function f | 2 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | 0 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | 1 | ControlFlowNode for z | | 24 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | | 24 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for x | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for x | | 25 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for y | | 25 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for z | | 33 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral | | 34 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral | +| 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | 0 | ControlFlowNode for IntegerLiteral | | 37 | ControlFlowNode for Attribute() | builtin method append | 0 | ControlFlowNode for l | | 37 | ControlFlowNode for Attribute() | builtin method append | 1 | ControlFlowNode for IntegerLiteral | | 38 | ControlFlowNode for len() | Builtin-function len | 0 | ControlFlowNode for l | @@ -21,3 +25,4 @@ | 40 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | | 42 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for IntegerLiteral | diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected index fe2759693f0..60ddd0b27f6 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -7,8 +7,11 @@ | 23 | ControlFlowNode for Attribute() | Function f | arg1 | ControlFlowNode for w | | 23 | ControlFlowNode for Attribute() | Function f | arg2 | ControlFlowNode for z | | 23 | ControlFlowNode for Attribute() | Function f | self | ControlFlowNode for c | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg0 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg1 | ControlFlowNode for z | | 24 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for x | | 24 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | self | ControlFlowNode for x | | 25 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for z | | 25 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for y | | 33 | ControlFlowNode for Attribute() | Function D.foo | arg | ControlFlowNode for IntegerLiteral | @@ -19,3 +22,4 @@ | 40 | ControlFlowNode for f() | Function f | arg2 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | +| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | arg1 | ControlFlowNode for IntegerLiteral | From 838106d49cdc47d62283e539c4c615bc25ca1ee5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:51:23 +0200 Subject: [PATCH 018/111] Python: Refactor get[Named]ArgumentForCall Also fixed a bug for BoundMethodValue, as highlighted in the expected diff :+1: --- .../ql/src/semmle/python/objects/ObjectAPI.qll | 18 +++--------------- .../calls/getNamedArgumentForCall.expected | 6 +++--- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index f7f8ab73762..39a95d2dd24 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -363,11 +363,7 @@ class CallableValue extends Value { or exists(string name | call.getArgByName(name) = result and - ( - this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name - or - this.(BoundMethodObjectInternal).getFunction().getScope().getArg(n+1).getName() = name - ) + this.getParameter(n).getId() = name ) or called instanceof BoundMethodObjectInternal and @@ -386,19 +382,11 @@ class CallableValue extends Value { | exists(int n | call.getArg(n) = result and - exists(PythonFunctionObjectInternal py | - py = this or py = this.(BoundMethodObjectInternal).getFunction() - | - py.getScope().getArg(n + offset).getName() = name - ) + this.getParameter(n+offset).getId() = name ) or call.getArgByName(name) = result and - exists(PythonFunctionObjectInternal py | - py = this or py = this.(BoundMethodObjectInternal).getFunction() - | - exists(py.getScope().getArgByName(name)) - ) + exists(this.getParameterByName(name)) or called instanceof BoundMethodObjectInternal and offset = 1 and diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected index 60ddd0b27f6..0bde0a2b585 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -7,11 +7,11 @@ | 23 | ControlFlowNode for Attribute() | Function f | arg1 | ControlFlowNode for w | | 23 | ControlFlowNode for Attribute() | Function f | arg2 | ControlFlowNode for z | | 23 | ControlFlowNode for Attribute() | Function f | self | ControlFlowNode for c | -| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg0 | ControlFlowNode for w | -| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg1 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg1 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg2 | ControlFlowNode for z | | 24 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for x | | 24 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | -| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | self | ControlFlowNode for x | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | arg1 | ControlFlowNode for x | | 25 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for z | | 25 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for y | | 33 | ControlFlowNode for Attribute() | Function D.foo | arg | ControlFlowNode for IntegerLiteral | From 061bbb82f5d85167b187ca61cbfc14668108a7a6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 09:00:55 +0200 Subject: [PATCH 019/111] Python: Restructure getNamedArgumentForCall So it matches the structure of getArgumentForCall -- call.getArgByName first! --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 39a95d2dd24..a4cb912d1f8 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -380,14 +380,14 @@ class CallableValue extends Value { PointsToInternal::pointsTo(call.getFunction(), _, called, _) and called.functionAndOffset(this, offset) | + call.getArgByName(name) = result and + exists(this.getParameterByName(name)) + or exists(int n | call.getArg(n) = result and this.getParameter(n+offset).getId() = name ) or - call.getArgByName(name) = result and - exists(this.getParameterByName(name)) - or called instanceof BoundMethodObjectInternal and offset = 1 and name = "self" and From 87d7738b6e7d784cf621500a9a241cb87bd2f7fd Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 09:54:54 +0200 Subject: [PATCH 020/111] Python: Expand QLDoc for get[Named]ArgumentForCall --- .../src/semmle/python/objects/ObjectAPI.qll | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index a4cb912d1f8..c18b4a6f594 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -352,7 +352,29 @@ class CallableValue extends Value { result = this.(CallableObjectInternal).getParameterByName(name) } - /** Gets the argument corresponding to the `n'th parameter node of this callable. */ + /** + * Gets the argument in `call` corresponding to the `n`'th positional parameter of this callable. + * + * Use this method instead of `call.getArg(n)` to handle the fact that this function might be used as + * a bound-method, such that argument `n` of the call corresponds to the `n+1` parameter of the callable. + * + * This method also gives results when the argument is passed as a keyword argument in `call`, as long + * as `this` is not a builtin function or a builtin method. + * + * Examples: + * + * - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents + * `func(10, 20)`, then `getArgumentForCall(call, 0)` will give the `ControlFlowNode` for `10`. + * + * - with `call` representing `func(b=20, a=10)`, `getArgumentForCall(call, 0)` will give + * the `ControlFlowNode` for `10`. + * + * - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call` + * represents `foo.func(10, 20)`, then `getArgumentForCall(call, 1)` will give the + * `ControlFlowNode` for `10`. + * Note: There will also exist a `BoundMethodValue bm` where `bm.getArgumentForCall(call, 0)` + * will give the `ControlFlowNode` for `10` (notice the shift in index used). + */ cached ControlFlowNode getArgumentForCall(CallNode call, int n) { exists(ObjectInternal called, int offset | @@ -373,7 +395,25 @@ class CallableValue extends Value { ) } - /** Gets the argument corresponding to the `name`d parameter node of this callable. */ + /** + * Gets the argument in `call` corresponding to the `name`d keyword parameter of this callable. + * ONLY WORKS FOR NON-BUILTINS. + * + * This method also gives results when the argument is passed as a positional argument in `call`, as long + * as `this` is not a builtin function or a builtin method. + * + * Examples: + * + * - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents + * `func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the `ControlFlowNode` for `10`. + * + * - with `call` representing `func(b=20, a=10)`, `getNamedArgumentForCall(call, "a")` will give + * the `ControlFlowNode` for `10`. + * + * - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call` + * represents `foo.func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the + * `ControlFlowNode` for `10`. + */ cached ControlFlowNode getNamedArgumentForCall(CallNode call, string name) { exists(CallableObjectInternal called, int offset | From dfe7c8270b6ee99ed70fd10c8fadcdf4fe46ea99 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 09:55:09 +0200 Subject: [PATCH 021/111] Python: Clean up trailing whitespace --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index c18b4a6f594..474fbbcac36 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -723,7 +723,7 @@ class PythonFunctionValue extends FunctionValue { ControlFlowNode getAReturnedNode() { result = this.getScope().getAReturnValueFlowNode() } override ClassValue getARaisedType() { scope_raises(result, this.getScope()) } - + override ClassValue getAnInferredReturnType() { /* We have to do a special version of this because builtin functions have no * explicit return nodes that we can query and get the class of. @@ -779,7 +779,7 @@ class BuiltinMethodValue extends FunctionValue { /* Information is unavailable for C code in general */ none() } - + override ClassValue getAnInferredReturnType() { result = TBuiltinClassObject(this.(BuiltinMethodObjectInternal).getReturnType()) } From a70f5344580516ed9b71b6266c44567b4a9d1d34 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 09:17:39 +0100 Subject: [PATCH 022/111] Sync identical files. --- csharp/ql/src/semmle/code/csharp/XML.qll | 4 ++-- java/ql/src/semmle/code/xml/XML.qll | 4 ++-- javascript/ql/src/semmle/javascript/XML.qll | 4 ++-- python/ql/src/semmle/python/xml/XML.qll | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/XML.qll b/csharp/ql/src/semmle/code/csharp/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/csharp/ql/src/semmle/code/csharp/XML.qll +++ b/csharp/ql/src/semmle/code/csharp/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/java/ql/src/semmle/code/xml/XML.qll b/java/ql/src/semmle/code/xml/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/java/ql/src/semmle/code/xml/XML.qll +++ b/java/ql/src/semmle/code/xml/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/javascript/ql/src/semmle/javascript/XML.qll b/javascript/ql/src/semmle/javascript/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/javascript/ql/src/semmle/javascript/XML.qll +++ b/javascript/ql/src/semmle/javascript/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/python/ql/src/semmle/python/xml/XML.qll b/python/ql/src/semmle/python/xml/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/python/ql/src/semmle/python/xml/XML.qll +++ b/python/ql/src/semmle/python/xml/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** From affca1a72808b1b680acdbde635242c2faab14e5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 10:24:35 +0200 Subject: [PATCH 023/111] Python: Add test-cases using keyword arguments for builtin function --- .../test/library-tests/PointsTo/calls/CallPointsTo.expected | 2 ++ python/ql/test/library-tests/PointsTo/calls/GetACall.expected | 2 ++ .../library-tests/PointsTo/calls/getArgumentForCall.expected | 2 ++ python/ql/test/library-tests/PointsTo/calls/test.py | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected index 627f433b847..101e971cb37 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -13,3 +13,5 @@ | 40 | ControlFlowNode for f() | Function f | | 41 | ControlFlowNode for C() | class C | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | +| 45 | ControlFlowNode for open() | Builtin-function open | +| 46 | ControlFlowNode for open() | Builtin-function open | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index dc3ac87cdf1..51051e1de00 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -17,3 +17,5 @@ | 41 | ControlFlowNode for C() | class C | | 42 | ControlFlowNode for Attribute() | Function C.n | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | +| 45 | ControlFlowNode for open() | Builtin-function open | +| 46 | ControlFlowNode for open() | Builtin-function open | diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected index 54e4ef8dafc..9cb8b3e9862 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -26,3 +26,5 @@ | 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | | 42 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for IntegerLiteral | +| 45 | ControlFlowNode for open() | Builtin-function open | 0 | ControlFlowNode for Str | +| 45 | ControlFlowNode for open() | Builtin-function open | 1 | ControlFlowNode for Str | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index 0b5a7237e7a..a8c7210b4ec 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -40,3 +40,7 @@ len(l) f(arg0=0, arg1=1, arg2=2) c = C() c.n(arg1=1) + +# positional/keyword arguments for a builtin function +open("foo.txt", "rb") # TODO: Not handled by getNamedArgumentForCall +open(file="foo.txt", mode="rb") # TODO: Not handled by either getNamedArgumentForCall or getArgumentForCall From 31a7e2c34e8c3799a6d0c5aeaba01943fcea9db3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 10:05:18 +0100 Subject: [PATCH 024/111] C++: Make getAnonymousParameterDescription private. --- cpp/ql/src/semmle/code/cpp/Variable.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 3fe58cf6ee7..54f39ab2bb6 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -260,7 +260,7 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ int getIndex() { param_decl_bind(underlyingElement(this), result, _) } - string getAnonymousParameterDescription() { + private string getAnonymousParameterDescription() { not exists(getName()) and exists(string idx | idx = From 07ae40206f04a8dd2908cee3ba0d2c28a57366de Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 11:37:10 +0200 Subject: [PATCH 025/111] Python: Don't allow getParameter(-1) for BoundMethodValue As per discussion in the PR --- python/ql/src/semmle/python/objects/Callables.qll | 12 ++++++++++-- python/ql/src/semmle/python/objects/ObjectAPI.qll | 3 +++ .../PointsTo/calls/getParameter.expected | 3 --- .../PointsTo/calls/getParameterByName.expected | 3 --- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/python/ql/src/semmle/python/objects/Callables.qll b/python/ql/src/semmle/python/objects/Callables.qll index 6c59f7f1e51..a25f1ad3e7d 100644 --- a/python/ql/src/semmle/python/objects/Callables.qll +++ b/python/ql/src/semmle/python/objects/Callables.qll @@ -438,10 +438,18 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod { PointsTo::pointsTo(result.getFunction(), ctx, this, _) } - override NameNode getParameter(int n) { result = this.getFunction().getParameter(n + 1) } + /** Gets the parameter node that will be used for `self`. */ + NameNode getSelfParameter() { result = this.getFunction().getParameter(0) } + + override NameNode getParameter(int n) { + result = this.getFunction().getParameter(n + 1) and + // don't return the parameter for `self` at `n = -1` + n >= 0 + } override NameNode getParameterByName(string name) { - result = this.getFunction().getParameterByName(name) + result = this.getFunction().getParameterByName(name) and + not result = this.getSelfParameter() } override predicate neverReturns() { this.getFunction().neverReturns() } diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 474fbbcac36..5bbec7876ef 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -454,6 +454,9 @@ class BoundMethodValue extends CallableValue { * The value for `o` in `o.func`. */ Value getSelf() { result = this.(BoundMethodObjectInternal).getSelf() } + + /** Gets the parameter node that will be used for `self`. */ + NameNode getSelfParameter() { result = this.(BoundMethodObjectInternal).getSelfParameter() } } /** diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected index 4aaa45d9662..86f3e525a9f 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected @@ -5,9 +5,6 @@ | Function f | 1 | ControlFlowNode for arg1 | | Function f | 2 | ControlFlowNode for arg2 | | Method(Function C.n, C()) | 0 | ControlFlowNode for arg1 | -| Method(Function C.n, C()) | -1 | ControlFlowNode for self | | Method(Function C.n, class C) | 0 | ControlFlowNode for arg1 | -| Method(Function C.n, class C) | -1 | ControlFlowNode for self | | Method(Function f, C()) | 0 | ControlFlowNode for arg1 | | Method(Function f, C()) | 1 | ControlFlowNode for arg2 | -| Method(Function f, C()) | -1 | ControlFlowNode for arg0 | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected index c030e46d1dd..74ded3b8a4d 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected @@ -5,9 +5,6 @@ | Function f | arg1 | ControlFlowNode for arg1 | | Function f | arg2 | ControlFlowNode for arg2 | | Method(Function C.n, C()) | arg1 | ControlFlowNode for arg1 | -| Method(Function C.n, C()) | self | ControlFlowNode for self | | Method(Function C.n, class C) | arg1 | ControlFlowNode for arg1 | -| Method(Function C.n, class C) | self | ControlFlowNode for self | -| Method(Function f, C()) | arg0 | ControlFlowNode for arg0 | | Method(Function f, C()) | arg1 | ControlFlowNode for arg1 | | Method(Function f, C()) | arg2 | ControlFlowNode for arg2 | From 6488714758c02a689b8b89c84cf0befc8723f2cc Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 11:38:17 +0200 Subject: [PATCH 026/111] Python: Autoformat --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 5bbec7876ef..2a49d0d44c4 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -425,7 +425,7 @@ class CallableValue extends Value { or exists(int n | call.getArg(n) = result and - this.getParameter(n+offset).getId() = name + this.getParameter(n + offset).getId() = name ) or called instanceof BoundMethodObjectInternal and @@ -728,9 +728,11 @@ class PythonFunctionValue extends FunctionValue { override ClassValue getARaisedType() { scope_raises(result, this.getScope()) } override ClassValue getAnInferredReturnType() { - /* We have to do a special version of this because builtin functions have no + /* + * We have to do a special version of this because builtin functions have no * explicit return nodes that we can query and get the class of. */ + result = this.getAReturnedNode().pointsTo().getClass() } } @@ -753,9 +755,11 @@ class BuiltinFunctionValue extends FunctionValue { } override ClassValue getAnInferredReturnType() { - /* We have to do a special version of this because builtin functions have no + /* + * We have to do a special version of this because builtin functions have no * explicit return nodes that we can query and get the class of. */ + result = TBuiltinClassObject(this.(BuiltinFunctionObjectInternal).getReturnType()) } } From 0b381b9ba72122e260443e0899b46439375ed464 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 12:58:54 +0100 Subject: [PATCH 027/111] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/Namespace.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index da6b1559cfa..37cc9f98958 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -172,9 +172,7 @@ class UsingDirectiveEntry extends UsingEntry { */ Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { - result = "using namespace " + this.getNamespace().getFriendlyName() - } + override string toString() { result = "using namespace " + this.getNamespace().getFriendlyName() } } /** From 2940f4794e77a7d4c640b5437b0ff5c0a2304774 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 13:06:48 +0100 Subject: [PATCH 028/111] C++: Fix isfromtemplateinstantiation test. --- .../isfromtemplateinstantiation.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql index 3a34cc2ca1b..dd97fdfc967 100644 --- a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql +++ b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql @@ -2,7 +2,7 @@ import cpp class FunctionMonkeyPatch extends Function { language[monotonicAggregates] - override string toString() { + override string getDescription() { exists(string name, string templateArgs, string args | result = name + templateArgs + args and name = this.getQualifiedName() and @@ -30,7 +30,7 @@ class FunctionMonkeyPatch extends Function { } class ParameterMonkeyPatch extends Parameter { - override string toString() { result = super.getType().getName() + " " + super.toString() } + override string getDescription() { result = super.getType().getName() + " " + super.getDescription() } } from Element e, Element ti From 3e2e69c06a0fef1b3af865ddf71c95db668ad686 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 16:55:15 +0100 Subject: [PATCH 029/111] C++: Autoformat. --- .../isfromtemplateinstantiation.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql index dd97fdfc967..454f901fe38 100644 --- a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql +++ b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql @@ -30,7 +30,9 @@ class FunctionMonkeyPatch extends Function { } class ParameterMonkeyPatch extends Parameter { - override string getDescription() { result = super.getType().getName() + " " + super.getDescription() } + override string getDescription() { + result = super.getType().getName() + " " + super.getDescription() + } } from Element e, Element ti From d75841d6a77c38277ba54e341e9513e80b48a868 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Tue, 12 May 2020 13:42:17 -0400 Subject: [PATCH 030/111] Add sample usage and remove unused imports --- .../CWE-939/IncorrectURLVerification.ql | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index eed077ea0b9..474244d66d9 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -8,10 +8,6 @@ */ import java -import semmle.code.java.dataflow.FlowSources -import semmle.code.java.dataflow.TaintTracking -import DataFlow -import PathGraph /** @@ -49,11 +45,11 @@ class HostVerificationMethodAccess extends MethodAccess { ) and this.getMethod().getNumberOfParameters() = 1 and ( - this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." or //string constant comparison - this.getArgument(0).(AddExpr).getLeftOperand().(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." or //var1+var2, check var1 starts with "." - this.getArgument(0).(AddExpr).getLeftOperand().(StringLiteral).getRepresentedString().charAt(0) != "." or //"."+var2, check string constant "." - exists (MethodAccess ma | this.getArgument(0) = ma and ma.getMethod().hasName("getString") and ma.getArgument(0).toString().indexOf("R.string") = 0) or //res.getString(R.string.key) - this.getArgument(0).(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." //check variable starts with "." + this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." or //string constant comparison e.g. uri.getHost().endsWith("example.com") + this.getArgument(0).(AddExpr).getLeftOperand().(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." or //var1+var2, check var1 starts with "." e.g. String domainName = "example"; Uri.parse(url).getHost().endsWith(domainName+".com") + this.getArgument(0).(AddExpr).getLeftOperand().(StringLiteral).getRepresentedString().charAt(0) != "." or //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) + exists (MethodAccess ma | this.getArgument(0) = ma and ma.getMethod().hasName("getString") and ma.getArgument(0).toString().indexOf("R.string") = 0) or //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) + this.getArgument(0).(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." //check variable starts with "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith(domainName) ) } } @@ -61,4 +57,4 @@ class HostVerificationMethodAccess extends MethodAccess { from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma where hma.getQualifier() = uma and uma.getMethod() = um select "Potentially improper URL verification with $@ in $@ having $@.", - hma, hma.getFile(), hma.getArgument(0), "user-provided value" \ No newline at end of file + hma, hma.getFile(), hma.getArgument(0), "user-provided value" From 106c181ab199e9045411129d60be570078e4ad45 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Tue, 12 May 2020 15:53:29 -0400 Subject: [PATCH 031/111] Formatting with auto-format --- .../CWE-939/IncorrectURLVerification.ql | 86 ++++++++++++------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index 474244d66d9..cd9ec0211ce 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -1,7 +1,7 @@ /** * @id java/incorrect-url-verification * @name Insertion of sensitive information into log files - * @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification. + * @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification. * @kind problem * @tags security * external/cwe-939 @@ -9,26 +9,25 @@ import java - /** * The Java class `android.net.Uri` and `java.net.URL`. */ class Uri extends RefType { - Uri() { - hasQualifiedName("android.net", "Uri") or - hasQualifiedName("java.net", "URL") - } + Uri() { + hasQualifiedName("android.net", "Uri") or + hasQualifiedName("java.net", "URL") + } } /** * The method `getHost()` declared in `android.net.Uri` and `java.net.URL`. */ class UriGetHostMethod extends Method { - UriGetHostMethod() { - getDeclaringType() instanceof Uri and - hasName("getHost") and - getNumberOfParameters() = 0 - } + UriGetHostMethod() { + getDeclaringType() instanceof Uri and + hasName("getHost") and + getNumberOfParameters() = 0 + } } /** @@ -36,25 +35,54 @@ class UriGetHostMethod extends Method { * its arguments according to a format string. */ class HostVerificationMethodAccess extends MethodAccess { - HostVerificationMethodAccess() { - ( - - this.getMethod().hasName("endsWith") or - this.getMethod().hasName("contains") or - this.getMethod().hasName("indexOf") - ) and - this.getMethod().getNumberOfParameters() = 1 and - ( - this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." or //string constant comparison e.g. uri.getHost().endsWith("example.com") - this.getArgument(0).(AddExpr).getLeftOperand().(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." or //var1+var2, check var1 starts with "." e.g. String domainName = "example"; Uri.parse(url).getHost().endsWith(domainName+".com") - this.getArgument(0).(AddExpr).getLeftOperand().(StringLiteral).getRepresentedString().charAt(0) != "." or //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) - exists (MethodAccess ma | this.getArgument(0) = ma and ma.getMethod().hasName("getString") and ma.getArgument(0).toString().indexOf("R.string") = 0) or //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) - this.getArgument(0).(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." //check variable starts with "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith(domainName) - ) - } + HostVerificationMethodAccess() { + ( + this.getMethod().hasName("endsWith") or + this.getMethod().hasName("contains") or + this.getMethod().hasName("indexOf") + ) and + this.getMethod().getNumberOfParameters() = 1 and + ( + this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." //string constant comparison e.g. uri.getHost().endsWith("example.com") + or + this + .getArgument(0) + .(AddExpr) + .getLeftOperand() + .(VarAccess) + .getVariable() + .getAnAssignedValue() + .(StringLiteral) + .getRepresentedString() + .charAt(0) != "." //var1+var2, check var1 starts with "." e.g. String domainName = "example"; Uri.parse(url).getHost().endsWith(domainName+".com") + or + this + .getArgument(0) + .(AddExpr) + .getLeftOperand() + .(StringLiteral) + .getRepresentedString() + .charAt(0) != "." //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) + or + exists(MethodAccess ma | + this.getArgument(0) = ma and + ma.getMethod().hasName("getString") and + ma.getArgument(0).toString().indexOf("R.string") = 0 + ) //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) + or + this + .getArgument(0) + .(VarAccess) + .getVariable() + .getAnAssignedValue() + .(StringLiteral) + .getRepresentedString() + .charAt(0) != "." //check variable starts with "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith(domainName) + ) + } } from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma where hma.getQualifier() = uma and uma.getMethod() = um -select "Potentially improper URL verification with $@ in $@ having $@.", - hma, hma.getFile(), hma.getArgument(0), "user-provided value" +select "Potentially improper URL verification with $@ in $@ having $@.", hma, hma.getFile(), + hma.getArgument(0), "user-provided value" From 9a7ab4ee322fba10ee73e849744aa7d87e9909bc Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Thu, 14 May 2020 07:43:17 -0400 Subject: [PATCH 032/111] Correct comment of the HostVerificationMethodAccess method access --- java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index cd9ec0211ce..03f6be26ab3 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -31,8 +31,7 @@ class UriGetHostMethod extends Method { } /** - * A library method that acts like `String.format` by formatting a number of - * its arguments according to a format string. + * The method access with incorrect string comparision */ class HostVerificationMethodAccess extends MethodAccess { HostVerificationMethodAccess() { From 819a599e2c1ba089f71dcbf78c5331f9b4c03fc8 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Thu, 14 May 2020 08:13:21 -0400 Subject: [PATCH 033/111] Correct the name tag and change the placeholders in the query --- java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index 03f6be26ab3..b0e5614b5bb 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -1,6 +1,6 @@ /** * @id java/incorrect-url-verification - * @name Insertion of sensitive information into log files + * @name Incorrect URL verification * @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification. * @kind problem * @tags security @@ -83,5 +83,5 @@ class HostVerificationMethodAccess extends MethodAccess { from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma where hma.getQualifier() = uma and uma.getMethod() = um -select "Potentially improper URL verification with $@ in $@ having $@.", hma, hma.getFile(), +select "Potentially improper URL verification at ", hma, "having $@ ", hma.getFile(), hma.getArgument(0), "user-provided value" From 754d7f0be847fbd9f0517435360ea34145f972ea Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 15:18:12 +0100 Subject: [PATCH 034/111] C++: More test cases for TaintedAllocationSize. --- .../TaintedAllocationSize.expected | 65 +++++++++++++++++++ .../semmle/TaintedAllocationSize/test.cpp | 62 ++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 773a969e9ad..e08db7a9c3e 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -59,6 +59,32 @@ edges | test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... | | test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | | test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | +| test.cpp:241:2:241:32 | Chi | test.cpp:271:17:271:20 | get_size output argument | +| test.cpp:241:2:241:32 | Chi | test.cpp:279:17:279:20 | get_size output argument | +| test.cpp:241:2:241:32 | Chi | test.cpp:287:18:287:21 | get_size output argument | +| test.cpp:241:2:241:32 | Chi | test.cpp:295:18:295:21 | get_size output argument | +| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi | +| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:257:11:257:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:257:11:257:29 | ... * ... | +| test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | +| test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | +| test.cpp:261:19:261:32 | (const char *)... | test.cpp:266:10:266:27 | ... * ... | +| test.cpp:261:19:261:32 | (const char *)... | test.cpp:266:10:266:27 | ... * ... | +| test.cpp:271:17:271:20 | get_size output argument | test.cpp:273:11:273:28 | ... * ... | +| test.cpp:271:17:271:20 | get_size output argument | test.cpp:273:11:273:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:287:18:287:21 | get_size output argument | test.cpp:290:10:290:27 | ... * ... | +| test.cpp:287:18:287:21 | get_size output argument | test.cpp:290:10:290:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | nodes | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:39:21:39:24 | argv | semmle.label | argv | @@ -122,6 +148,38 @@ nodes | test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | | test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... | | test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... | +| test.cpp:241:2:241:32 | Chi | semmle.label | Chi | +| test.cpp:241:18:241:23 | call to getenv | semmle.label | call to getenv | +| test.cpp:241:18:241:31 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:249:20:249:25 | call to getenv | semmle.label | call to getenv | +| test.cpp:249:20:249:33 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:261:19:261:24 | call to getenv | semmle.label | call to getenv | +| test.cpp:261:19:261:32 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:271:17:271:20 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:287:18:287:21 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | #select | test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | @@ -136,3 +194,10 @@ nodes | test.cpp:221:14:221:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:221:21:221:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | | test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | | test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) | +| test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | +| test.cpp:257:4:257:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | +| test.cpp:266:3:266:8 | call to malloc | test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:261:19:261:24 | call to getenv | user input (getenv) | +| test.cpp:273:4:273:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:273:11:273:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:281:4:281:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:281:11:281:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:290:3:290:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:290:10:290:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:298:3:298:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:298:10:298:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp index cb21e8f1915..ad1153dd910 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp @@ -236,3 +236,65 @@ void more_cases() { my_func(100); // GOOD my_func(local_size); // GOOD } + +bool get_size(int &out_size) { + out_size = atoi(getenv("USER")); + + return true; +} + +void equality_cases() { + { + int size1 = atoi(getenv("USER")); + int size2 = atoi(getenv("USER")); + + if (size1 == 100) + { + malloc(size2 * sizeof(int)); // BAD + } + if (size2 == 100) + { + malloc(size2 * sizeof(int)); // GOOD [FALSE POSITIVE] + } + } + { + int size = atoi(getenv("USER")); + + if (size != 100) + return; + + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } + { + int size; + + if ((get_size(size)) && (size == 100)) + { + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } + } + { + int size; + + if ((get_size(size)) && (size != 100)) + { + malloc(size * sizeof(int)); // BAD + } + } + { + int size; + + if ((!get_size(size)) || (size != 100)) + return; + + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } + { + int size; + + if ((!get_size(size)) || (size == 100)) + return; + + malloc(size * sizeof(int)); // BAD + } +} From 4a6021fb61440f705293d0acc8a410746c47ed42 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 18:19:32 +0100 Subject: [PATCH 035/111] C++: Allow equality checking to block taint flow. --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 18 ++++++++++ .../TaintedAllocationSize.expected | 34 ------------------- .../semmle/TaintedAllocationSize/test.cpp | 8 ++--- 3 files changed, 22 insertions(+), 38 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index dbeefae4880..c98a13a23bd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -5,6 +5,7 @@ private import semmle.code.cpp.ir.dataflow.DataFlow2 private import semmle.code.cpp.ir.dataflow.DataFlow3 private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch +private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.models.interfaces.Taint private import semmle.code.cpp.models.interfaces.DataFlow @@ -175,6 +176,23 @@ private predicate nodeIsBarrier(DataFlow::Node node) { readsVariable(node.asInstruction(), checkedVar) and hasUpperBoundsCheck(checkedVar) ) + or + exists(Variable checkedVar, IRGuardCondition guard, Operand access, Operand other | + /* + * This node is guarded by a condition that forces the accessed variable + * to equal something else. For example: + * ``` + * x = taintsource() + * if (x == 10) { + * taintsink(x); // not considered tainted + * } + * ``` + */ + + readsVariable(node.asInstruction(), checkedVar) and + readsVariable(access.getDef(), checkedVar) and + guard.ensuresEq(access, other, _, node.asInstruction().getBlock(), true) + ) } private predicate nodeIsBarrierIn(DataFlow::Node node) { diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index e08db7a9c3e..ed154eca0bb 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -59,30 +59,16 @@ edges | test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... | | test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | | test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | -| test.cpp:241:2:241:32 | Chi | test.cpp:271:17:271:20 | get_size output argument | | test.cpp:241:2:241:32 | Chi | test.cpp:279:17:279:20 | get_size output argument | -| test.cpp:241:2:241:32 | Chi | test.cpp:287:18:287:21 | get_size output argument | | test.cpp:241:2:241:32 | Chi | test.cpp:295:18:295:21 | get_size output argument | | test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi | | test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | -| test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:249:20:249:33 | (const char *)... | test.cpp:257:11:257:29 | ... * ... | -| test.cpp:249:20:249:33 | (const char *)... | test.cpp:257:11:257:29 | ... * ... | -| test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | -| test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | -| test.cpp:261:19:261:32 | (const char *)... | test.cpp:266:10:266:27 | ... * ... | -| test.cpp:261:19:261:32 | (const char *)... | test.cpp:266:10:266:27 | ... * ... | -| test.cpp:271:17:271:20 | get_size output argument | test.cpp:273:11:273:28 | ... * ... | -| test.cpp:271:17:271:20 | get_size output argument | test.cpp:273:11:273:28 | ... * ... | | test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | | test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:287:18:287:21 | get_size output argument | test.cpp:290:10:290:27 | ... * ... | -| test.cpp:287:18:287:21 | get_size output argument | test.cpp:290:10:290:27 | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | nodes @@ -156,26 +142,10 @@ nodes | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:261:19:261:24 | call to getenv | semmle.label | call to getenv | -| test.cpp:261:19:261:32 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:271:17:271:20 | get_size output argument | semmle.label | get_size output argument | -| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | | test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:287:18:287:21 | get_size output argument | semmle.label | get_size output argument | -| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | @@ -195,9 +165,5 @@ nodes | test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | | test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) | | test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | -| test.cpp:257:4:257:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | -| test.cpp:266:3:266:8 | call to malloc | test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:261:19:261:24 | call to getenv | user input (getenv) | -| test.cpp:273:4:273:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:273:11:273:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | | test.cpp:281:4:281:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:281:11:281:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | -| test.cpp:290:3:290:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:290:10:290:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | | test.cpp:298:3:298:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:298:10:298:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp index ad1153dd910..4e984a20c7c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp @@ -254,7 +254,7 @@ void equality_cases() { } if (size2 == 100) { - malloc(size2 * sizeof(int)); // GOOD [FALSE POSITIVE] + malloc(size2 * sizeof(int)); // GOOD } } { @@ -263,14 +263,14 @@ void equality_cases() { if (size != 100) return; - malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + malloc(size * sizeof(int)); // GOOD } { int size; if ((get_size(size)) && (size == 100)) { - malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + malloc(size * sizeof(int)); // GOOD } } { @@ -287,7 +287,7 @@ void equality_cases() { if ((!get_size(size)) || (size != 100)) return; - malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + malloc(size * sizeof(int)); // GOOD } { int size; From df5e16c45d9f1ccebabbdc6f5743f964ec4064e0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 18:41:14 +0100 Subject: [PATCH 036/111] C++: Add a 1.25 change note file (didn't we used to have templates for these?). --- change-notes/1.25/analysis-cpp.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 change-notes/1.25/analysis-cpp.md diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md new file mode 100644 index 00000000000..f0fe2e06642 --- /dev/null +++ b/change-notes/1.25/analysis-cpp.md @@ -0,0 +1,19 @@ +# Improvements to C/C++ analysis + +The following changes in version 1.25 affect C/C++ analysis in all applications. + +## General improvements + + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| + +## Changes to libraries + From 6579c71866f86a2967caf722ca8e6e94eae17ab8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 18:44:06 +0100 Subject: [PATCH 037/111] C++: Change note. --- change-notes/1.25/analysis-cpp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md index f0fe2e06642..8e1123b2247 100644 --- a/change-notes/1.25/analysis-cpp.md +++ b/change-notes/1.25/analysis-cpp.md @@ -17,3 +17,4 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. ## Changes to libraries +* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) now considers that equality checks may block the flow of taint. This results in fewer false positive results from queries that use this library. From edd09f09cd80ec253d469d618bb05aee86c738ac Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 15 May 2020 17:00:42 +0100 Subject: [PATCH 038/111] C++: Add test cases where several specific values are permitted. --- .../TaintedAllocationSize.expected | 20 +++++++++++++++++++ .../semmle/TaintedAllocationSize/test.cpp | 16 +++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 000658da82c..26d49b1f90b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -80,6 +80,14 @@ edges | test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | +| test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | +| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... | +| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... | nodes | field_conflation.c:12:22:12:27 | call to getenv | semmle.label | call to getenv | | field_conflation.c:12:22:12:34 | (const char *)... | semmle.label | (const char *)... | @@ -168,6 +176,16 @@ nodes | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:301:19:301:24 | call to getenv | semmle.label | call to getenv | +| test.cpp:301:19:301:32 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:309:19:309:24 | call to getenv | semmle.label | call to getenv | +| test.cpp:309:19:309:32 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | #select | field_conflation.c:20:3:20:8 | call to malloc | field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:20:13:20:13 | x | This allocation size is derived from $@ and might overflow | field_conflation.c:12:22:12:27 | call to getenv | user input (getenv) | | test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | @@ -186,3 +204,5 @@ nodes | test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | | test.cpp:281:4:281:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:281:11:281:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | | test.cpp:298:3:298:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:298:10:298:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:305:4:305:9 | call to malloc | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:301:19:301:24 | call to getenv | user input (getenv) | +| test.cpp:314:3:314:8 | call to malloc | test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:309:19:309:24 | call to getenv | user input (getenv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp index 4e984a20c7c..0683f7211e3 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp @@ -297,4 +297,20 @@ void equality_cases() { malloc(size * sizeof(int)); // BAD } + { + int size = atoi(getenv("USER")); + + if ((size == 50) || (size == 100)) + { + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } + } + { + int size = atoi(getenv("USER")); + + if (size != 50 && size != 100) + return; + + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } } From 7a9381f1fbd8f0c1dd51d8f9ee0b4038261b1e8d Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 18 May 2020 07:59:38 -0400 Subject: [PATCH 039/111] Add declaring type to the res.getString(R.string.key) call --- .../ql/src/experimental/CWE-939/IncorrectURLVerification.ql | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index b0e5614b5bb..69071232241 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -63,9 +63,11 @@ class HostVerificationMethodAccess extends MethodAccess { .getRepresentedString() .charAt(0) != "." //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) or - exists(MethodAccess ma | + exists(MethodAccess ma, Method m | this.getArgument(0) = ma and - ma.getMethod().hasName("getString") and + ma.getMethod() = m and + m.hasName("getString") and + m.getDeclaringType().getQualifiedName() = "android.content.res.Resources" and ma.getArgument(0).toString().indexOf("R.string") = 0 ) //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) or From 08ab7b0eb2f7ce0e7aa5ded6b662dd64c170fe69 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 18 May 2020 10:00:12 -0400 Subject: [PATCH 040/111] Remove the ending blank line for auto-format check From ac329e81f84234fcaabcc1875935a7450b7f3dc6 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Mon, 18 May 2020 22:55:33 +0200 Subject: [PATCH 041/111] Fixes FPs in SpringBootActuators query No evidence that Spring Actuators are being used, e.g. `http.authorizeRequests().anyRequest().permitAll()` Only safe Actuators are enabled, e.g. `EndpointRequest.to("health", "info")` --- .../CWE/CWE-016/SpringBootActuators.qll | 56 ++++++++++------ .../security/CWE-016/SpringBootActuators.java | 64 +++++++++++++++++++ .../security/servlet/EndpointRequest.java | 4 ++ 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll index 658983f2437..c1ef873b1fa 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll @@ -22,8 +22,7 @@ class TypeAuthorizedUrl extends Class { } /** - * The class - * `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. + * The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. */ class TypeAbstractRequestMatcherRegistry extends Class { TypeAbstractRequestMatcherRegistry() { @@ -34,38 +33,44 @@ class TypeAbstractRequestMatcherRegistry extends Class { } /** - * The class - * `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest.EndpointRequestMatcher`. + * The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`. */ -class TypeEndpointRequestMatcher extends Class { - TypeEndpointRequestMatcher() { +class TypeEndpointRequest extends Class { + TypeEndpointRequest() { this .hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet", - "EndpointRequest$EndpointRequestMatcher") + "EndpointRequest") + } +} + +/** A call to `EndpointRequest.toAnyEndpoint` method. */ +class ToAnyEndpointCall extends MethodAccess { + ToAnyEndpointCall() { + getMethod().hasName("toAnyEndpoint") and + getMethod().getDeclaringType() instanceof TypeEndpointRequest } } /** - * A call to `HttpSecurity.requestMatcher` method with argument of type - * `EndpointRequestMatcher`. + * A call to `HttpSecurity.requestMatcher` method with argument `RequestMatcher.toAnyEndpoint()`. */ class RequestMatcherCall extends MethodAccess { RequestMatcherCall() { getMethod().hasName("requestMatcher") and getMethod().getDeclaringType() instanceof TypeHttpSecurity and - getArgument(0).getType() instanceof TypeEndpointRequestMatcher + getArgument(0) instanceof ToAnyEndpointCall } } /** - * A call to `HttpSecurity.requestMatchers` method with lambda argument resolving to - * `EndpointRequestMatcher` type. + * A call to `HttpSecurity.requestMatchers` method with lambda argument + * `RequestMatcher.toAnyEndpoint()`. */ class RequestMatchersCall extends MethodAccess { RequestMatchersCall() { getMethod().hasName("requestMatchers") and getMethod().getDeclaringType() instanceof TypeHttpSecurity and - getArgument(0).(LambdaExpr).getExprBody().getType() instanceof TypeEndpointRequestMatcher + getArgument(0).(LambdaExpr).getExprBody() instanceof ToAnyEndpointCall } } @@ -92,9 +97,6 @@ class PermitAllCall extends MethodAccess { or // .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...] authorizeRequestsCall.getQualifier() instanceof RequestMatchersCall - or - // http.authorizeRequests([...]).[...] - authorizeRequestsCall.getQualifier() instanceof VarAccess | // [...].authorizeRequests(r -> r.anyRequest().permitAll()) or // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) @@ -117,6 +119,22 @@ class PermitAllCall extends MethodAccess { this.getQualifier() = anyRequestCall ) ) + or + exists(AuthorizeRequestsCall authorizeRequestsCall | + // http.authorizeRequests([...]).[...] + authorizeRequestsCall.getQualifier() instanceof VarAccess + | + // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) + authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and + this.getQualifier() instanceof RegistryRequestMatchersCall + or + // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or + authorizeRequestsCall.getNumArgument() = 0 and + exists(RegistryRequestMatchersCall registryRequestMatchersCall | + registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and + this.getQualifier() = registryRequestMatchersCall + ) + ) } } @@ -129,13 +147,13 @@ class AnyRequestCall extends MethodAccess { } /** - * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument of type - * `EndpointRequestMatcher`. + * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument + * `RequestMatcher.toAnyEndpoint()`. */ class RegistryRequestMatchersCall extends MethodAccess { RegistryRequestMatchersCall() { getMethod().hasName("requestMatchers") and getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry and - getAnArgument().getType() instanceof TypeEndpointRequestMatcher + getAnArgument() instanceof ToAnyEndpointCall } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java index b554a7bac7e..da59919fbe6 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java +++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java @@ -37,4 +37,68 @@ public class SpringBootActuators { protected void configureOk2(HttpSecurity http) throws Exception { http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint()); } + + protected void configureOk3(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOk4(HttpSecurity http) throws Exception { + http.authorizeRequests(authz -> authz.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests(requests -> requests.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health")).authorizeRequests().requestMatchers(EndpointRequest.to("health")).permitAll(); + } + + protected void configureOkSafeEndpoints3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkSafeEndpoints5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll()); + } + + protected void configureOkSafeEndpoints7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkNoPermitAll1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest()); + } + + protected void configureOkNoPermitAll2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } + + protected void configureOkNoPermitAll5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint())); + } + + protected void configureOkNoPermitAll7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } } diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java index 5b94a086e8f..e7dd0fd7673 100644 --- a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -7,6 +7,10 @@ public final class EndpointRequest { public static EndpointRequestMatcher toAnyEndpoint() { return null; } + + public static EndpointRequestMatcher to(String... endpoints) { + return null; + } public static final class EndpointRequestMatcher extends AbstractRequestMatcher {} From 19d2a404c9773b7544cc38fbfbabb3d08ff624cb Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Tue, 19 May 2020 08:44:26 -0400 Subject: [PATCH 042/111] Add AndroidRString RefType to clarify the Android query --- .../CWE-939/IncorrectURLVerification.ql | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index 69071232241..b3879ac881c 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -9,6 +9,14 @@ import java +/** + * The Java class `android.R.string` specific to Android applications, which contains references to application specific resources defined in /res/values/strings.xml. + * For example, ...example.com... in the application com.example.android.web can be referred as R.string.host with the type com.example.android.web.R$string + */ +class AndroidRString extends RefType { + AndroidRString() { this.hasQualifiedName(_, "R$string") } +} + /** * The Java class `android.net.Uri` and `java.net.URL`. */ @@ -63,12 +71,13 @@ class HostVerificationMethodAccess extends MethodAccess { .getRepresentedString() .charAt(0) != "." //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) or - exists(MethodAccess ma, Method m | + exists(MethodAccess ma, Method m, Field f | this.getArgument(0) = ma and ma.getMethod() = m and m.hasName("getString") and m.getDeclaringType().getQualifiedName() = "android.content.res.Resources" and - ma.getArgument(0).toString().indexOf("R.string") = 0 + ma.getArgument(0).(FieldRead).getField() = f and + f.getDeclaringType() instanceof AndroidRString ) //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) or this From 9db8b993a9b3ff851dd7de8d0f5d5038bd7ee4fa Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 19 May 2020 15:32:29 +0200 Subject: [PATCH 043/111] C#: Remove two deprecated predicates --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 24 ++--------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 710a4ac8f95..df94a259f57 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -1160,26 +1160,6 @@ class UsingStmt extends Stmt, @using_stmt { * ``` */ Expr getAnExpr() { none() } - - /** - * DEPRECATED: Use UsingBlockStmt.getExpr() instead. - * Gets the expression directly used by this `using` statement, if any. For - * example, `f` on line 2 in - * - * ``` - * var f = File.Open("settings.xml"); - * using (f) { - * ... - * } - * ``` - */ - deprecated Expr getExpr() { none() } - - /** - * DEPRECATED: Use UsingBlockStmt.getBody() instead. - * Gets the body of this `using` statement. - */ - deprecated Stmt getBody() { none() } } /** @@ -1212,7 +1192,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { * } * ``` */ - override Expr getExpr() { result = this.getChild(0) } + Expr getExpr() { result = this.getChild(0) } override Expr getAnExpr() { result = this.getAVariableDeclExpr().getInitializer() @@ -1221,7 +1201,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { } /** Gets the body of this `using` statement. */ - override Stmt getBody() { result.getParent() = this } + Stmt getBody() { result.getParent() = this } override string toString() { result = "using (...) {...}" } } From 431403f5dbe23ae96d52061fb693c1b515cb5140 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 19 May 2020 15:42:59 +0200 Subject: [PATCH 044/111] Data flow: Remove deprecated predicates --- .../src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 3 --- .../semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll | 3 --- .../semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll | 3 --- .../semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll | 3 --- .../code/cpp/dataflow/internal/DataFlowImplLocal.qll | 3 --- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 7 ------- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 3 --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 3 --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 3 --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 3 --- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 7 ------- .../semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 3 --- .../semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll | 3 --- .../semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll | 3 --- .../semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll | 3 --- .../semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll | 3 --- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking3/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking4/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking5/TaintTrackingImpl.qll | 7 ------- .../semmle/code/java/dataflow/internal/DataFlowImpl.qll | 3 --- .../semmle/code/java/dataflow/internal/DataFlowImpl2.qll | 3 --- .../semmle/code/java/dataflow/internal/DataFlowImpl3.qll | 3 --- .../semmle/code/java/dataflow/internal/DataFlowImpl4.qll | 3 --- .../semmle/code/java/dataflow/internal/DataFlowImpl5.qll | 3 --- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 7 ------- 30 files changed, 134 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } From fdf4e83c25723f851b064ce142f51a702f572a80 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 19 May 2020 16:59:37 +0100 Subject: [PATCH 045/111] C++: Solve tuple count bulge that may affect performance. --- .../code/cpp/ir/dataflow/DefaultTaintTracking.qll | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index c98a13a23bd..1de41288867 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -171,13 +171,18 @@ private predicate hasUpperBoundsCheck(Variable var) { ) } +private predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) { + readsVariable(node.asInstruction(), checkedVar) and + any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true) +} + private predicate nodeIsBarrier(DataFlow::Node node) { exists(Variable checkedVar | readsVariable(node.asInstruction(), checkedVar) and hasUpperBoundsCheck(checkedVar) ) or - exists(Variable checkedVar, IRGuardCondition guard, Operand access, Operand other | + exists(Variable checkedVar, Operand access | /* * This node is guarded by a condition that forces the accessed variable * to equal something else. For example: @@ -189,9 +194,8 @@ private predicate nodeIsBarrier(DataFlow::Node node) { * ``` */ - readsVariable(node.asInstruction(), checkedVar) and - readsVariable(access.getDef(), checkedVar) and - guard.ensuresEq(access, other, _, node.asInstruction().getBlock(), true) + nodeIsBarrierEqualityCandidate(node, access, checkedVar) and + readsVariable(access.getDef(), checkedVar) ) } From 8cbc01d49b2fb87c2070edc5bae4e939c6469f63 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 20 May 2020 10:44:15 +0200 Subject: [PATCH 046/111] Java: Add a few qltest cases for nullness and range analysis FPs. --- java/ql/test/query-tests/Nullness/C.java | 24 +++++++++++++++++++ .../query-tests/Nullness/NullMaybe.expected | 1 + java/ql/test/query-tests/RangeAnalysis/A.java | 19 +++++++++++++++ .../ArrayIndexOutOfBounds.expected | 2 ++ 4 files changed, 46 insertions(+) diff --git a/java/ql/test/query-tests/Nullness/C.java b/java/ql/test/query-tests/Nullness/C.java index 48d7799c9a1..c9fe368a394 100644 --- a/java/ql/test/query-tests/Nullness/C.java +++ b/java/ql/test/query-tests/Nullness/C.java @@ -220,4 +220,28 @@ public class C { return; } } + + private Object foo16; + + private Object getFoo16() { + return this.foo16; + } + + public static void ex16(C c) { + int[] xs = c.getFoo16() != null ? new int[5] : null; + if (c.getFoo16() != null) { + xs[0]++; // NPE - false positive + } + } + + public static final int MAXLEN = 1024; + + public void ex17() { + int[] xs = null; + // loop executes at least once + for (int i = 32; i <= MAXLEN; i *= 2) { + xs = new int[5]; + } + xs[0]++; // OK + } } diff --git a/java/ql/test/query-tests/Nullness/NullMaybe.expected b/java/ql/test/query-tests/Nullness/NullMaybe.expected index 2ddb51dfe4c..8f72be0619f 100644 --- a/java/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/java/ql/test/query-tests/Nullness/NullMaybe.expected @@ -31,5 +31,6 @@ | C.java:188:9:188:11 | obj | Variable $@ may be null here because of $@ assignment. | C.java:181:5:181:22 | Object obj | obj | C.java:181:12:181:21 | obj | this | | C.java:207:9:207:11 | obj | Variable $@ may be null here because of $@ assignment. | C.java:201:5:201:22 | Object obj | obj | C.java:201:12:201:21 | obj | this | | C.java:219:9:219:10 | o1 | Variable $@ may be null here as suggested by $@ null guard. | C.java:212:20:212:28 | o1 | o1 | C.java:213:9:213:18 | ... == ... | this | +| C.java:233:7:233:8 | xs | Variable $@ may be null here because of $@ assignment. | C.java:231:5:231:56 | int[] xs | xs | C.java:231:11:231:55 | xs | this | | F.java:11:5:11:7 | obj | Variable $@ may be null here as suggested by $@ null guard. | F.java:8:18:8:27 | obj | obj | F.java:9:9:9:19 | ... == ... | this | | F.java:17:5:17:7 | obj | Variable $@ may be null here as suggested by $@ null guard. | F.java:14:18:14:27 | obj | obj | F.java:15:9:15:19 | ... == ... | this | diff --git a/java/ql/test/query-tests/RangeAnalysis/A.java b/java/ql/test/query-tests/RangeAnalysis/A.java index d219b85bec3..f2cb4918387 100644 --- a/java/ql/test/query-tests/RangeAnalysis/A.java +++ b/java/ql/test/query-tests/RangeAnalysis/A.java @@ -175,4 +175,23 @@ public class A { } } } + + void m14(int[] xs) { + for (int i = 0; i < xs.length + 1; i++) { + if (i == 0 && xs.length > 0) { + xs[i]++; // OK - FP + } + } + } + + void m15(int[] xs) { + for (int i = 0; i < xs.length; i++) { + int x = ++i; + int y = ++i; + if (y < xs.length) { + xs[x]++; // OK - FP + xs[y]++; // OK + } + } + } } diff --git a/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected b/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected index 0c2aafdc4b1..378e9ad3336 100644 --- a/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected +++ b/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected @@ -10,3 +10,5 @@ | A.java:111:14:111:21 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length + 1. | | A.java:122:16:122:23 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length + 3. | | A.java:134:16:134:23 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. | +| A.java:182:9:182:13 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. | +| A.java:192:9:192:13 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. | From f2436ff713417d130231230fb4477ac54878824b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 20 May 2020 12:39:54 +0100 Subject: [PATCH 047/111] C++: Autoformat. --- .../src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 1de41288867..8186ac9268f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -171,7 +171,9 @@ private predicate hasUpperBoundsCheck(Variable var) { ) } -private predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) { +private predicate nodeIsBarrierEqualityCandidate( + DataFlow::Node node, Operand access, Variable checkedVar +) { readsVariable(node.asInstruction(), checkedVar) and any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true) } From 9babd5dc1035c354b6853ac6d9e01c7efd85eb65 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 20 May 2020 12:49:01 +0100 Subject: [PATCH 048/111] C++: Another positive effect of the change. --- .../CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected | 1 - .../test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected index 20e5eafbd3b..a46371f36b6 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected @@ -5,5 +5,4 @@ | test.c:63:3:63:5 | sc8 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:62:9:62:16 | - ... | Extreme value | | test.c:75:3:75:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value | | test.c:76:3:76:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value | -| test.c:114:9:114:9 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:108:17:108:23 | 2147483647 | Extreme value | | test.c:124:9:124:9 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:118:17:118:23 | 2147483647 | Extreme value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c index e17d413e3fd..8c40d984ee0 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c @@ -111,7 +111,7 @@ void test_guards3(int cond) { if (x != 0) return; - return x + 1; // GOOD [FALSE POSITIVE] + return x + 1; // GOOD } void test_guards4(int cond) { From 74ab6981ebcac5895bfca8dd2b7d284e11c3d04f Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Wed, 20 May 2020 10:23:40 -0400 Subject: [PATCH 049/111] Fix HTML tag issue --- java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp index 32bf6785825..850e9f3fa9d 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp @@ -23,5 +23,6 @@ verification is implemented as partial domain match. In the 'GOOD' case, full do
  • Common Android app vulnerabilities from bugcrowd +
  • From ec7c9489dc890f6656bb8b2dc40b39998dc1007c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 20 May 2020 17:12:24 +0100 Subject: [PATCH 050/111] JS: Remove timeout for node --version check --- .../extractor/src/com/semmle/js/parser/TypeScriptParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index d7ead7adecc..7467507ef75 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -203,7 +203,7 @@ public class TypeScriptParser { getNodeJsRuntimeInvocation("--version"), out, err, getParserWrapper().getParentFile()); b.expectFailure(); // We want to do our own logging in case of an error. - int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); + int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 0); // Default to no timeout. try { int r = b.execute(timeout); String stdout = new String(out.toByteArray()); From 218a3cf93d73ebf3c7e8143b2b051a2ff22cea63 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 20 May 2020 18:18:26 +0200 Subject: [PATCH 051/111] C++: Remove field conflation --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 2 + .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 63 ++++++++++++------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index dbeefae4880..5087363eee6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -1,6 +1,7 @@ import cpp import semmle.code.cpp.security.Security private import semmle.code.cpp.ir.dataflow.DataFlow +private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil private import semmle.code.cpp.ir.dataflow.DataFlow2 private import semmle.code.cpp.ir.dataflow.DataFlow3 private import semmle.code.cpp.ir.IR @@ -228,6 +229,7 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) { // Flow from an element to an array or union that contains it. i2.(ChiInstruction).getPartial() = i1 and not i2.isResultConflated() and + not exists(PartialDefinitionNode n | n.asInstruction() = i2) and exists(Type t | i2.getResultLanguageType().hasType(t, false) | t instanceof Union or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9f9659a506e..772754745df 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -239,6 +239,8 @@ abstract class PostUpdateNode extends InstructionNode { } /** + * INTERNAL: do not use. + * * The base class for nodes that perform "partial definitions". * * In contrast to a normal "definition", which provides a new value for @@ -251,7 +253,7 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } +abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; @@ -270,6 +272,17 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } } +private class FieldStoreWriteSideEffectNode extends PartialDefinitionNode { + override ChiInstruction instr; + + FieldStoreWriteSideEffectNode() { + not instr.isResultConflated() and + exists(WriteSideEffectInstruction sideEffect | instr.getPartial() = sideEffect) + } + + override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } +} + /** * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. * For instance, an update to a field of a struct containing only one field. For these cases we @@ -421,6 +434,32 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) + or + // The next two rules allow flow from partial definitions in setters to succeeding loads in the caller. + // First, we add flow from write side-effects to non-conflated chi instructions through their + // partial operands. Consider the following example: + // ``` + // void setX(Point* p, int new_x) { + // p->x = new_x; + // } + // ... + // setX(&p, taint()); + // ``` + // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to + // `setX`, which will be melded into `p` through a chi instruction. + nodeTo instanceof FieldStoreWriteSideEffectNode and + exists(ChiInstruction chi | chi = nodeTo.asInstruction() | + chi.getPartialOperand().getDef() = nodeFrom.asInstruction().(WriteSideEffectInstruction) and + not chi.isResultConflated() + ) + or + // Next, we add flow from non-conflated chi instructions to loads (even when they are not precise). + // This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above. + nodeFrom instanceof FieldStoreWriteSideEffectNode and + exists(ChiInstruction chi | chi = nodeFrom.asInstruction() | + not chi.isResultConflated() and + nodeTo.asInstruction().(LoadInstruction).getSourceValueOperand().getAnyDef() = chi + ) } pragma[noinline] @@ -458,28 +497,6 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // for now. iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or - // The next two rules allow flow from partial definitions in setters to succeeding loads in the caller. - // First, we add flow from write side-effects to non-conflated chi instructions through their - // partial operands. Consider the following example: - // ``` - // void setX(Point* p, int new_x) { - // p->x = new_x; - // } - // ... - // setX(&p, taint()); - // ``` - // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to - // `setX`, which will be melded into `p` through a chi instruction. - iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom.(WriteSideEffectInstruction) and - not iTo.isResultConflated() - or - // Next, we add flow from non-conflated chi instructions to loads (even when they are not precise). - // This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above. - exists(ChiInstruction chi | iFrom = chi | - not chi.isResultConflated() and - iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi - ) - or // Flow from stores to structs with a single field to a load of that field. iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and exists(int size, Type type | From 3c167125e514a606cc54cb87eb8fc6bdd90d2c10 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 20 May 2020 18:18:34 +0200 Subject: [PATCH 052/111] C++: Accept test output --- .../DefaultTaintTracking/tainted.expected | 2 -- .../DefaultTaintTracking/test_diff.expected | 2 -- .../dataflow-ir-consistency.expected | 1 + .../TaintedAllocationSize.expected | 19 ------------------- 4 files changed, 1 insertion(+), 23 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index a2acc1a7dbf..e1620e55f65 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -103,8 +103,6 @@ | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | (int)... | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | access to array | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:12:111:18 | tainted | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | shared.h:6:15:6:23 | sinkparam | | dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:24:28:27 | call to atoi | | dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:34 | call to getenv | | dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:45 | (const char *)... | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected index 26c83f57cb7..b02339f160c 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -21,8 +21,6 @@ | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 | IR only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:8:111:8 | y | AST only | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x | IR only | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index 3940c1e8389..99bf7799ff2 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -31,6 +31,7 @@ postIsNotPre postHasUniquePre uniquePostUpdate | ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. | +| ref.cpp:100:34:100:36 | InitializeIndirection | Node has multiple PostUpdateNodes. | | ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. | postIsInSameCallable reverseRead diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 803b330716e..773a969e9ad 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -1,13 +1,4 @@ edges -| field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:13:3:13:18 | Chi | -| field_conflation.c:12:22:12:34 | (const char *)... | field_conflation.c:13:3:13:18 | Chi | -| field_conflation.c:13:3:13:18 | Chi | field_conflation.c:19:15:19:17 | taint_array output argument | -| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:10:20:13 | (unsigned long)... | -| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | -| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | -| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | -| field_conflation.c:20:13:20:13 | x | field_conflation.c:20:10:20:13 | (unsigned long)... | -| field_conflation.c:20:13:20:13 | x | field_conflation.c:20:13:20:13 | x | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | @@ -69,15 +60,6 @@ edges | test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | | test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | nodes -| field_conflation.c:12:22:12:27 | call to getenv | semmle.label | call to getenv | -| field_conflation.c:12:22:12:34 | (const char *)... | semmle.label | (const char *)... | -| field_conflation.c:13:3:13:18 | Chi | semmle.label | Chi | -| field_conflation.c:19:15:19:17 | taint_array output argument | semmle.label | taint_array output argument | -| field_conflation.c:20:10:20:13 | (unsigned long)... | semmle.label | (unsigned long)... | -| field_conflation.c:20:10:20:13 | (unsigned long)... | semmle.label | (unsigned long)... | -| field_conflation.c:20:13:20:13 | x | semmle.label | x | -| field_conflation.c:20:13:20:13 | x | semmle.label | x | -| field_conflation.c:20:13:20:13 | x | semmle.label | x | | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:42:38:42:44 | (size_t)... | semmle.label | (size_t)... | @@ -141,7 +123,6 @@ nodes | test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... | | test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... | #select -| field_conflation.c:20:3:20:8 | call to malloc | field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:20:13:20:13 | x | This allocation size is derived from $@ and might overflow | field_conflation.c:12:22:12:27 | call to getenv | user input (getenv) | | test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:45:31:45:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | From 617ef324649b5140dfd6555324ad1bf1a5f4fbad Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 21 May 2020 02:22:57 +0200 Subject: [PATCH 053/111] C++: Remove [FALSE POSITIVE] annotations --- .../dataflow/DefaultTaintTracking/defaulttainttracking.cpp | 2 +- .../CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index a456bc856ff..4dfba0aebf9 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -115,5 +115,5 @@ void test_conflated_fields3() { XY xy; xy.x = 0; taint_y(&xy); - sink(xy.x); // not tainted [FALSE POSITIVE] + sink(xy.x); // not tainted } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c index 5f6cb730e80..9a69a420a79 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c @@ -17,5 +17,5 @@ void test_conflated_fields3(void) { struct XY xy; xy.x = 4; taint_array(&xy); - malloc(xy.x); // not tainted [FALSE POSITIVE] + malloc(xy.x); // not tainted } From a76c70d2d78e95d0fba0475b6523ad3c034b59bd Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Tue, 19 May 2020 22:49:41 +0200 Subject: [PATCH 054/111] JS: model fastify --- change-notes/1.25/analysis-javascript.md | 1 + .../semmle/javascript/frameworks/Fastify.qll | 249 ++++++++++++++++++ .../javascript/frameworks/HttpFrameworks.qll | 1 + .../frameworks/fastify/HeaderAccess.qll | 5 + .../frameworks/fastify/HeaderDefinition.qll | 5 + .../fastify/HeaderDefinition_defines.qll | 5 + .../HeaderDefinition_getAHeaderName.qll | 5 + .../frameworks/fastify/RedirectInvocation.qll | 5 + .../frameworks/fastify/RequestInputAccess.qll | 7 + .../fastify/ResponseSendArgument.qll | 5 + .../frameworks/fastify/RouteHandler.qll | 3 + .../fastify/RouteHandler_getARequestExpr.qll | 5 + .../RouteHandler_getAResponseHeader.qll | 7 + .../frameworks/fastify/RouteSetup.qll | 3 + .../fastify/RouteSetup_getARouteHandler.qll | 5 + .../fastify/RouteSetup_getServer.qll | 3 + .../frameworks/fastify/ServerDefinition.qll | 3 + .../frameworks/fastify/src/fastify.js | 48 ++++ .../frameworks/fastify/tests.expected | 66 +++++ .../library-tests/frameworks/fastify/tests.ql | 14 + 20 files changed, 445 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/Fastify.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/HeaderAccess.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_defines.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_getAHeaderName.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RedirectInvocation.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/ResponseSendArgument.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getAResponseHeader.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteSetup.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getARouteHandler.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/ServerDefinition.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/tests.expected create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/tests.ql diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 1202d58d858..3f5c284d605 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -5,6 +5,7 @@ * Support for the following frameworks and libraries has been improved: - [bluebird](http://bluebirdjs.com/) - [express](https://www.npmjs.com/package/express) + - [fastify](https://www.npmjs.com/package/fastify) - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll new file mode 100644 index 00000000000..93b57ecccee --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -0,0 +1,249 @@ +/** + * Provides classes for working with [Fastify](https://www.fastify.io/) applications. + */ + +import javascript +import semmle.javascript.frameworks.HTTP + +module Fastify { + /** + * An expression that creates a new Fastify server. + */ + abstract class ServerDefinition extends HTTP::Servers::StandardServerDefinition { } + + /** + * A standard way to create a Fastify server. + */ + class StandardServerDefinition extends ServerDefinition { + StandardServerDefinition() { + this = DataFlow::moduleImport("fastify").getAnInvocation().asExpr() + } + } + + /** + * A function used as a Fastify route handler. + * + * By default, only handlers installed by an Fastify route setup are recognized, + * but support for other kinds of route handlers can be added by implementing + * additional subclasses of this class. + */ + abstract class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::ValueNode { + /** + * Gets the parameter of the route handler that contains the request object. + */ + abstract SimpleParameter getRequestParameter(); + + /** + * Gets the parameter of the route handler that contains the reply object. + */ + abstract SimpleParameter getReplyParameter(); + } + + /** + * A Fastify route handler installed by a route setup. + */ + class StandardRouteHandler extends RouteHandler, DataFlow::FunctionNode { + StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() } + + override SimpleParameter getRequestParameter() { result = this.getParameter(0).getParameter() } + + override SimpleParameter getReplyParameter() { result = this.getParameter(1).getParameter() } + } + + /** + * A Fastify reply source, that is, the `reply` parameter of a + * route handler. + */ + private class ReplySource extends HTTP::Servers::ResponseSource { + RouteHandler rh; + + ReplySource() { this = DataFlow::parameterNode(rh.getReplyParameter()) } + + /** + * Gets the route handler that provides this response. + */ + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * A Fastify request source, that is, the request parameter of a + * route handler. + */ + private class RequestSource extends HTTP::Servers::RequestSource { + RouteHandler rh; + + RequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } + + /** + * Gets the route handler that handles this request. + */ + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * A call to a Fastify method that sets up a route. + */ + class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup { + ServerDefinition server; + string methodName; + + RouteSetup() { + this.getMethodName() = methodName and + methodName = ["route", "get", "head", "post", "put", "delete", "options", "patch"] and + server.flowsTo(this.getReceiver()) + } + + override DataFlow::SourceNode getARouteHandler() { + result = getARouteHandler(DataFlow::TypeBackTracker::end()) + } + + private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { + t.start() and + result = this.getARouteHandlerExpr().getALocalSource() + or + exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t)) + } + + override Expr getServer() { result = server } + + /** Gets an argument that represents a route handler being registered. */ + private DataFlow::Node getARouteHandlerExpr() { + if methodName = "route" + then + result = + this + .flow() + .(DataFlow::MethodCallNode) + .getOptionArgument(0, + ["onRequest", "preParsing", "preValidation", "preHandler", "preSerialization", + "onSend", "onResponse", "handler"]) + else result = getLastArgument().flow() + } + } + + /** + * An access to a user-controlled Fastify request input. + */ + private class RequestInputAccess extends HTTP::RequestInputAccess { + RouteHandler rh; + string kind; + + RequestInputAccess() { + exists(string name | this.(DataFlow::PropRead).accesses(rh.getARequestExpr().flow(), name) | + kind = "parameter" and + name = ["params", "query"] + or + kind = "body" and + name = "body" + ) + } + + override RouteHandler getRouteHandler() { result = rh } + + override string getKind() { result = kind } + } + + /** + * An access to a header on a Fastify request. + */ + private class RequestHeaderAccess extends HTTP::RequestHeaderAccess { + RouteHandler rh; + + RequestHeaderAccess() { + exists(DataFlow::PropRead headers | + headers.accesses(rh.getARequestExpr().flow(), "headers") and + this = headers.getAPropertyRead() + ) + } + + override string getAHeaderName() { + result = this.(DataFlow::PropRead).getPropertyName().toLowerCase() + } + + override RouteHandler getRouteHandler() { result = rh } + + override string getKind() { result = "header" } + } + + /** + * An argument passed to the `send` or `end` method of an HTTP response object. + */ + private class ResponseSendArgument extends HTTP::ResponseSendArgument { + RouteHandler rh; + + ResponseSendArgument() { + exists(MethodCallExpr mce | + mce.calls(rh.getAResponseExpr(), "send") and + this = mce.getArgument(0) + ) + or + exists(Function f | + f = rh.(DataFlow::FunctionNode).getFunction() and + f.isAsync() and + f.getAReturnedExpr() = this + ) + } + + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * An invocation of the `redirect` method of an HTTP response object. + */ + private class RedirectInvocation extends HTTP::RedirectInvocation, MethodCallExpr { + RouteHandler rh; + + RedirectInvocation() { this.calls(rh.getAResponseExpr(), "redirect") } + + override Expr getUrlArgument() { result = this.getLastArgument() } + + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * An invocation that sets a single header of the HTTP response. + */ + private class SetOneHeader extends HTTP::Servers::StandardHeaderDefinition { + RouteHandler rh; + + SetOneHeader() { + astNode.calls(rh.getAResponseExpr(), "header") and + astNode.getNumArgument() = 2 + } + + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * An invocation that sets any number of headers of the HTTP response. + */ + class SetMultipleHeaders extends HTTP::ExplicitHeaderDefinition, DataFlow::MethodCallNode { + RouteHandler rh; + + SetMultipleHeaders() { + this.calls(rh.getAResponseExpr().flow(), "headers") and + this.getNumArgument() = 1 + } + + /** + * Gets a reference to the multiple headers object that is to be set. + */ + private DataFlow::SourceNode getAHeaderSource() { result.flowsTo(this.getArgument(0)) } + + override predicate definesExplicitly(string headerName, Expr headerValue) { + exists(string header | + getAHeaderSource().hasPropertyWrite(header, headerValue.flow()) and + headerName = header.toLowerCase() + ) + } + + override RouteHandler getRouteHandler() { result = rh } + + override Expr getNameExpr() { + exists(DataFlow::PropWrite write | + this.getAHeaderSource().flowsTo(write.getBase()) and + result = write.getPropertyNameExpr() + ) + } + } +} diff --git a/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll b/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll index 810246e429e..c6798fb22a5 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll @@ -4,3 +4,4 @@ import semmle.javascript.frameworks.Koa import semmle.javascript.frameworks.NodeJSLib import semmle.javascript.frameworks.Restify import semmle.javascript.frameworks.Connect +import semmle.javascript.frameworks.Fastify diff --git a/javascript/ql/test/library-tests/frameworks/fastify/HeaderAccess.qll b/javascript/ql/test/library-tests/frameworks/fastify/HeaderAccess.qll new file mode 100644 index 00000000000..22d1d6aee53 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/HeaderAccess.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_HeaderAccess(HTTP::RequestHeaderAccess access, string res) { + res = access.getAHeaderName() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition.qll b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition.qll new file mode 100644 index 00000000000..bf3ef7fb7fc --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_HeaderDefinition(HTTP::HeaderDefinition hd, Fastify::RouteHandler rh) { + rh = hd.getRouteHandler() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_defines.qll b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_defines.qll new file mode 100644 index 00000000000..43413a4dc4b --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_defines.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_HeaderDefinition_defines(HTTP::HeaderDefinition hd, string name, string value) { + hd.defines(name, value) and hd.getRouteHandler() instanceof Fastify::RouteHandler +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_getAHeaderName.qll b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_getAHeaderName.qll new file mode 100644 index 00000000000..62e1d62c06f --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_getAHeaderName.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_HeaderDefinition_getAHeaderName(HTTP::HeaderDefinition hd, string res) { + hd.getRouteHandler() instanceof Fastify::RouteHandler and res = hd.getAHeaderName() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RedirectInvocation.qll b/javascript/ql/test/library-tests/frameworks/fastify/RedirectInvocation.qll new file mode 100644 index 00000000000..fffbf35a79e --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RedirectInvocation.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_RedirectInvocation(HTTP::RedirectInvocation invk, Fastify::RouteHandler rh) { + invk.getRouteHandler() = rh +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll b/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll new file mode 100644 index 00000000000..43b8547d7bb --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll @@ -0,0 +1,7 @@ +import javascript + +query predicate test_RequestInputAccess( + HTTP::RequestInputAccess ria, string res, Fastify::RouteHandler rh +) { + ria.getRouteHandler() = rh and res = ria.getKind() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/ResponseSendArgument.qll b/javascript/ql/test/library-tests/frameworks/fastify/ResponseSendArgument.qll new file mode 100644 index 00000000000..8f221b18bd7 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/ResponseSendArgument.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_ResponseSendArgument(HTTP::ResponseSendArgument arg, Fastify::RouteHandler rh) { + arg.getRouteHandler() = rh +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll new file mode 100644 index 00000000000..89598e2169e --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll @@ -0,0 +1,3 @@ +import javascript + +query predicate test_RouteHandler(Fastify::RouteHandler rh, Expr res) { res = rh.getServer() } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll new file mode 100644 index 00000000000..dbc8d7cb896 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll @@ -0,0 +1,5 @@ +import semmle.javascript.frameworks.Express + +query predicate test_RouteHandler_getARequestExpr(Fastify::RouteHandler rh, HTTP::RequestExpr res) { + res = rh.getARequestExpr() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getAResponseHeader.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getAResponseHeader.qll new file mode 100644 index 00000000000..a5394519940 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getAResponseHeader.qll @@ -0,0 +1,7 @@ +import semmle.javascript.frameworks.Express + +query predicate test_RouteHandler_getAResponseHeader( + Fastify::RouteHandler rh, string name, HTTP::HeaderDefinition res +) { + res = rh.getAResponseHeader(name) +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup.qll new file mode 100644 index 00000000000..e75078c94f5 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup.qll @@ -0,0 +1,3 @@ +import javascript + +query predicate test_RouteSetup(Fastify::RouteSetup rs) { any() } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getARouteHandler.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getARouteHandler.qll new file mode 100644 index 00000000000..51e333d54fa --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getARouteHandler.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_RouteSetup_getARouteHandler(Fastify::RouteSetup r, DataFlow::SourceNode res) { + res = r.getARouteHandler() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll new file mode 100644 index 00000000000..8339498d094 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll @@ -0,0 +1,3 @@ +import javascript + +query predicate test_RouteSetup_getServer(Fastify::RouteSetup rs, Expr res) { res = rs.getServer() } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/ServerDefinition.qll b/javascript/ql/test/library-tests/frameworks/fastify/ServerDefinition.qll new file mode 100644 index 00000000000..97fb53f0f8e --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/ServerDefinition.qll @@ -0,0 +1,3 @@ +import javascript + +query predicate test_ServerDefinition(Fastify::ServerDefinition s) { any() } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js b/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js new file mode 100644 index 00000000000..1ab426dbe85 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js @@ -0,0 +1,48 @@ +var fastify = require("fastify")(); + +fastify.get( + "/", + /* handler */ async (request, reply) => { + return { hello: "world" }; // response + } +); + +fastify.route({ + method: "GET", + url: "/", + onRequest: /* handler */ (request, reply, done) => {}, + preParsing: /* handler */ (request, reply, done) => {}, + preValidation: /* handler */ (request, reply, done) => {}, + preHandler: /* handler */ (request, reply, done) => {}, + preSerialization: /* handler */ (request, reply, payload, done) => {}, + onSend: /* handler */ (request, reply, payload, done) => {}, + onResponse: /* handler */ (request, reply, done) => {}, + handler: /* handler */ (request, reply) => {} +}); + +fastify.get( + "/", + opts, + /* handler */ (request, reply) => { + reply.send({ hello: "world" }); // response + } +); + +fastify.post( + "/:params", + options, + /* handler */ function(request, reply) { + // request properties + request.query.name; // the parsed querystring + request.body; // the body + request.params.name; // the params matching the URL + request.headers.name; // the headers + + // reply properties + reply.header("name", "value"); // Sets a response header. + reply.headers({ name: "value" }); // Sets all the keys of the object as a response headers. + reply.redirect(code, url); // Redirect to the specified url, the status code is optional (default to 302). + reply.send(payload); // Sends the payload to the user, could be a plain text, a buffer, JSON, stream + } +); +fastify.listen(3000); diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected new file mode 100644 index 00000000000..76cf220bad1 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected @@ -0,0 +1,66 @@ +test_RouteSetup +| src/fastify.js:3:1:8:1 | fastify ... e\\n }\\n) | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | +| src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | +| src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | +test_RequestInputAccess +| src/fastify.js:36:5:36:17 | request.query | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:37:5:37:16 | request.body | body | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:38:5:38:18 | request.params | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:39:5:39:24 | request.headers.name | header | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +test_RouteHandler_getAResponseHeader +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | name | src/fastify.js:42:5:42:33 | reply.h ... value") | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | name | src/fastify.js:43:5:43:36 | reply.h ... lue" }) | +test_HeaderDefinition_defines +| src/fastify.js:42:5:42:33 | reply.h ... value") | name | value | +| src/fastify.js:43:5:43:36 | reply.h ... lue" }) | name | value | +test_HeaderDefinition +| src/fastify.js:42:5:42:33 | reply.h ... value") | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:43:5:43:36 | reply.h ... lue" }) | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +test_RouteSetup_getServer +| src/fastify.js:3:1:8:1 | fastify ... e\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | +test_HeaderDefinition_getAHeaderName +| src/fastify.js:42:5:42:33 | reply.h ... value") | name | +| src/fastify.js:43:5:43:36 | reply.h ... lue" }) | name | +test_ServerDefinition +| src/fastify.js:1:15:1:34 | require("fastify")() | +test_HeaderAccess +| src/fastify.js:39:5:39:24 | request.headers.name | name | +test_RouteSetup_getARouteHandler +| src/fastify.js:3:1:8:1 | fastify ... e\\n }\\n) | src/fastify.js:5:17:7:3 | async ( ... nse\\n } | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:13:28:13:55 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:14:29:14:56 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:15:32:15:59 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:16:29:16:56 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:17:35:17:71 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:18:25:18:61 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:19:29:19:56 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:20:26:20:47 | (reques ... ) => {} | +| src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | +| src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +test_RouteHandler +| src/fastify.js:5:17:7:3 | async ( ... nse\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:13:28:13:55 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:14:29:14:56 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:15:32:15:59 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:16:29:16:56 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:17:35:17:71 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:18:25:18:61 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:19:29:19:56 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:20:26:20:47 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:26:17:28:3 | (reques ... nse\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | +test_RouteHandler_getARequestExpr +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:36:5:36:11 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:37:5:37:11 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:38:5:38:11 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:39:5:39:11 | request | +test_ResponseSendArgument +| src/fastify.js:6:12:6:29 | { hello: "world" } | src/fastify.js:5:17:7:3 | async ( ... nse\\n } | +| src/fastify.js:27:16:27:33 | { hello: "world" } | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | +| src/fastify.js:45:16:45:22 | payload | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +test_RedirectInvocation +| src/fastify.js:44:5:44:29 | reply.r ... e, url) | src/fastify.js:34:17:46:3 | functio ... eam\\n } | diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.ql b/javascript/ql/test/library-tests/frameworks/fastify/tests.ql new file mode 100644 index 00000000000..8bf2f61f5dd --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.ql @@ -0,0 +1,14 @@ +import RouteSetup +import RequestInputAccess +import RouteHandler_getAResponseHeader +import HeaderDefinition_defines +import HeaderDefinition +import RouteSetup_getServer +import HeaderDefinition_getAHeaderName +import ServerDefinition +import HeaderAccess +import RouteSetup_getARouteHandler +import RouteHandler +import RouteHandler_getARequestExpr +import ResponseSendArgument +import RedirectInvocation From 74fc33e2a85b237421ab1bb1006b88ce57b4fbbf Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 20 May 2020 12:07:51 +0200 Subject: [PATCH 055/111] JS: make the qldoc check happy --- javascript/ql/src/semmle/javascript/frameworks/Fastify.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll index 93b57ecccee..79fc4fc4054 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -5,6 +5,9 @@ import javascript import semmle.javascript.frameworks.HTTP +/** + * Provides classes for working with [Fastify](https://www.fastify.io/) applications. + */ module Fastify { /** * An expression that creates a new Fastify server. From 894033df8a9fec3e7cf03cf79cafed2549673bc2 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 20 May 2020 13:03:54 +0200 Subject: [PATCH 056/111] JS: de-boilerplate the fastify model: address expr/dataflow comments --- .../semmle/javascript/frameworks/Fastify.qll | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll index 79fc4fc4054..2e6460c2904 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -26,7 +26,7 @@ module Fastify { /** * A function used as a Fastify route handler. * - * By default, only handlers installed by an Fastify route setup are recognized, + * By default, only handlers installed by a Fastify route setup are recognized, * but support for other kinds of route handlers can be added by implementing * additional subclasses of this class. */ @@ -34,12 +34,12 @@ module Fastify { /** * Gets the parameter of the route handler that contains the request object. */ - abstract SimpleParameter getRequestParameter(); + abstract DataFlow::ParameterNode getRequestParameter(); /** * Gets the parameter of the route handler that contains the reply object. */ - abstract SimpleParameter getReplyParameter(); + abstract DataFlow::ParameterNode getReplyParameter(); } /** @@ -48,9 +48,9 @@ module Fastify { class StandardRouteHandler extends RouteHandler, DataFlow::FunctionNode { StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() } - override SimpleParameter getRequestParameter() { result = this.getParameter(0).getParameter() } + override DataFlow::ParameterNode getRequestParameter() { result = this.getParameter(0) } - override SimpleParameter getReplyParameter() { result = this.getParameter(1).getParameter() } + override DataFlow::ParameterNode getReplyParameter() { result = this.getParameter(1) } } /** @@ -60,7 +60,7 @@ module Fastify { private class ReplySource extends HTTP::Servers::ResponseSource { RouteHandler rh; - ReplySource() { this = DataFlow::parameterNode(rh.getReplyParameter()) } + ReplySource() { this = rh.getReplyParameter() } /** * Gets the route handler that provides this response. @@ -75,7 +75,7 @@ module Fastify { private class RequestSource extends HTTP::Servers::RequestSource { RouteHandler rh; - RequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } + RequestSource() { this = rh.getRequestParameter() } /** * Gets the route handler that handles this request. @@ -132,7 +132,9 @@ module Fastify { string kind; RequestInputAccess() { - exists(string name | this.(DataFlow::PropRead).accesses(rh.getARequestExpr().flow(), name) | + exists(DataFlow::PropRead read, string name | + this = read and read = rh.getARequestSource().ref().getAPropertyRead(name) + | kind = "parameter" and name = ["params", "query"] or @@ -153,10 +155,7 @@ module Fastify { RouteHandler rh; RequestHeaderAccess() { - exists(DataFlow::PropRead headers | - headers.accesses(rh.getARequestExpr().flow(), "headers") and - this = headers.getAPropertyRead() - ) + this = rh.getARequestSource().ref().getAPropertyRead("headers").getAPropertyRead() } override string getAHeaderName() { @@ -175,16 +174,9 @@ module Fastify { RouteHandler rh; ResponseSendArgument() { - exists(MethodCallExpr mce | - mce.calls(rh.getAResponseExpr(), "send") and - this = mce.getArgument(0) - ) + this = rh.getAResponseSource().ref().getAMethodCall("send").getArgument(0).asExpr() or - exists(Function f | - f = rh.(DataFlow::FunctionNode).getFunction() and - f.isAsync() and - f.getAReturnedExpr() = this - ) + this = rh.(DataFlow::FunctionNode).getAReturn().asExpr() } override RouteHandler getRouteHandler() { result = rh } @@ -196,7 +188,9 @@ module Fastify { private class RedirectInvocation extends HTTP::RedirectInvocation, MethodCallExpr { RouteHandler rh; - RedirectInvocation() { this.calls(rh.getAResponseExpr(), "redirect") } + RedirectInvocation() { + this = rh.getAResponseSource().ref().getAMethodCall("redirect").asExpr() + } override Expr getUrlArgument() { result = this.getLastArgument() } @@ -206,12 +200,13 @@ module Fastify { /** * An invocation that sets a single header of the HTTP response. */ - private class SetOneHeader extends HTTP::Servers::StandardHeaderDefinition { + private class SetOneHeader extends HTTP::Servers::StandardHeaderDefinition, + DataFlow::MethodCallNode { RouteHandler rh; SetOneHeader() { - astNode.calls(rh.getAResponseExpr(), "header") and - astNode.getNumArgument() = 2 + this = rh.getAResponseSource().ref().getAMethodCall("header") and + this.getNumArgument() = 2 } override RouteHandler getRouteHandler() { result = rh } @@ -224,7 +219,7 @@ module Fastify { RouteHandler rh; SetMultipleHeaders() { - this.calls(rh.getAResponseExpr().flow(), "headers") and + this = rh.getAResponseSource().ref().getAMethodCall("headers") and this.getNumArgument() = 1 } From c400b45cd6dbda60edfac689bc11bb6cf444c058 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 20 May 2020 14:33:19 +0200 Subject: [PATCH 057/111] JS: make the Fastify model support `isUserControlledObject` --- .../semmle/javascript/frameworks/Fastify.qll | 45 ++++++++++++++++ .../frameworks/fastify/RequestInputAccess.qll | 8 ++- .../frameworks/fastify/src/fastify.js | 44 ++++++++++++++++ .../frameworks/fastify/tests.expected | 52 +++++++++++++++++-- 4 files changed, 143 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll index 2e6460c2904..99217fa683f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -146,6 +146,51 @@ module Fastify { override RouteHandler getRouteHandler() { result = rh } override string getKind() { result = kind } + + override predicate isUserControlledObject() { + kind = "body" and + ( + usesFastifyPlugin(rh, DataFlow::moduleImport(["fastify-xml-body-parser", "fastify-formbody"])) + or + usesMiddleware(rh, + any(ExpressLibraries::BodyParser bodyParser | bodyParser.producesUserControlledObjects())) + ) + or + kind = "parameter" and + usesFastifyPlugin(rh, DataFlow::moduleImport("fastify-qs")) + } + } + + /** + * Holds if `rh` uses `plugin`. + */ + private predicate usesFastifyPlugin(RouteHandler rh, DataFlow::SourceNode plugin) { + exists(RouteSetup setup | + plugin + .flowsTo(setup + .getServer() + .flow() + .(DataFlow::SourceNode) + .getAMethodCall("register") + .getArgument(0)) and // only matches the plugins that apply to all routes + rh = setup.getARouteHandler() + ) + } + + /** + * Holds if `rh` uses `plugin`. + */ + private predicate usesMiddleware(RouteHandler rh, DataFlow::SourceNode middleware) { + exists(RouteSetup setup | + middleware + .flowsTo(setup + .getServer() + .flow() + .(DataFlow::SourceNode) + .getAMethodCall("use") + .getArgument(0)) and // only matches the middlewares that apply to all routes + rh = setup.getARouteHandler() + ) } /** diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll b/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll index 43b8547d7bb..d8cdc2a4ccb 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll +++ b/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll @@ -1,7 +1,11 @@ import javascript query predicate test_RequestInputAccess( - HTTP::RequestInputAccess ria, string res, Fastify::RouteHandler rh + HTTP::RequestInputAccess ria, string res, Fastify::RouteHandler rh, boolean isUserControlledObject ) { - ria.getRouteHandler() = rh and res = ria.getKind() + ria.getRouteHandler() = rh and + res = ria.getKind() and + if ria.isUserControlledObject() + then isUserControlledObject = true + else isUserControlledObject = false } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js b/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js index 1ab426dbe85..8c5264b50e8 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js +++ b/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js @@ -46,3 +46,47 @@ fastify.post( } ); fastify.listen(3000); + +var fastifyWithObjects1 = require("fastify")(); +fastifyWithObjects1.register(require("fastify-xml-body-parser")); +fastifyWithObjects1.post( + "/:params", + /* handler */ function(request, reply) { + request.query; + request.body; + request.params; + } +); + +var fastifyWithObjects2 = require("fastify")(); +fastifyWithObjects2.register(require("fastify-formbody")); +fastifyWithObjects2.post( + "/:params", + /* handler */ function(request, reply) { + request.query; + request.body; + request.params; + } +); + +var fastifyWithObjects3 = require("fastify")(); +fastifyWithObjects3.register(require("fastify-qs")); +fastifyWithObjects3.post( + "/:params", + /* handler */ function(request, reply) { + request.query; + request.body; + request.params; + } +); + +var fastifyWithObjects4 = require("fastify")(); +fastifyWithObjects4.use(require("body-parser").urlencoded({ extended: true })); +fastifyWithObjects4.post( + "/:params", + /* handler */ function(request, reply) { + request.query; + request.body; + request.params; + } +); diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected index 76cf220bad1..1fd7cbfa379 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected @@ -3,11 +3,27 @@ test_RouteSetup | src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | | src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | | src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | +| src/fastify.js:52:1:59:1 | fastify ... ;\\n }\\n) | +| src/fastify.js:63:1:70:1 | fastify ... ;\\n }\\n) | +| src/fastify.js:74:1:81:1 | fastify ... ;\\n }\\n) | +| src/fastify.js:85:1:92:1 | fastify ... ;\\n }\\n) | test_RequestInputAccess -| src/fastify.js:36:5:36:17 | request.query | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | -| src/fastify.js:37:5:37:16 | request.body | body | src/fastify.js:34:17:46:3 | functio ... eam\\n } | -| src/fastify.js:38:5:38:18 | request.params | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | -| src/fastify.js:39:5:39:24 | request.headers.name | header | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:36:5:36:17 | request.query | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | false | +| src/fastify.js:37:5:37:16 | request.body | body | src/fastify.js:34:17:46:3 | functio ... eam\\n } | false | +| src/fastify.js:38:5:38:18 | request.params | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | false | +| src/fastify.js:39:5:39:24 | request.headers.name | header | src/fastify.js:34:17:46:3 | functio ... eam\\n } | false | +| src/fastify.js:55:5:55:17 | request.query | parameter | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | false | +| src/fastify.js:56:5:56:16 | request.body | body | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | true | +| src/fastify.js:57:5:57:18 | request.params | parameter | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | false | +| src/fastify.js:66:5:66:17 | request.query | parameter | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | false | +| src/fastify.js:67:5:67:16 | request.body | body | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | true | +| src/fastify.js:68:5:68:18 | request.params | parameter | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | false | +| src/fastify.js:77:5:77:17 | request.query | parameter | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | true | +| src/fastify.js:78:5:78:16 | request.body | body | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | false | +| src/fastify.js:79:5:79:18 | request.params | parameter | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | true | +| src/fastify.js:88:5:88:17 | request.query | parameter | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | false | +| src/fastify.js:89:5:89:16 | request.body | body | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | true | +| src/fastify.js:90:5:90:18 | request.params | parameter | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | false | test_RouteHandler_getAResponseHeader | src/fastify.js:34:17:46:3 | functio ... eam\\n } | name | src/fastify.js:42:5:42:33 | reply.h ... value") | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | name | src/fastify.js:43:5:43:36 | reply.h ... lue" }) | @@ -22,11 +38,19 @@ test_RouteSetup_getServer | src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:52:1:59:1 | fastify ... ;\\n }\\n) | src/fastify.js:50:27:50:46 | require("fastify")() | +| src/fastify.js:63:1:70:1 | fastify ... ;\\n }\\n) | src/fastify.js:61:27:61:46 | require("fastify")() | +| src/fastify.js:74:1:81:1 | fastify ... ;\\n }\\n) | src/fastify.js:72:27:72:46 | require("fastify")() | +| src/fastify.js:85:1:92:1 | fastify ... ;\\n }\\n) | src/fastify.js:83:27:83:46 | require("fastify")() | test_HeaderDefinition_getAHeaderName | src/fastify.js:42:5:42:33 | reply.h ... value") | name | | src/fastify.js:43:5:43:36 | reply.h ... lue" }) | name | test_ServerDefinition | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:50:27:50:46 | require("fastify")() | +| src/fastify.js:61:27:61:46 | require("fastify")() | +| src/fastify.js:72:27:72:46 | require("fastify")() | +| src/fastify.js:83:27:83:46 | require("fastify")() | test_HeaderAccess | src/fastify.js:39:5:39:24 | request.headers.name | name | test_RouteSetup_getARouteHandler @@ -41,6 +65,10 @@ test_RouteSetup_getARouteHandler | src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:20:26:20:47 | (reques ... ) => {} | | src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | | src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:52:1:59:1 | fastify ... ;\\n }\\n) | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | +| src/fastify.js:63:1:70:1 | fastify ... ;\\n }\\n) | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | +| src/fastify.js:74:1:81:1 | fastify ... ;\\n }\\n) | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | +| src/fastify.js:85:1:92:1 | fastify ... ;\\n }\\n) | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | test_RouteHandler | src/fastify.js:5:17:7:3 | async ( ... nse\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:13:28:13:55 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | @@ -53,11 +81,27 @@ test_RouteHandler | src/fastify.js:20:26:20:47 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:50:27:50:46 | require("fastify")() | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:61:27:61:46 | require("fastify")() | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:72:27:72:46 | require("fastify")() | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:83:27:83:46 | require("fastify")() | test_RouteHandler_getARequestExpr | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:36:5:36:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:37:5:37:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:38:5:38:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:39:5:39:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:55:5:55:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:56:5:56:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:57:5:57:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:66:5:66:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:67:5:67:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:68:5:68:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:77:5:77:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:78:5:78:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:79:5:79:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:88:5:88:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:89:5:89:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:90:5:90:11 | request | test_ResponseSendArgument | src/fastify.js:6:12:6:29 | { hello: "world" } | src/fastify.js:5:17:7:3 | async ( ... nse\\n } | | src/fastify.js:27:16:27:33 | { hello: "world" } | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | From e588e59f9b6459fe3123067caeb8737a8569130c Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 20 May 2020 15:14:04 +0200 Subject: [PATCH 058/111] JS: fixup --- javascript/ql/src/semmle/javascript/frameworks/Fastify.qll | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll index 99217fa683f..621017d5b4f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -132,9 +132,7 @@ module Fastify { string kind; RequestInputAccess() { - exists(DataFlow::PropRead read, string name | - this = read and read = rh.getARequestSource().ref().getAPropertyRead(name) - | + exists(string name | this = rh.getARequestSource().ref().getAPropertyRead(name) | kind = "parameter" and name = ["params", "query"] or @@ -150,7 +148,8 @@ module Fastify { override predicate isUserControlledObject() { kind = "body" and ( - usesFastifyPlugin(rh, DataFlow::moduleImport(["fastify-xml-body-parser", "fastify-formbody"])) + usesFastifyPlugin(rh, + DataFlow::moduleImport(["fastify-xml-body-parser", "fastify-formbody"])) or usesMiddleware(rh, any(ExpressLibraries::BodyParser bodyParser | bodyParser.producesUserControlledObjects())) From b31f83a5afaa9cb9d19684adff9c99d0d5b5b3a4 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Thu, 21 May 2020 13:47:16 +0200 Subject: [PATCH 059/111] JS: fixup expected output --- .../frameworks/fastify/tests.expected | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected index 1fd7cbfa379..1371bf551c8 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected @@ -86,19 +86,34 @@ test_RouteHandler | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:72:27:72:46 | require("fastify")() | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:83:27:83:46 | require("fastify")() | test_RouteHandler_getARequestExpr +| src/fastify.js:5:17:7:3 | async ( ... nse\\n } | src/fastify.js:5:24:5:30 | request | +| src/fastify.js:13:28:13:55 | (reques ... ) => {} | src/fastify.js:13:29:13:35 | request | +| src/fastify.js:14:29:14:56 | (reques ... ) => {} | src/fastify.js:14:30:14:36 | request | +| src/fastify.js:15:32:15:59 | (reques ... ) => {} | src/fastify.js:15:33:15:39 | request | +| src/fastify.js:16:29:16:56 | (reques ... ) => {} | src/fastify.js:16:30:16:36 | request | +| src/fastify.js:17:35:17:71 | (reques ... ) => {} | src/fastify.js:17:36:17:42 | request | +| src/fastify.js:18:25:18:61 | (reques ... ) => {} | src/fastify.js:18:26:18:32 | request | +| src/fastify.js:19:29:19:56 | (reques ... ) => {} | src/fastify.js:19:30:19:36 | request | +| src/fastify.js:20:26:20:47 | (reques ... ) => {} | src/fastify.js:20:27:20:33 | request | +| src/fastify.js:26:17:28:3 | (reques ... nse\\n } | src/fastify.js:26:18:26:24 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:34:26:34:32 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:36:5:36:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:37:5:37:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:38:5:38:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:39:5:39:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:54:26:54:32 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:55:5:55:11 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:56:5:56:11 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:57:5:57:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:65:26:65:32 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:66:5:66:11 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:67:5:67:11 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:68:5:68:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:76:26:76:32 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:77:5:77:11 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:78:5:78:11 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:79:5:79:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:87:26:87:32 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:88:5:88:11 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:89:5:89:11 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:90:5:90:11 | request | From 75be3b7ecbb251049110bc7731dbeb863858bc94 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 21 May 2020 16:14:13 +0100 Subject: [PATCH 060/111] JS: Add test case for missed captured flow --- .../TaintTracking/BasicTaintTracking.expected | 1 + .../TaintTracking/DataFlowTracking.expected | 1 + .../TaintTracking/capture-flow.js | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 javascript/ql/test/library-tests/TaintTracking/capture-flow.js diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 9c12e879372..261631d61ab 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -31,6 +31,7 @@ typeInferenceMismatch | callbacks.js:44:17:44:24 | source() | callbacks.js:41:10:41:10 | x | | callbacks.js:50:18:50:25 | source() | callbacks.js:30:29:30:29 | y | | callbacks.js:51:18:51:25 | source() | callbacks.js:30:29:30:29 | y | +| capture-flow.js:9:11:9:18 | source() | capture-flow.js:14:10:14:16 | outer() | | captured-sanitizer.js:25:3:25:10 | source() | captured-sanitizer.js:15:10:15:10 | x | | closure.js:6:15:6:22 | source() | closure.js:8:8:8:31 | string. ... (taint) | | closure.js:6:15:6:22 | source() | closure.js:9:8:9:25 | string.trim(taint) | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 471c5991025..5434cc908ba 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -22,6 +22,7 @@ | callbacks.js:44:17:44:24 | source() | callbacks.js:41:10:41:10 | x | | callbacks.js:50:18:50:25 | source() | callbacks.js:30:29:30:29 | y | | callbacks.js:51:18:51:25 | source() | callbacks.js:30:29:30:29 | y | +| capture-flow.js:9:11:9:18 | source() | capture-flow.js:14:10:14:16 | outer() | | captured-sanitizer.js:25:3:25:10 | source() | captured-sanitizer.js:15:10:15:10 | x | | constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:18:8:18:14 | c.taint | | constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:22:8:22:19 | c_safe.taint | diff --git a/javascript/ql/test/library-tests/TaintTracking/capture-flow.js b/javascript/ql/test/library-tests/TaintTracking/capture-flow.js new file mode 100644 index 00000000000..f9b7d30d4cf --- /dev/null +++ b/javascript/ql/test/library-tests/TaintTracking/capture-flow.js @@ -0,0 +1,19 @@ +import 'dummy'; + +function outerMost() { + function outer() { + var captured; + function f(x) { + captured = x; + } + f(source()); + + return captured; + } + + sink(outer()); // NOT OK + + return outer(); +} + +sink(outerMost()); // NOT OK - but missed From 6f0356b2297034ffa1dbe3b814e87d6c4b07db9f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 22 May 2020 10:40:07 +0100 Subject: [PATCH 061/111] Revert "JS: Remove timeout for node --version check" This reverts commit ec7c9489dc890f6656bb8b2dc40b39998dc1007c. --- .../extractor/src/com/semmle/js/parser/TypeScriptParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index 7467507ef75..d7ead7adecc 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -203,7 +203,7 @@ public class TypeScriptParser { getNodeJsRuntimeInvocation("--version"), out, err, getParserWrapper().getParentFile()); b.expectFailure(); // We want to do our own logging in case of an error. - int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 0); // Default to no timeout. + int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); try { int r = b.execute(timeout); String stdout = new String(out.toByteArray()); From 823ed3bbdf0f5ff524035d30ab537e9062e064a5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 20 May 2020 16:58:42 +0100 Subject: [PATCH 062/111] JS: Wrap node --version call in retry loop --- .../semmle/js/parser/TypeScriptParser.java | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index d7ead7adecc..0d505ecb578 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -86,6 +86,12 @@ public class TypeScriptParser { */ public static final String TYPESCRIPT_TIMEOUT_VAR = "SEMMLE_TYPESCRIPT_TIMEOUT"; + /** + * An environment variable that can be set to specify a number of retries when verifying + * the TypeScript installation. Default is 3. + */ + public static final String TYPESCRIPT_RETRIES_VAR = "SEMMLE_TYPESCRIPT_RETRIES"; + /** * An environment variable (without the SEMMLE_ or LGTM_ prefix), that can be * set to indicate the maximum heap space usable by the Node.js process, in addition to its @@ -179,9 +185,6 @@ public class TypeScriptParser { public String verifyNodeInstallation() { if (nodeJsVersionString != null) return nodeJsVersionString; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteArrayOutputStream err = new ByteArrayOutputStream(); - // Determine where to find the Node.js runtime. String explicitNodeJsRuntime = Env.systemEnv().get(TYPESCRIPT_NODE_RUNTIME_VAR); if (explicitNodeJsRuntime != null) { @@ -198,12 +201,41 @@ public class TypeScriptParser { nodeJsRuntimeExtraArgs = Arrays.asList(extraArgs.split("\\s+")); } + // Run 'node --version' with a timeout, and retry a few times if it times out. + // If the Java process is suspended we may get a spurious timeout, and we want to + // support long suspensions in cloud environments. Instead of setting a huge timeout, + // retrying guarantees we can survive arbitrary suspensions as long as they don't happen + // too many times in rapid succession. + int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); + int numRetries = Env.systemEnv().getInt(TYPESCRIPT_RETRIES_VAR, 3); + for (int i = 0; i < numRetries - 1; ++i) { + try { + return startNodeAndGetVersion(timeout); + } catch (InterruptedError e) { + Exceptions.ignore(e, "We will retry the call that caused this exception."); + System.err.println("Starting Node.js seems to take a long time. Retrying."); + } + } + try { + return startNodeAndGetVersion(timeout); + } catch (InterruptedError e) { + Exceptions.ignore(e, "Exception details are not important."); + throw new CatastrophicError( + "Could not start Node.js (timed out after " + (timeout / 1000) + "s and " + numRetries + " attempts"); + } + } + + /** + * Checks that Node.js is installed and can be run and returns its version string. + */ + private String startNodeAndGetVersion(int timeout) throws InterruptedError { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream(); Builder b = new Builder( getNodeJsRuntimeInvocation("--version"), out, err, getParserWrapper().getParentFile()); b.expectFailure(); // We want to do our own logging in case of an error. - int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); try { int r = b.execute(timeout); String stdout = new String(out.toByteArray()); @@ -213,10 +245,6 @@ public class TypeScriptParser { "Could not start Node.js. It is required for TypeScript extraction.\n" + stderr); } return nodeJsVersionString = stdout; - } catch (InterruptedError e) { - Exceptions.ignore(e, "Exception details are not important."); - throw new CatastrophicError( - "Could not start Node.js (timed out after " + (timeout / 1000) + "s)."); } catch (ResourceError e) { // In case 'node' is not found, the process builder converts the IOException // into a ResourceError. From df834ac0319e25a199d451a2fcb24d18430cf98c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 22 May 2020 16:14:47 -0400 Subject: [PATCH 063/111] C++: Fix duplicate result types In a couple of cases, we use `glval` as the result type of an instruction because we can't come up with anything better. Two examples are the result of `VariableAddress[#ellipsis]`, and the address of the temp variable that holds the lvalue result of the conditional operator in `(a ? b : c) = y`. In both cases, we call `getTypeForGLValue(any(UnknownType t))`, but that would have multiple results because `result.hasType(any(UnknownType t), true)` also holds for `CppFunctionGLValueType`. I tightened the result type to ensure we get the right one. --- cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index 7a164012845..f8c4ceaf904 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -362,7 +362,7 @@ CppType getTypeForPRValueOrUnknown(Type type) { /** * Gets the `CppType` that represents a glvalue of type `type`. */ -CppType getTypeForGLValue(Type type) { result.hasType(type, true) } +CppGLValueAddressType getTypeForGLValue(Type type) { result.hasType(type, true) } /** * Gets the `CppType` that represents a prvalue of type `int`. From 573fdaa424cc84246bdedc819c2639dbb45d8e93 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 22 May 2020 17:31:09 +0100 Subject: [PATCH 064/111] JavaScript: Track `require` through local data flow. --- .../ql/src/semmle/javascript/NodeJS.qll | 23 ++++++++++++------- .../library-tests/NodeJS/Require.expected | 2 ++ javascript/ql/test/library-tests/NodeJS/g.js | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 javascript/ql/test/library-tests/NodeJS/g.js diff --git a/javascript/ql/src/semmle/javascript/NodeJS.qll b/javascript/ql/src/semmle/javascript/NodeJS.qll index 8376debf8b0..6da4a625537 100644 --- a/javascript/ql/src/semmle/javascript/NodeJS.qll +++ b/javascript/ql/src/semmle/javascript/NodeJS.qll @@ -152,6 +152,18 @@ private class RequireVariable extends Variable { */ private predicate moduleInFile(Module m, File f) { m.getFile() = f } +/** + * Holds if `nd` may refer to `require`, either directly or modulo local data flow. + */ +cached +private predicate isRequire(DataFlow::Node nd) { + nd.asExpr() = any(RequireVariable req).getAnAccess() and + // `mjs` files explicitly disallow `require` + not nd.getFile().getExtension() = "mjs" + or + isRequire(nd.getAPredecessor()) +} + /** * A `require` import. * @@ -162,12 +174,7 @@ private predicate moduleInFile(Module m, File f) { m.getFile() = f } * ``` */ class Require extends CallExpr, Import { - cached - Require() { - any(RequireVariable req).getAnAccess() = getCallee() and - // `mjs` files explicitly disallow `require` - not getFile().getExtension() = "mjs" - } + Require() { isRequire(getCallee().flow()) } override PathExpr getImportedPath() { result = getArgument(0) } @@ -257,8 +264,8 @@ private class RequirePath extends PathExprCandidate { RequirePath() { this = any(Require req).getArgument(0) or - exists(RequireVariable req, MethodCallExpr reqres | - reqres.getReceiver() = req.getAnAccess() and + exists(MethodCallExpr reqres | + isRequire(reqres.getReceiver().flow()) and reqres.getMethodName() = "resolve" and this = reqres.getArgument(0) ) diff --git a/javascript/ql/test/library-tests/NodeJS/Require.expected b/javascript/ql/test/library-tests/NodeJS/Require.expected index 7e9a50685ab..cdbead07939 100644 --- a/javascript/ql/test/library-tests/NodeJS/Require.expected +++ b/javascript/ql/test/library-tests/NodeJS/Require.expected @@ -11,6 +11,8 @@ | d.js:7:1:7:14 | require('foo') | | e.js:5:1:5:18 | require("process") | | f.js:2:1:2:7 | r("fs") | +| g.js:1:1:1:96 | (proces ... https") | +| g.js:1:43:1:61 | require("electron") | | index.js:1:12:1:26 | require('path') | | index.js:2:1:2:41 | require ... b.js")) | | mjs-files/require-from-js.js:1:12:1:36 | require ... on-me') | diff --git a/javascript/ql/test/library-tests/NodeJS/g.js b/javascript/ql/test/library-tests/NodeJS/g.js new file mode 100644 index 00000000000..9d04081336e --- /dev/null +++ b/javascript/ql/test/library-tests/NodeJS/g.js @@ -0,0 +1 @@ +(process && "renderer" === process.type ? require("electron").remote.require : require)("https"); \ No newline at end of file From 3e712be431436c864c6d9030aa706ab1c768f3ab Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 15 May 2020 19:08:41 +0200 Subject: [PATCH 065/111] Python: Modernise --- .../DefineEqualsWhenAddingAttributes.ql | 28 +++++++++---------- .../DefineEqualsWhenAddingAttributes.expected | 4 +-- .../DefineEqualsWhenAddingFields.expected | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql index 8bf7d24b729..a0fff36b344 100644 --- a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql +++ b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql @@ -14,21 +14,21 @@ import python import semmle.python.SelfAttribute import Equality -predicate class_stores_to_attribute(ClassObject cls, SelfAttributeStore store, string name) { - exists(FunctionObject f | - f = cls.declaredAttribute(_) and store.getScope() = f.getFunction() and store.getName() = name +predicate class_stores_to_attribute(ClassValue cls, SelfAttributeStore store, string name) { + exists(FunctionValue f | + f = cls.declaredAttribute(_) and store.getScope() = f.getScope() and store.getName() = name ) and /* Exclude classes used as metaclasses */ - not cls.getASuperType() = theTypeType() + not cls.getASuperType() = ClassValue::type() } -predicate should_override_eq(ClassObject cls, Object base_eq) { +predicate should_override_eq(ClassValue cls, Value base_eq) { not cls.declaresAttribute("__eq__") and - exists(ClassObject sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | - not exists(GenericEqMethod eq | eq.getScope() = sup.getPyClass()) and - not exists(IdentityEqMethod eq | eq.getScope() = sup.getPyClass()) and - not base_eq.(FunctionObject).getFunction() instanceof IdentityEqMethod and - not base_eq = theObjectType().declaredAttribute("__eq__") + exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | + not exists(GenericEqMethod eq | eq.getScope() = sup.getScope()) and + not exists(IdentityEqMethod eq | eq.getScope() = sup.getScope()) and + not base_eq.(FunctionValue).getScope() instanceof IdentityEqMethod and + not base_eq = ClassValue::object().declaredAttribute("__eq__") ) } @@ -36,16 +36,16 @@ predicate should_override_eq(ClassObject cls, Object base_eq) { * Does the non-overridden __eq__ method access the attribute, * which implies that the __eq__ method does not need to be overridden. */ -predicate superclassEqExpectsAttribute(ClassObject cls, PyFunctionObject base_eq, string attrname) { +predicate superclassEqExpectsAttribute(ClassValue cls, FunctionValue base_eq, string attrname) { not cls.declaresAttribute("__eq__") and - exists(ClassObject sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | + exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | exists(SelfAttributeRead store | store.getName() = attrname | - store.getScope() = base_eq.getFunction() + store.getScope() = base_eq.getScope() ) ) } -from ClassObject cls, SelfAttributeStore store, Object base_eq +from ClassValue cls, SelfAttributeStore store, Value base_eq where class_stores_to_attribute(cls, store, _) and should_override_eq(cls, base_eq) and diff --git a/python/ql/test/3/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected b/python/ql/test/3/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected index 8f5f5e7b762..8843b6d52ef 100644 --- a/python/ql/test/3/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected +++ b/python/ql/test/3/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected @@ -1,2 +1,2 @@ -| test.py:12:1:12:24 | class C | The class 'C' does not override $@, but adds the new attribute $@. | test.py:9:5:9:28 | Function __eq__ | '__eq__' | test.py:15:9:15:14 | Attribute | a | -| test.py:12:1:12:24 | class C | The class 'C' does not override $@, but adds the new attribute $@. | test.py:9:5:9:28 | Function __eq__ | '__eq__' | test.py:15:17:15:22 | Attribute | b | +| test.py:12:1:12:24 | class C | The class 'C' does not override $@, but adds the new attribute $@. | test.py:9:5:9:28 | Function RedefineEquals.__eq__ | '__eq__' | test.py:15:9:15:14 | Attribute | a | +| test.py:12:1:12:24 | class C | The class 'C' does not override $@, but adds the new attribute $@. | test.py:9:5:9:28 | Function RedefineEquals.__eq__ | '__eq__' | test.py:15:17:15:22 | Attribute | b | diff --git a/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected b/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected index dcdb8992b18..2f5a5a249f5 100644 --- a/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected +++ b/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected @@ -1 +1 @@ -| attr_eq_test.py:21:1:21:27 | class BadColorPoint | The class 'BadColorPoint' does not override $@, but adds the new attribute $@. | attr_eq_test.py:10:5:10:28 | Function __eq__ | '__eq__' | attr_eq_test.py:25:9:25:19 | Attribute | _color | +| attr_eq_test.py:21:1:21:27 | class BadColorPoint | The class 'BadColorPoint' does not override $@, but adds the new attribute $@. | attr_eq_test.py:10:5:10:28 | Function Point.__eq__ | '__eq__' | attr_eq_test.py:25:9:25:19 | Attribute | _color | From 9e0d57c610d969a7d5e78034fef6d0c73afa6e03 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 09:47:01 +0200 Subject: [PATCH 066/111] Python: Fix grammar in QLDoc Co-authored-by: Taus --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 2a49d0d44c4..6b431723d18 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -444,7 +444,7 @@ class BoundMethodValue extends CallableValue { BoundMethodValue() { this instanceof BoundMethodObjectInternal } /** - * Gets the callable that will be used when `this` called. + * Gets the callable that will be used when `this` is called. * The actual callable for `func` in `o.func`. */ CallableValue getFunction() { result = this.(BoundMethodObjectInternal).getFunction() } From 87ee6ae10198f8fd6398348425f5d30d0784ca63 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 09:53:28 +0200 Subject: [PATCH 067/111] Python: Add a bit of docs to CallableObjectInternal As requested :) --- python/ql/src/semmle/python/objects/Callables.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ql/src/semmle/python/objects/Callables.qll b/python/ql/src/semmle/python/objects/Callables.qll index a25f1ad3e7d..4021f04c510 100644 --- a/python/ql/src/semmle/python/objects/Callables.qll +++ b/python/ql/src/semmle/python/objects/Callables.qll @@ -27,8 +27,10 @@ abstract class CallableObjectInternal extends ObjectInternal { none() } + /** Gets the `n`th parameter node of this callable. */ abstract NameNode getParameter(int n); + /** Gets the `name`d parameter node of this callable. */ abstract NameNode getParameterByName(string name); abstract predicate neverReturns(); @@ -447,6 +449,10 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod { n >= 0 } + /** + * Gets the `name`d parameter node of this callable. + * Will not return the parameter node for `self`, instead use `getSelfParameter`. + */ override NameNode getParameterByName(string name) { result = this.getFunction().getParameterByName(name) and not result = this.getSelfParameter() From 4fc3cae6466264256abbbe3ccd6f5f2d3b9d60e4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 10:14:25 +0200 Subject: [PATCH 068/111] Python: Add test for how arguments to *args and **kwargs are handled --- .../library-tests/PointsTo/calls/CallPointsTo.expected | 2 ++ .../test/library-tests/PointsTo/calls/GetACall.expected | 2 ++ .../PointsTo/calls/getArgumentForCall.expected | 4 ++++ .../PointsTo/calls/getNamedArgumentForCall.expected | 2 ++ .../library-tests/PointsTo/calls/getParameter.expected | 2 ++ .../PointsTo/calls/getParameterByName.expected | 2 ++ python/ql/test/library-tests/PointsTo/calls/test.py | 9 +++++++++ 7 files changed, 23 insertions(+) diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected index 101e971cb37..05c4d41406e 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -15,3 +15,5 @@ | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | | 45 | ControlFlowNode for open() | Builtin-function open | | 46 | ControlFlowNode for open() | Builtin-function open | +| 51 | ControlFlowNode for foo() | Function foo | +| 55 | ControlFlowNode for bar() | Function bar | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 51051e1de00..c9b7822b278 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -19,3 +19,5 @@ | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | | 45 | ControlFlowNode for open() | Builtin-function open | | 46 | ControlFlowNode for open() | Builtin-function open | +| 51 | ControlFlowNode for foo() | Function foo | +| 55 | ControlFlowNode for bar() | Function bar | diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected index 9cb8b3e9862..c834c72049f 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -28,3 +28,7 @@ | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for IntegerLiteral | | 45 | ControlFlowNode for open() | Builtin-function open | 0 | ControlFlowNode for Str | | 45 | ControlFlowNode for open() | Builtin-function open | 1 | ControlFlowNode for Str | +| 51 | ControlFlowNode for foo() | Function foo | 0 | ControlFlowNode for IntegerLiteral | +| 51 | ControlFlowNode for foo() | Function foo | 1 | ControlFlowNode for IntegerLiteral | +| 51 | ControlFlowNode for foo() | Function foo | 2 | ControlFlowNode for IntegerLiteral | +| 55 | ControlFlowNode for bar() | Function bar | 0 | ControlFlowNode for IntegerLiteral | diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected index 0bde0a2b585..c12eff4249a 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -23,3 +23,5 @@ | 42 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | arg1 | ControlFlowNode for IntegerLiteral | +| 51 | ControlFlowNode for foo() | Function foo | a | ControlFlowNode for IntegerLiteral | +| 55 | ControlFlowNode for bar() | Function bar | a | ControlFlowNode for IntegerLiteral | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected index 86f3e525a9f..3f384d38786 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected @@ -1,9 +1,11 @@ | Function C.n | 0 | ControlFlowNode for self | | Function C.n | 1 | ControlFlowNode for arg1 | | Function D.foo | 0 | ControlFlowNode for arg | +| Function bar | 0 | ControlFlowNode for a | | Function f | 0 | ControlFlowNode for arg0 | | Function f | 1 | ControlFlowNode for arg1 | | Function f | 2 | ControlFlowNode for arg2 | +| Function foo | 0 | ControlFlowNode for a | | Method(Function C.n, C()) | 0 | ControlFlowNode for arg1 | | Method(Function C.n, class C) | 0 | ControlFlowNode for arg1 | | Method(Function f, C()) | 0 | ControlFlowNode for arg1 | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected index 74ded3b8a4d..da61f6296a7 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected @@ -1,9 +1,11 @@ | Function C.n | arg1 | ControlFlowNode for arg1 | | Function C.n | self | ControlFlowNode for self | | Function D.foo | arg | ControlFlowNode for arg | +| Function bar | a | ControlFlowNode for a | | Function f | arg0 | ControlFlowNode for arg0 | | Function f | arg1 | ControlFlowNode for arg1 | | Function f | arg2 | ControlFlowNode for arg2 | +| Function foo | a | ControlFlowNode for a | | Method(Function C.n, C()) | arg1 | ControlFlowNode for arg1 | | Method(Function C.n, class C) | arg1 | ControlFlowNode for arg1 | | Method(Function f, C()) | arg1 | ControlFlowNode for arg1 | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index a8c7210b4ec..1c469dd8afa 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -44,3 +44,12 @@ c.n(arg1=1) # positional/keyword arguments for a builtin function open("foo.txt", "rb") # TODO: Not handled by getNamedArgumentForCall open(file="foo.txt", mode="rb") # TODO: Not handled by either getNamedArgumentForCall or getArgumentForCall + +# Testing how arguments to *args and **kwargs are handled +def foo(a, *args): + pass +foo(1, 2, 3) + +def bar(a, **kwargs): + pass +bar(a=1, b=2, c=3) # TODO: no result for `b` or `c` with getNamedArgumentForCall From 49d7e12acde402dbde28bd0e53a31b2b24679fb0 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 09:57:48 +0200 Subject: [PATCH 069/111] Python: Remove unnecessary restriction from getNamedArgumentForCall As agreed in https://github.com/github/codeql/pull/3407 --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 4 +--- .../PointsTo/calls/getNamedArgumentForCall.expected | 4 ++++ python/ql/test/library-tests/PointsTo/calls/test.py | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 6b431723d18..320135814e1 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -397,7 +397,6 @@ class CallableValue extends Value { /** * Gets the argument in `call` corresponding to the `name`d keyword parameter of this callable. - * ONLY WORKS FOR NON-BUILTINS. * * This method also gives results when the argument is passed as a positional argument in `call`, as long * as `this` is not a builtin function or a builtin method. @@ -420,8 +419,7 @@ class CallableValue extends Value { PointsToInternal::pointsTo(call.getFunction(), _, called, _) and called.functionAndOffset(this, offset) | - call.getArgByName(name) = result and - exists(this.getParameterByName(name)) + call.getArgByName(name) = result or exists(int n | call.getArg(n) = result and diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected index c12eff4249a..3df8b4336bf 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -23,5 +23,9 @@ | 42 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | arg1 | ControlFlowNode for IntegerLiteral | +| 46 | ControlFlowNode for open() | Builtin-function open | file | ControlFlowNode for Str | +| 46 | ControlFlowNode for open() | Builtin-function open | mode | ControlFlowNode for Str | | 51 | ControlFlowNode for foo() | Function foo | a | ControlFlowNode for IntegerLiteral | | 55 | ControlFlowNode for bar() | Function bar | a | ControlFlowNode for IntegerLiteral | +| 55 | ControlFlowNode for bar() | Function bar | b | ControlFlowNode for IntegerLiteral | +| 55 | ControlFlowNode for bar() | Function bar | c | ControlFlowNode for IntegerLiteral | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index 1c469dd8afa..449f7fe49fc 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -43,7 +43,7 @@ c.n(arg1=1) # positional/keyword arguments for a builtin function open("foo.txt", "rb") # TODO: Not handled by getNamedArgumentForCall -open(file="foo.txt", mode="rb") # TODO: Not handled by either getNamedArgumentForCall or getArgumentForCall +open(file="foo.txt", mode="rb") # Testing how arguments to *args and **kwargs are handled def foo(a, *args): @@ -52,4 +52,4 @@ foo(1, 2, 3) def bar(a, **kwargs): pass -bar(a=1, b=2, c=3) # TODO: no result for `b` or `c` with getNamedArgumentForCall +bar(a=1, b=2, c=3) From 32c8dd0491f7bf5c4a3014efa6cd98282b67d80f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 11:05:30 +0200 Subject: [PATCH 070/111] Python: Fix (upcoming) deprecation compiler-warnings In a near-future release overriding a deprecated predicate without making as deprecated would give a compiler warning. Not fixing the XML one. [I can see that this shouldn't be reported anymore](https://github.com/github/codeql/pull/3520#issuecomment-631552943), and it's not safe to remove since it was only marked as deprecated in e6425bb4cf1b7b00f1b6ff592a1956de0fc0a8b6. --- python/ql/src/semmle/python/Exprs.qll | 2 +- python/ql/src/semmle/python/types/ModuleObject.qll | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/semmle/python/Exprs.qll b/python/ql/src/semmle/python/Exprs.qll index 2b58fe38e4e..a137f4d4fb0 100644 --- a/python/ql/src/semmle/python/Exprs.qll +++ b/python/ql/src/semmle/python/Exprs.qll @@ -597,7 +597,7 @@ class StrConst extends Str_, ImmutableLiteral { this.getEnclosingModule().hasFromFuture("unicode_literals") } - override string strValue() { result = this.getS() } + deprecated override string strValue() { result = this.getS() } override Expr getASubExpression() { none() } diff --git a/python/ql/src/semmle/python/types/ModuleObject.qll b/python/ql/src/semmle/python/types/ModuleObject.qll index 3b5d15c41b1..644d4e60244 100644 --- a/python/ql/src/semmle/python/types/ModuleObject.qll +++ b/python/ql/src/semmle/python/types/ModuleObject.qll @@ -118,7 +118,7 @@ class BuiltinModuleObject extends ModuleObject { override predicate hasAttribute(string name) { exists(this.asBuiltin().getMember(name)) } - override predicate exportsComplete() { any() } + deprecated override predicate exportsComplete() { any() } } class PythonModuleObject extends ModuleObject { @@ -132,7 +132,7 @@ class PythonModuleObject extends ModuleObject { override Container getPath() { result = this.getModule().getFile() } - override predicate exportsComplete() { + deprecated override predicate exportsComplete() { exists(Module m | m = this.getModule() | not exists(Call modify, Attribute attr, GlobalVariable all | modify.getScope() = m and @@ -196,7 +196,7 @@ class PackageObject extends ModuleObject { ) } - override predicate exportsComplete() { + deprecated override predicate exportsComplete() { not exists(this.getInitModule()) or this.getInitModule().exportsComplete() From 6ce1b9f7fa81da8bfdb6e8255df9f618a111c12f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 13:12:56 +0200 Subject: [PATCH 071/111] Python: Fix use of StrConst.strValue() --- python/ql/src/Variables/UndefinedExport.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Variables/UndefinedExport.ql b/python/ql/src/Variables/UndefinedExport.ql index 4d81e0f3c8d..d536e63b856 100644 --- a/python/ql/src/Variables/UndefinedExport.ql +++ b/python/ql/src/Variables/UndefinedExport.ql @@ -59,7 +59,7 @@ predicate contains_unknown_import_star(ModuleValue m) { from ModuleValue m, StrConst name, string exported_name where declaredInAll(m.getScope(), name) and - exported_name = name.strValue() and + exported_name = name.getText() and not m.hasAttribute(exported_name) and not is_exported_submodule_name(m, exported_name) and not contains_unknown_import_star(m) and From 74167923bc57c7d99cc3c500e10e906f17bbf59a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 13:17:32 +0200 Subject: [PATCH 072/111] Python: Fix filename example I got my eyes on this one since it was using a deprecated method, BUT it was also doing the thing, since File.getName() is the same as File.getAbsolutePath(), and that doesn't match the description :\ --- python/ql/examples/snippets/filename.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/examples/snippets/filename.ql b/python/ql/examples/snippets/filename.ql index 579cceea47a..d0a2d122603 100644 --- a/python/ql/examples/snippets/filename.ql +++ b/python/ql/examples/snippets/filename.ql @@ -8,5 +8,5 @@ import python from File f -where f.getName() = "spam.py" +where f.getShortName() = "spam.py" select f From f602f3e1c71317fae2f8df2ebbf672253ea25dfa Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 13:45:49 +0200 Subject: [PATCH 073/111] Python: Use proper import for semmle.python.dataflow.TaintTracking It was moved in 637677d515d1301b0818eac396a64ef72ee02274, but imports were not updated. --- python/ql/src/Security/CWE-022/TarSlip.ql | 2 +- python/ql/src/Security/CWE-312/CleartextLogging.ql | 2 +- python/ql/src/Security/CWE-312/CleartextStorage.ql | 2 +- python/ql/src/Security/CWE-798/HardcodedCredentials.ql | 2 +- python/ql/src/Variables/Undefined.qll | 2 +- python/ql/src/semmle/python/dataflow/Configuration.qll | 2 +- python/ql/src/semmle/python/dataflow/DataFlow.qll | 2 +- python/ql/src/semmle/python/dataflow/Files.qll | 2 +- python/ql/src/semmle/python/dataflow/Legacy.qll | 2 +- python/ql/src/semmle/python/security/ClearText.qll | 2 +- python/ql/src/semmle/python/security/Crypto.qll | 2 +- python/ql/src/semmle/python/security/Exceptions.qll | 2 +- python/ql/src/semmle/python/security/SQL.qll | 2 +- python/ql/src/semmle/python/security/SensitiveData.qll | 2 +- python/ql/src/semmle/python/security/injection/Command.qll | 2 +- .../ql/src/semmle/python/security/injection/Deserialization.qll | 2 +- python/ql/src/semmle/python/security/injection/Exec.qll | 2 +- python/ql/src/semmle/python/security/injection/Marshal.qll | 2 +- python/ql/src/semmle/python/security/injection/Path.qll | 2 +- python/ql/src/semmle/python/security/injection/Pickle.qll | 2 +- python/ql/src/semmle/python/security/injection/Sql.qll | 2 +- python/ql/src/semmle/python/security/injection/Xml.qll | 2 +- python/ql/src/semmle/python/security/injection/Yaml.qll | 2 +- python/ql/src/semmle/python/security/strings/Basic.qll | 2 +- python/ql/src/semmle/python/web/bottle/Redirect.qll | 2 +- python/ql/src/semmle/python/web/bottle/Request.qll | 2 +- python/ql/src/semmle/python/web/bottle/Response.qll | 2 +- python/ql/src/semmle/python/web/cherrypy/Request.qll | 2 +- python/ql/src/semmle/python/web/cherrypy/Response.qll | 2 +- python/ql/src/semmle/python/web/django/Model.qll | 2 +- python/ql/src/semmle/python/web/django/Redirect.qll | 2 +- python/ql/src/semmle/python/web/django/Request.qll | 2 +- python/ql/src/semmle/python/web/django/Response.qll | 2 +- python/ql/src/semmle/python/web/falcon/Request.qll | 2 +- python/ql/src/semmle/python/web/falcon/Response.qll | 2 +- python/ql/src/semmle/python/web/flask/Redirect.qll | 2 +- python/ql/src/semmle/python/web/flask/Request.qll | 2 +- python/ql/src/semmle/python/web/flask/Response.qll | 2 +- python/ql/src/semmle/python/web/pyramid/Redirect.qll | 2 +- python/ql/src/semmle/python/web/pyramid/Request.qll | 2 +- python/ql/src/semmle/python/web/pyramid/Response.qll | 2 +- python/ql/src/semmle/python/web/stdlib/Request.qll | 2 +- python/ql/src/semmle/python/web/stdlib/Response.qll | 2 +- python/ql/src/semmle/python/web/tornado/Redirect.qll | 2 +- python/ql/src/semmle/python/web/tornado/Request.qll | 2 +- python/ql/src/semmle/python/web/tornado/Response.qll | 2 +- python/ql/src/semmle/python/web/tornado/Tornado.qll | 2 +- python/ql/src/semmle/python/web/turbogears/Response.qll | 2 +- python/ql/src/semmle/python/web/turbogears/TurboGears.qll | 2 +- python/ql/src/semmle/python/web/twisted/Request.qll | 2 +- python/ql/src/semmle/python/web/twisted/Response.qll | 2 +- python/ql/src/semmle/python/web/twisted/Twisted.qll | 2 +- python/ql/src/semmle/python/web/webob/Request.qll | 2 +- python/ql/test/3/library-tests/taint/unpacking/Taint.qll | 2 +- python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql | 2 +- .../ql/test/library-tests/examples/custom-sanitizer/Taint.qll | 2 +- .../test/library-tests/examples/custom-sanitizer/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/collections/Taint.qll | 2 +- python/ql/test/library-tests/taint/collections/TestStep.ql | 2 +- python/ql/test/library-tests/taint/collections/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/config/RockPaperScissors.ql | 2 +- python/ql/test/library-tests/taint/config/Simple.ql | 2 +- python/ql/test/library-tests/taint/config/TaintLib.qll | 2 +- python/ql/test/library-tests/taint/config/TaintedArgument.ql | 2 +- python/ql/test/library-tests/taint/config/TestNode.ql | 2 +- python/ql/test/library-tests/taint/config/TestSink.ql | 2 +- python/ql/test/library-tests/taint/config/TestSource.ql | 2 +- python/ql/test/library-tests/taint/config/TestStep.ql | 2 +- python/ql/test/library-tests/taint/example/Edges.ql | 2 +- python/ql/test/library-tests/taint/example/Nodes.ql | 2 +- python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll | 2 +- .../ql/test/library-tests/taint/flowpath_regression/Config.qll | 2 +- python/ql/test/library-tests/taint/general/ParamSource.ql | 2 +- python/ql/test/library-tests/taint/general/TaintLib.qll | 2 +- python/ql/test/library-tests/taint/general/TestSanitizers.ql | 2 +- python/ql/test/library-tests/taint/general/TestSink.ql | 2 +- python/ql/test/library-tests/taint/general/TestSource.ql | 2 +- python/ql/test/library-tests/taint/general/TestStep.ql | 2 +- python/ql/test/library-tests/taint/general/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/namedtuple/Taint.qll | 2 +- python/ql/test/library-tests/taint/namedtuple/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/strings/Taint.qll | 2 +- python/ql/test/library-tests/taint/strings/TestStep.ql | 2 +- python/ql/test/library-tests/taint/strings/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/unpacking/Taint.qll | 2 +- python/ql/test/library-tests/taint/unpacking/TestStep.ql | 2 +- python/ql/test/library-tests/taint/unpacking/TestTaint.ql | 2 +- python/ql/test/library-tests/web/stdlib/TestTaint.ql | 2 +- python/ql/test/query-tests/Security/CWE-327/TestNode.ql | 2 +- 89 files changed, 89 insertions(+), 89 deletions(-) diff --git a/python/ql/src/Security/CWE-022/TarSlip.ql b/python/ql/src/Security/CWE-022/TarSlip.ql index aedc47b92ec..5769bae409f 100644 --- a/python/ql/src/Security/CWE-022/TarSlip.ql +++ b/python/ql/src/Security/CWE-022/TarSlip.ql @@ -13,7 +13,7 @@ import python import semmle.python.security.Paths -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic /** A TaintKind to represent open tarfile objects. That is, the result of calling `tarfile.open(...)` */ diff --git a/python/ql/src/Security/CWE-312/CleartextLogging.ql b/python/ql/src/Security/CWE-312/CleartextLogging.ql index de71a56e3d3..d1c6ac94d4b 100644 --- a/python/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/python/ql/src/Security/CWE-312/CleartextLogging.ql @@ -14,7 +14,7 @@ import python import semmle.python.security.Paths -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.SensitiveData import semmle.python.security.ClearText diff --git a/python/ql/src/Security/CWE-312/CleartextStorage.ql b/python/ql/src/Security/CWE-312/CleartextStorage.ql index 99dc8f6626c..f1f898b00dd 100644 --- a/python/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/python/ql/src/Security/CWE-312/CleartextStorage.ql @@ -14,7 +14,7 @@ import python import semmle.python.security.Paths -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.SensitiveData import semmle.python.security.ClearText diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql index 4f79a3382b7..edc03fb5f36 100644 --- a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -13,7 +13,7 @@ import python import semmle.python.security.Paths -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.filters.Tests class HardcodedValue extends TaintKind { diff --git a/python/ql/src/Variables/Undefined.qll b/python/ql/src/Variables/Undefined.qll index 78e6438ec69..2c757733af4 100644 --- a/python/ql/src/Variables/Undefined.qll +++ b/python/ql/src/Variables/Undefined.qll @@ -1,6 +1,6 @@ import python import Loop -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking /** Marker for "uninitialized". */ class Uninitialized extends TaintKind { diff --git a/python/ql/src/semmle/python/dataflow/Configuration.qll b/python/ql/src/semmle/python/dataflow/Configuration.qll index 851578999a8..91a9971c97d 100644 --- a/python/ql/src/semmle/python/dataflow/Configuration.qll +++ b/python/ql/src/semmle/python/dataflow/Configuration.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private import semmle.python.objects.ObjectInternal private import semmle.python.dataflow.Implementation diff --git a/python/ql/src/semmle/python/dataflow/DataFlow.qll b/python/ql/src/semmle/python/dataflow/DataFlow.qll index 4684441563c..42eda521bc8 100644 --- a/python/ql/src/semmle/python/dataflow/DataFlow.qll +++ b/python/ql/src/semmle/python/dataflow/DataFlow.qll @@ -1 +1 @@ -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking diff --git a/python/ql/src/semmle/python/dataflow/Files.qll b/python/ql/src/semmle/python/dataflow/Files.qll index 467a8bec29e..a0cd1753f9d 100644 --- a/python/ql/src/semmle/python/dataflow/Files.qll +++ b/python/ql/src/semmle/python/dataflow/Files.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking class OpenFile extends TaintKind { OpenFile() { this = "file.open" } diff --git a/python/ql/src/semmle/python/dataflow/Legacy.qll b/python/ql/src/semmle/python/dataflow/Legacy.qll index 61961921514..ffdb7aee869 100644 --- a/python/ql/src/semmle/python/dataflow/Legacy.qll +++ b/python/ql/src/semmle/python/dataflow/Legacy.qll @@ -1,4 +1,4 @@ -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private import semmle.python.objects.ObjectInternal import semmle.python.dataflow.Implementation diff --git a/python/ql/src/semmle/python/security/ClearText.qll b/python/ql/src/semmle/python/security/ClearText.qll index d08d2b03883..a26e33218dd 100644 --- a/python/ql/src/semmle/python/security/ClearText.qll +++ b/python/ql/src/semmle/python/security/ClearText.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.SensitiveData import semmle.python.dataflow.Files import semmle.python.web.Http diff --git a/python/ql/src/semmle/python/security/Crypto.qll b/python/ql/src/semmle/python/security/Crypto.qll index 06244851018..98ec8ecb2f1 100644 --- a/python/ql/src/semmle/python/security/Crypto.qll +++ b/python/ql/src/semmle/python/security/Crypto.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private import semmle.python.security.SensitiveData private import semmle.crypto.Crypto as CryptoLib diff --git a/python/ql/src/semmle/python/security/Exceptions.qll b/python/ql/src/semmle/python/security/Exceptions.qll index 5344808caac..4288761c565 100644 --- a/python/ql/src/semmle/python/security/Exceptions.qll +++ b/python/ql/src/semmle/python/security/Exceptions.qll @@ -4,7 +4,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic private Value traceback_function(string name) { result = Module::named("traceback").attr(name) } diff --git a/python/ql/src/semmle/python/security/SQL.qll b/python/ql/src/semmle/python/security/SQL.qll index a09d74134e6..4d2ef6218cc 100644 --- a/python/ql/src/semmle/python/security/SQL.qll +++ b/python/ql/src/semmle/python/security/SQL.qll @@ -1,4 +1,4 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking abstract class SqlInjectionSink extends TaintSink { } diff --git a/python/ql/src/semmle/python/security/SensitiveData.qll b/python/ql/src/semmle/python/security/SensitiveData.qll index 6e0b44d3c33..18e52423d19 100644 --- a/python/ql/src/semmle/python/security/SensitiveData.qll +++ b/python/ql/src/semmle/python/security/SensitiveData.qll @@ -10,7 +10,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.HttpRequest /** diff --git a/python/ql/src/semmle/python/security/injection/Command.qll b/python/ql/src/semmle/python/security/injection/Command.qll index 1a6c2508719..3084f2c8cf4 100644 --- a/python/ql/src/semmle/python/security/injection/Command.qll +++ b/python/ql/src/semmle/python/security/injection/Command.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted /** Abstract taint sink that is potentially vulnerable to malicious shell commands. */ diff --git a/python/ql/src/semmle/python/security/injection/Deserialization.qll b/python/ql/src/semmle/python/security/injection/Deserialization.qll index 14bf9d2233d..1f73ede22f2 100644 --- a/python/ql/src/semmle/python/security/injection/Deserialization.qll +++ b/python/ql/src/semmle/python/security/injection/Deserialization.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking /** `pickle.loads(untrusted)` vulnerability. */ abstract class DeserializationSink extends TaintSink { diff --git a/python/ql/src/semmle/python/security/injection/Exec.qll b/python/ql/src/semmle/python/security/injection/Exec.qll index 59ed181023a..462847e7d3e 100644 --- a/python/ql/src/semmle/python/security/injection/Exec.qll +++ b/python/ql/src/semmle/python/security/injection/Exec.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted /** diff --git a/python/ql/src/semmle/python/security/injection/Marshal.qll b/python/ql/src/semmle/python/security/injection/Marshal.qll index 274392c8b4f..7ae77e597a5 100644 --- a/python/ql/src/semmle/python/security/injection/Marshal.qll +++ b/python/ql/src/semmle/python/security/injection/Marshal.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Deserialization diff --git a/python/ql/src/semmle/python/security/injection/Path.qll b/python/ql/src/semmle/python/security/injection/Path.qll index 02c0eb12697..e871d11cf2b 100644 --- a/python/ql/src/semmle/python/security/injection/Path.qll +++ b/python/ql/src/semmle/python/security/injection/Path.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted /** diff --git a/python/ql/src/semmle/python/security/injection/Pickle.qll b/python/ql/src/semmle/python/security/injection/Pickle.qll index 2d56bc25f8e..1135587df50 100644 --- a/python/ql/src/semmle/python/security/injection/Pickle.qll +++ b/python/ql/src/semmle/python/security/injection/Pickle.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Deserialization diff --git a/python/ql/src/semmle/python/security/injection/Sql.qll b/python/ql/src/semmle/python/security/injection/Sql.qll index 38c0eaec7d7..7fc9515c08b 100644 --- a/python/ql/src/semmle/python/security/injection/Sql.qll +++ b/python/ql/src/semmle/python/security/injection/Sql.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.SQL diff --git a/python/ql/src/semmle/python/security/injection/Xml.qll b/python/ql/src/semmle/python/security/injection/Xml.qll index 080df3067d0..3a4e6ebc552 100644 --- a/python/ql/src/semmle/python/security/injection/Xml.qll +++ b/python/ql/src/semmle/python/security/injection/Xml.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Deserialization diff --git a/python/ql/src/semmle/python/security/injection/Yaml.qll b/python/ql/src/semmle/python/security/injection/Yaml.qll index 3b0156b2812..0799d9b9160 100644 --- a/python/ql/src/semmle/python/security/injection/Yaml.qll +++ b/python/ql/src/semmle/python/security/injection/Yaml.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Deserialization diff --git a/python/ql/src/semmle/python/security/strings/Basic.qll b/python/ql/src/semmle/python/security/strings/Basic.qll index 1eed2bb327a..cb2178addde 100755 --- a/python/ql/src/semmle/python/security/strings/Basic.qll +++ b/python/ql/src/semmle/python/security/strings/Basic.qll @@ -1,6 +1,6 @@ import python private import Common -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking /** An extensible kind of taint representing any kind of string. */ abstract class StringKind extends TaintKind { diff --git a/python/ql/src/semmle/python/web/bottle/Redirect.qll b/python/ql/src/semmle/python/web/bottle/Redirect.qll index 187839f30e8..be4c552fea2 100644 --- a/python/ql/src/semmle/python/web/bottle/Redirect.qll +++ b/python/ql/src/semmle/python/web/bottle/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.bottle.General diff --git a/python/ql/src/semmle/python/web/bottle/Request.qll b/python/ql/src/semmle/python/web/bottle/Request.qll index 585336ac65a..10d2b223863 100644 --- a/python/ql/src/semmle/python/web/bottle/Request.qll +++ b/python/ql/src/semmle/python/web/bottle/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.bottle.General diff --git a/python/ql/src/semmle/python/web/bottle/Response.qll b/python/ql/src/semmle/python/web/bottle/Response.qll index 7dd53377a8c..dede231c27d 100644 --- a/python/ql/src/semmle/python/web/bottle/Response.qll +++ b/python/ql/src/semmle/python/web/bottle/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.bottle.General diff --git a/python/ql/src/semmle/python/web/cherrypy/Request.qll b/python/ql/src/semmle/python/web/cherrypy/Request.qll index 2440a2710f6..309d51f5539 100644 --- a/python/ql/src/semmle/python/web/cherrypy/Request.qll +++ b/python/ql/src/semmle/python/web/cherrypy/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http import semmle.python.web.cherrypy.General diff --git a/python/ql/src/semmle/python/web/cherrypy/Response.qll b/python/ql/src/semmle/python/web/cherrypy/Response.qll index 7702b8ce500..3ed1d0d9b57 100644 --- a/python/ql/src/semmle/python/web/cherrypy/Response.qll +++ b/python/ql/src/semmle/python/web/cherrypy/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.cherrypy.General diff --git a/python/ql/src/semmle/python/web/django/Model.qll b/python/ql/src/semmle/python/web/django/Model.qll index b8f47b64bdf..f8a61bda10e 100644 --- a/python/ql/src/semmle/python/web/django/Model.qll +++ b/python/ql/src/semmle/python/web/django/Model.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http import semmle.python.security.injection.Sql diff --git a/python/ql/src/semmle/python/web/django/Redirect.qll b/python/ql/src/semmle/python/web/django/Redirect.qll index a550088eaf6..67342517a99 100644 --- a/python/ql/src/semmle/python/web/django/Redirect.qll +++ b/python/ql/src/semmle/python/web/django/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic private import semmle.python.web.django.Shared private import semmle.python.web.Http diff --git a/python/ql/src/semmle/python/web/django/Request.qll b/python/ql/src/semmle/python/web/django/Request.qll index e054407fcee..503264c2817 100644 --- a/python/ql/src/semmle/python/web/django/Request.qll +++ b/python/ql/src/semmle/python/web/django/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.web.django.General diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index dc6a3634440..35d8cd63553 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic private import semmle.python.web.django.Shared private import semmle.python.web.Http diff --git a/python/ql/src/semmle/python/web/falcon/Request.qll b/python/ql/src/semmle/python/web/falcon/Request.qll index 13f3fa4c441..66707b01d0c 100644 --- a/python/ql/src/semmle/python/web/falcon/Request.qll +++ b/python/ql/src/semmle/python/web/falcon/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.web.falcon.General import semmle.python.security.strings.External diff --git a/python/ql/src/semmle/python/web/falcon/Response.qll b/python/ql/src/semmle/python/web/falcon/Response.qll index ab7798cc2cb..c66a6315ce5 100644 --- a/python/ql/src/semmle/python/web/falcon/Response.qll +++ b/python/ql/src/semmle/python/web/falcon/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.web.falcon.General import semmle.python.security.strings.External diff --git a/python/ql/src/semmle/python/web/flask/Redirect.qll b/python/ql/src/semmle/python/web/flask/Redirect.qll index f01f13f6ef7..4c4e289c605 100644 --- a/python/ql/src/semmle/python/web/flask/Redirect.qll +++ b/python/ql/src/semmle/python/web/flask/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.flask.General diff --git a/python/ql/src/semmle/python/web/flask/Request.qll b/python/ql/src/semmle/python/web/flask/Request.qll index 7e2650a1ca0..5548e409c32 100644 --- a/python/ql/src/semmle/python/web/flask/Request.qll +++ b/python/ql/src/semmle/python/web/flask/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.web.flask.General diff --git a/python/ql/src/semmle/python/web/flask/Response.qll b/python/ql/src/semmle/python/web/flask/Response.qll index 0828c180e9a..e070f19b1f6 100644 --- a/python/ql/src/semmle/python/web/flask/Response.qll +++ b/python/ql/src/semmle/python/web/flask/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.flask.General diff --git a/python/ql/src/semmle/python/web/pyramid/Redirect.qll b/python/ql/src/semmle/python/web/pyramid/Redirect.qll index 8c7e57a4285..2ab68b40621 100644 --- a/python/ql/src/semmle/python/web/pyramid/Redirect.qll +++ b/python/ql/src/semmle/python/web/pyramid/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http diff --git a/python/ql/src/semmle/python/web/pyramid/Request.qll b/python/ql/src/semmle/python/web/pyramid/Request.qll index dc5be31e68a..f3422b682d6 100644 --- a/python/ql/src/semmle/python/web/pyramid/Request.qll +++ b/python/ql/src/semmle/python/web/pyramid/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http private import semmle.python.web.webob.Request private import semmle.python.web.pyramid.View diff --git a/python/ql/src/semmle/python/web/pyramid/Response.qll b/python/ql/src/semmle/python/web/pyramid/Response.qll index 37dc4be783c..c51a437350d 100644 --- a/python/ql/src/semmle/python/web/pyramid/Response.qll +++ b/python/ql/src/semmle/python/web/pyramid/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http private import semmle.python.web.pyramid.View diff --git a/python/ql/src/semmle/python/web/stdlib/Request.qll b/python/ql/src/semmle/python/web/stdlib/Request.qll index ce150371279..459a5091389 100644 --- a/python/ql/src/semmle/python/web/stdlib/Request.qll +++ b/python/ql/src/semmle/python/web/stdlib/Request.qll @@ -4,7 +4,7 @@ * (or subclasses) and form parsing using `cgi.FieldStorage`. */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http /** Source of BaseHTTPRequestHandler instances. */ diff --git a/python/ql/src/semmle/python/web/stdlib/Response.qll b/python/ql/src/semmle/python/web/stdlib/Response.qll index fb056d49525..58949e0a6d9 100644 --- a/python/ql/src/semmle/python/web/stdlib/Response.qll +++ b/python/ql/src/semmle/python/web/stdlib/Response.qll @@ -3,7 +3,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http private predicate is_wfile(AttrNode wfile) { diff --git a/python/ql/src/semmle/python/web/tornado/Redirect.qll b/python/ql/src/semmle/python/web/tornado/Redirect.qll index 2d2c39907eb..f846f113816 100644 --- a/python/ql/src/semmle/python/web/tornado/Redirect.qll +++ b/python/ql/src/semmle/python/web/tornado/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http import Tornado diff --git a/python/ql/src/semmle/python/web/tornado/Request.qll b/python/ql/src/semmle/python/web/tornado/Request.qll index 66c77d4f269..cfb7bfa7b04 100644 --- a/python/ql/src/semmle/python/web/tornado/Request.qll +++ b/python/ql/src/semmle/python/web/tornado/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import Tornado diff --git a/python/ql/src/semmle/python/web/tornado/Response.qll b/python/ql/src/semmle/python/web/tornado/Response.qll index 2c2da1a4c70..b9213ac8446 100644 --- a/python/ql/src/semmle/python/web/tornado/Response.qll +++ b/python/ql/src/semmle/python/web/tornado/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic private import semmle.python.web.Http import Tornado diff --git a/python/ql/src/semmle/python/web/tornado/Tornado.qll b/python/ql/src/semmle/python/web/tornado/Tornado.qll index 10a5c5be962..d9f6ab823b9 100644 --- a/python/ql/src/semmle/python/web/tornado/Tornado.qll +++ b/python/ql/src/semmle/python/web/tornado/Tornado.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http private ClassValue theTornadoRequestHandlerClass() { diff --git a/python/ql/src/semmle/python/web/turbogears/Response.qll b/python/ql/src/semmle/python/web/turbogears/Response.qll index cab083bf8b7..307806dc485 100644 --- a/python/ql/src/semmle/python/web/turbogears/Response.qll +++ b/python/ql/src/semmle/python/web/turbogears/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http import TurboGears diff --git a/python/ql/src/semmle/python/web/turbogears/TurboGears.qll b/python/ql/src/semmle/python/web/turbogears/TurboGears.qll index 1cef2f51c84..547a6c0e505 100644 --- a/python/ql/src/semmle/python/web/turbogears/TurboGears.qll +++ b/python/ql/src/semmle/python/web/turbogears/TurboGears.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private ClassValue theTurboGearsControllerClass() { result = Value::named("tg.TGController") } diff --git a/python/ql/src/semmle/python/web/twisted/Request.qll b/python/ql/src/semmle/python/web/twisted/Request.qll index 969392d0eef..0be6fc78f2c 100644 --- a/python/ql/src/semmle/python/web/twisted/Request.qll +++ b/python/ql/src/semmle/python/web/twisted/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import Twisted diff --git a/python/ql/src/semmle/python/web/twisted/Response.qll b/python/ql/src/semmle/python/web/twisted/Response.qll index b7f67ff6b20..be32ba08188 100644 --- a/python/ql/src/semmle/python/web/twisted/Response.qll +++ b/python/ql/src/semmle/python/web/twisted/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.security.strings.Basic import Twisted diff --git a/python/ql/src/semmle/python/web/twisted/Twisted.qll b/python/ql/src/semmle/python/web/twisted/Twisted.qll index e3b0ab0f9be..9ecd12b9620 100644 --- a/python/ql/src/semmle/python/web/twisted/Twisted.qll +++ b/python/ql/src/semmle/python/web/twisted/Twisted.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private ClassValue theTwistedHttpRequestClass() { result = Value::named("twisted.web.http.Request") diff --git a/python/ql/src/semmle/python/web/webob/Request.qll b/python/ql/src/semmle/python/web/webob/Request.qll index 70fa311f6b0..4d6e98bb2e9 100644 --- a/python/ql/src/semmle/python/web/webob/Request.qll +++ b/python/ql/src/semmle/python/web/webob/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http abstract class BaseWebobRequest extends TaintKind { diff --git a/python/ql/test/3/library-tests/taint/unpacking/Taint.qll b/python/ql/test/3/library-tests/taint/unpacking/Taint.qll index b97f65225f2..21e16aabac5 100644 --- a/python/ql/test/3/library-tests/taint/unpacking/Taint.qll +++ b/python/ql/test/3/library-tests/taint/unpacking/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql b/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql +++ b/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll b/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll index 9b2216dbcd9..64cbacae2a6 100644 --- a/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll +++ b/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql b/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql index 4df37b9cdfa..571672cb312 100644 --- a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql +++ b/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from diff --git a/python/ql/test/library-tests/taint/collections/Taint.qll b/python/ql/test/library-tests/taint/collections/Taint.qll index b97f65225f2..21e16aabac5 100644 --- a/python/ql/test/library-tests/taint/collections/Taint.qll +++ b/python/ql/test/library-tests/taint/collections/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/library-tests/taint/collections/TestStep.ql b/python/ql/test/library-tests/taint/collections/TestStep.ql index e7c014f2eb2..7e42b878e74 100644 --- a/python/ql/test/library-tests/taint/collections/TestStep.ql +++ b/python/ql/test/library-tests/taint/collections/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from TaintedNode n, TaintedNode s diff --git a/python/ql/test/library-tests/taint/collections/TestTaint.ql b/python/ql/test/library-tests/taint/collections/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/library-tests/taint/collections/TestTaint.ql +++ b/python/ql/test/library-tests/taint/collections/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/taint/config/RockPaperScissors.ql b/python/ql/test/library-tests/taint/config/RockPaperScissors.ql index 311039a6553..abcc862f418 100644 --- a/python/ql/test/library-tests/taint/config/RockPaperScissors.ql +++ b/python/ql/test/library-tests/taint/config/RockPaperScissors.ql @@ -3,7 +3,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib import semmle.python.security.Paths diff --git a/python/ql/test/library-tests/taint/config/Simple.ql b/python/ql/test/library-tests/taint/config/Simple.ql index 76e8c261048..b3593354f5e 100644 --- a/python/ql/test/library-tests/taint/config/Simple.ql +++ b/python/ql/test/library-tests/taint/config/Simple.ql @@ -3,7 +3,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib import semmle.python.security.Paths diff --git a/python/ql/test/library-tests/taint/config/TaintLib.qll b/python/ql/test/library-tests/taint/config/TaintLib.qll index 670a9515c33..52e7c71858b 100644 --- a/python/ql/test/library-tests/taint/config/TaintLib.qll +++ b/python/ql/test/library-tests/taint/config/TaintLib.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking class SimpleTest extends TaintKind { SimpleTest() { this = "simple.test" } diff --git a/python/ql/test/library-tests/taint/config/TaintedArgument.ql b/python/ql/test/library-tests/taint/config/TaintedArgument.ql index ca351d878a5..0663fce65e1 100644 --- a/python/ql/test/library-tests/taint/config/TaintedArgument.ql +++ b/python/ql/test/library-tests/taint/config/TaintedArgument.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib import semmle.python.dataflow.Implementation diff --git a/python/ql/test/library-tests/taint/config/TestNode.ql b/python/ql/test/library-tests/taint/config/TestNode.ql index 02a4dd278c3..688002f3eb0 100644 --- a/python/ql/test/library-tests/taint/config/TestNode.ql +++ b/python/ql/test/library-tests/taint/config/TestNode.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.dataflow.Implementation import TaintLib diff --git a/python/ql/test/library-tests/taint/config/TestSink.ql b/python/ql/test/library-tests/taint/config/TestSink.ql index 4df3f48b939..0e191e16e84 100644 --- a/python/ql/test/library-tests/taint/config/TestSink.ql +++ b/python/ql/test/library-tests/taint/config/TestSink.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TestConfig config, DataFlow::Node sink, TaintKind kind diff --git a/python/ql/test/library-tests/taint/config/TestSource.ql b/python/ql/test/library-tests/taint/config/TestSource.ql index 191583becb7..45c5dd3ac57 100644 --- a/python/ql/test/library-tests/taint/config/TestSource.ql +++ b/python/ql/test/library-tests/taint/config/TestSource.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TestConfig config, DataFlow::Node source, TaintKind kind diff --git a/python/ql/test/library-tests/taint/config/TestStep.ql b/python/ql/test/library-tests/taint/config/TestStep.ql index f16f2e36bb8..2773321d300 100644 --- a/python/ql/test/library-tests/taint/config/TestStep.ql +++ b/python/ql/test/library-tests/taint/config/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib import semmle.python.dataflow.Implementation diff --git a/python/ql/test/library-tests/taint/example/Edges.ql b/python/ql/test/library-tests/taint/example/Edges.ql index 0674f3a073c..063f4883316 100644 --- a/python/ql/test/library-tests/taint/example/Edges.ql +++ b/python/ql/test/library-tests/taint/example/Edges.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.dataflow.Implementation import DilbertConfig diff --git a/python/ql/test/library-tests/taint/example/Nodes.ql b/python/ql/test/library-tests/taint/example/Nodes.ql index 0a5ff02c2a3..c7544767bba 100644 --- a/python/ql/test/library-tests/taint/example/Nodes.ql +++ b/python/ql/test/library-tests/taint/example/Nodes.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.dataflow.Implementation import DilbertConfig diff --git a/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll b/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll index bc0534df455..19e369412ac 100644 --- a/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll +++ b/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking class SimpleTest extends TaintKind { SimpleTest() { this = "simple.test" } diff --git a/python/ql/test/library-tests/taint/flowpath_regression/Config.qll b/python/ql/test/library-tests/taint/flowpath_regression/Config.qll index 0e3d5a71f8f..446365b2d12 100644 --- a/python/ql/test/library-tests/taint/flowpath_regression/Config.qll +++ b/python/ql/test/library-tests/taint/flowpath_regression/Config.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class FooSource extends TaintSource { diff --git a/python/ql/test/library-tests/taint/general/ParamSource.ql b/python/ql/test/library-tests/taint/general/ParamSource.ql index f0956d0333d..192de466882 100644 --- a/python/ql/test/library-tests/taint/general/ParamSource.ql +++ b/python/ql/test/library-tests/taint/general/ParamSource.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking /* Standard library sink */ import semmle.python.security.injection.Command diff --git a/python/ql/test/library-tests/taint/general/TaintLib.qll b/python/ql/test/library-tests/taint/general/TaintLib.qll index 9e4cbc31a89..d0e8b9902ec 100644 --- a/python/ql/test/library-tests/taint/general/TaintLib.qll +++ b/python/ql/test/library-tests/taint/general/TaintLib.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking class SimpleTest extends TaintKind { SimpleTest() { this = "simple.test" } diff --git a/python/ql/test/library-tests/taint/general/TestSanitizers.ql b/python/ql/test/library-tests/taint/general/TestSanitizers.ql index cee31378f7d..97c48dfa8e5 100644 --- a/python/ql/test/library-tests/taint/general/TestSanitizers.ql +++ b/python/ql/test/library-tests/taint/general/TestSanitizers.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from Sanitizer s, TaintKind taint, PyEdgeRefinement test diff --git a/python/ql/test/library-tests/taint/general/TestSink.ql b/python/ql/test/library-tests/taint/general/TestSink.ql index 422527fbee2..2405ee3af06 100644 --- a/python/ql/test/library-tests/taint/general/TestSink.ql +++ b/python/ql/test/library-tests/taint/general/TestSink.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TaintSource src, TaintSink sink, TaintKind srckind, TaintKind sinkkind diff --git a/python/ql/test/library-tests/taint/general/TestSource.ql b/python/ql/test/library-tests/taint/general/TestSource.ql index d71bab289e0..4a06025a1f0 100644 --- a/python/ql/test/library-tests/taint/general/TestSource.ql +++ b/python/ql/test/library-tests/taint/general/TestSource.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TaintSource src, TaintKind kind diff --git a/python/ql/test/library-tests/taint/general/TestStep.ql b/python/ql/test/library-tests/taint/general/TestStep.ql index c6de9cad361..5274cd0af44 100644 --- a/python/ql/test/library-tests/taint/general/TestStep.ql +++ b/python/ql/test/library-tests/taint/general/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TaintedNode n, TaintedNode s diff --git a/python/ql/test/library-tests/taint/general/TestTaint.ql b/python/ql/test/library-tests/taint/general/TestTaint.ql index 904cbbbded9..7c513d7b52c 100644 --- a/python/ql/test/library-tests/taint/general/TestTaint.ql +++ b/python/ql/test/library-tests/taint/general/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/taint/namedtuple/Taint.qll b/python/ql/test/library-tests/taint/namedtuple/Taint.qll index 580ed13f8f1..bb40491c202 100644 --- a/python/ql/test/library-tests/taint/namedtuple/Taint.qll +++ b/python/ql/test/library-tests/taint/namedtuple/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql b/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql +++ b/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/taint/strings/Taint.qll b/python/ql/test/library-tests/taint/strings/Taint.qll index 62dba92a45d..3840df662ef 100644 --- a/python/ql/test/library-tests/taint/strings/Taint.qll +++ b/python/ql/test/library-tests/taint/strings/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.Exceptions diff --git a/python/ql/test/library-tests/taint/strings/TestStep.ql b/python/ql/test/library-tests/taint/strings/TestStep.ql index e7c014f2eb2..7e42b878e74 100644 --- a/python/ql/test/library-tests/taint/strings/TestStep.ql +++ b/python/ql/test/library-tests/taint/strings/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from TaintedNode n, TaintedNode s diff --git a/python/ql/test/library-tests/taint/strings/TestTaint.ql b/python/ql/test/library-tests/taint/strings/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/library-tests/taint/strings/TestTaint.ql +++ b/python/ql/test/library-tests/taint/strings/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/taint/unpacking/Taint.qll b/python/ql/test/library-tests/taint/unpacking/Taint.qll index b97f65225f2..21e16aabac5 100644 --- a/python/ql/test/library-tests/taint/unpacking/Taint.qll +++ b/python/ql/test/library-tests/taint/unpacking/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/library-tests/taint/unpacking/TestStep.ql b/python/ql/test/library-tests/taint/unpacking/TestStep.ql index e7c014f2eb2..7e42b878e74 100644 --- a/python/ql/test/library-tests/taint/unpacking/TestStep.ql +++ b/python/ql/test/library-tests/taint/unpacking/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from TaintedNode n, TaintedNode s diff --git a/python/ql/test/library-tests/taint/unpacking/TestTaint.ql b/python/ql/test/library-tests/taint/unpacking/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/library-tests/taint/unpacking/TestTaint.ql +++ b/python/ql/test/library-tests/taint/unpacking/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/web/stdlib/TestTaint.ql b/python/ql/test/library-tests/web/stdlib/TestTaint.ql index 87133eda869..1ac84c3d290 100644 --- a/python/ql/test/library-tests/web/stdlib/TestTaint.ql +++ b/python/ql/test/library-tests/web/stdlib/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.HttpRequest import semmle.python.security.strings.Untrusted diff --git a/python/ql/test/query-tests/Security/CWE-327/TestNode.ql b/python/ql/test/query-tests/Security/CWE-327/TestNode.ql index 50305f21a2e..420ed8bb38e 100644 --- a/python/ql/test/query-tests/Security/CWE-327/TestNode.ql +++ b/python/ql/test/query-tests/Security/CWE-327/TestNode.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import python import semmle.python.security.SensitiveData import semmle.python.security.Crypto From 2a654af983a46ca33ce41cd552edf9982c0f2973 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 25 May 2020 08:24:38 -0400 Subject: [PATCH 074/111] Correct the select statement in the query --- java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index b3879ac881c..46541d28698 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -94,5 +94,4 @@ class HostVerificationMethodAccess extends MethodAccess { from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma where hma.getQualifier() = uma and uma.getMethod() = um -select "Potentially improper URL verification at ", hma, "having $@ ", hma.getFile(), - hma.getArgument(0), "user-provided value" +select hma, "Method has potentially $@ ", hma.getArgument(0), "improper URL verification" From b1edc1d255b0058fc0fb7261dbab529c0720c89a Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 25 May 2020 14:38:46 +0200 Subject: [PATCH 075/111] C++: Only give alert when no def fits arg count The `cpp/too-few-arguments` query produced alerts for ambiguous databases where a function had multiple possible declarations, with some declarations having the right number of parameters and some having too many. With this change, the query errs on the side of caution in those cases and does not produce an alert. This fixes false positives on racket/racket. The new `hasDefiniteNumberOfParameters` is exactly the negation of the old `hasZeroParamDecl`. --- .../TooFewArguments.qll | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll index b65d256f45c..1e039e5d861 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll @@ -6,10 +6,23 @@ import cpp +/** + * Holds if `fde` has a parameter declaration that's clear on the minimum + * number of parameters. This is essentially true for everything except + * `()`-declarations. + */ +private predicate hasDefiniteNumberOfParameters(FunctionDeclarationEntry fde) { + fde.hasVoidParamList() + or + fde.getNumberOfParameters() > 0 + or + fde.isDefinition() +} + // True if function was ()-declared, but not (void)-declared or K&R-defined private predicate hasZeroParamDecl(Function f) { exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition() + not hasDefiniteNumberOfParameters(fde) ) } @@ -24,11 +37,18 @@ predicate tooFewArguments(FunctionCall fc, Function f) { f = fc.getTarget() and not f.isVarargs() and not f instanceof BuiltInFunction and + // This query should only have results on C (not C++) functions that have a + // `()` parameter list somewhere. If it has results on other functions, then + // it's probably because the extractor only saw a partial compilation. hasZeroParamDecl(f) and isCompiledAsC(f.getFile()) and - // There is an explicit declaration of the function whose parameter count is larger - // than the number of call arguments - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + // Produce an alert when all declarations that are authoritative on the + // parameter count specify a parameter count larger than the number of call + // arguments. + forex(FunctionDeclarationEntry fde | + fde = f.getADeclarationEntry() and + hasDefiniteNumberOfParameters(fde) + | fde.getNumberOfParameters() > fc.getNumberOfArguments() ) } From b4c32a00d847d098f47f1f3bfbb85b1814c0bca6 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 25 May 2020 14:44:08 +0200 Subject: [PATCH 076/111] C++: Fix up QLDoc in TooFewArguments.qll --- .../Likely Bugs/Underspecified Functions/TooFewArguments.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll index 1e039e5d861..6f3f4d43e9a 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll @@ -19,20 +19,21 @@ private predicate hasDefiniteNumberOfParameters(FunctionDeclarationEntry fde) { fde.isDefinition() } -// True if function was ()-declared, but not (void)-declared or K&R-defined +/* Holds if function was ()-declared, but not (void)-declared or K&R-defined. */ private predicate hasZeroParamDecl(Function f) { exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not hasDefiniteNumberOfParameters(fde) ) } -// True if this file (or header) was compiled as a C file +/* Holds if this file (or header) was compiled as a C file. */ private predicate isCompiledAsC(File f) { f.compiledAsC() or exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f) } +/** Holds if `fc` is a call to `f` with too few arguments. */ predicate tooFewArguments(FunctionCall fc, Function f) { f = fc.getTarget() and not f.isVarargs() and From 6fc9e1d84c0b5fbf8c0f516c23eec4924b489eee Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 20 May 2020 14:44:43 +0200 Subject: [PATCH 077/111] C++/JavaScript: Improve CodeDuplication.qll QLDoc I took most of the docs from the corresponding predicates in JavaScript's `CodeDuplication.qll`. Where JavaScript had a corresponding predicate but didn't have QLDoc, I added new QLDoc to both. --- cpp/ql/src/external/CodeDuplication.qll | 65 ++++++++++++++++++- .../ql/src/external/CodeDuplication.qll | 14 ++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/external/CodeDuplication.qll b/cpp/ql/src/external/CodeDuplication.qll index 2f4fd0d05da..4548e0be85e 100644 --- a/cpp/ql/src/external/CodeDuplication.qll +++ b/cpp/ql/src/external/CodeDuplication.qll @@ -1,3 +1,5 @@ +/** Provides classes for detecting duplicate or similar code. */ + import cpp private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") } @@ -8,9 +10,12 @@ private predicate tokenLocation(string path, int sl, int sc, int ec, int el, Cop tokens(copy, index, sl, sc, ec, el) } +/** A token block used for detection of duplicate and similar code. */ class Copy extends @duplication_or_similarity { + /** Gets the index of the last token in this block. */ private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) } + /** Gets the index of the token in this block starting at the location `loc`, if any. */ int tokenStartingAt(Location loc) { exists(string filepath, int startline, int startcol | loc.hasLocationInfo(filepath, startline, startcol, _, _) and @@ -18,6 +23,7 @@ class Copy extends @duplication_or_similarity { ) } + /** Gets the index of the token in this block ending at the location `loc`, if any. */ int tokenEndingAt(Location loc) { exists(string filepath, int endline, int endcol | loc.hasLocationInfo(filepath, _, _, endline, endcol) and @@ -25,24 +31,38 @@ class Copy extends @duplication_or_similarity { ) } + /** Gets the line on which the first token in this block starts. */ int sourceStartLine() { tokens(this, 0, result, _, _, _) } + /** Gets the column on which the first token in this block starts. */ int sourceStartColumn() { tokens(this, 0, _, result, _, _) } + /** Gets the line on which the last token in this block ends. */ int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) } + /** Gets the column on which the last token in this block ends. */ int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) } + /** Gets the number of lines containing at least (part of) one token in this block. */ int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() } + /** Gets an opaque identifier for the equivalence class of this block. */ int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) } + /** Gets the source file in which this block appears. */ File sourceFile() { exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) | name.replaceAll("\\", "/") = relativePath(result) ) } + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { @@ -53,25 +73,30 @@ class Copy extends @duplication_or_similarity { endcolumn = sourceEndColumn() } + /** Gets a textual representation of this element. */ string toString() { none() } } +/** A block of duplicated code. */ class DuplicateBlock extends Copy, @duplication { override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." } } +/** A block of similar code. */ class SimilarBlock extends Copy, @similarity { override string toString() { result = "Similar code: " + sourceLines() + " almost duplicated lines." } } +/** Gets a function with a body and a location. */ FunctionDeclarationEntry sourceMethod() { result.isDefinition() and exists(result.getLocation()) and numlines(unresolveElement(result.getFunction()), _, _, _) } +/** Gets the number of member functions in `c` with a body and a location. */ int numberOfSourceMethods(Class c) { result = count(FunctionDeclarationEntry m | @@ -108,6 +133,10 @@ private predicate duplicateStatement( ) } +/** + * Holds if `m1` is a function with `total` lines, and `m2` is a function + * that has `duplicate` lines in common with `m1`. + */ predicate duplicateStatements( FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, int duplicate, int total ) { @@ -115,13 +144,16 @@ predicate duplicateStatements( total = strictcount(statementInMethod(m1)) } -/** - * Find pairs of methods are identical - */ +/** Holds if `m` and other are identical functions. */ predicate duplicateMethod(FunctionDeclarationEntry m, FunctionDeclarationEntry other) { exists(int total | duplicateStatements(m, other, total, total)) } +/** + * INTERNAL: do not use. + * + * Holds if `line` in `f` is similar to a line somewhere else. + */ predicate similarLines(File f, int line) { exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]) } @@ -152,6 +184,7 @@ private predicate similarLinesCoveredFiles(File f, File otherFile) { ) } +/** Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. */ predicate similarLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getMetrics().getNumberOfLines() | similarLinesCoveredFiles(f, otherFile) and @@ -166,6 +199,11 @@ predicate similarLinesCovered(File f, int coveredLines, File otherFile) { ) } +/** + * INTERNAL: do not use. + * + * Holds if `line` in `f` is duplicated by a line somewhere else. + */ predicate duplicateLines(File f, int line) { exists(DuplicateBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()] @@ -182,6 +220,7 @@ private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, F ) } +/** Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. */ predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getMetrics().getNumberOfLines() | exists(int coveredApprox | @@ -206,6 +245,7 @@ predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { ) } +/** Holds if most of `f` (`percent`%) is similar to `other`. */ predicate similarFiles(File f, File other, int percent) { exists(int covered, int total | similarLinesCovered(f, covered, other) and @@ -216,6 +256,7 @@ predicate similarFiles(File f, File other, int percent) { not duplicateFiles(f, other, _) } +/** Holds if most of `f` (`percent`%) is duplicated by `other`. */ predicate duplicateFiles(File f, File other, int percent) { exists(int covered, int total | duplicateLinesCovered(f, covered, other) and @@ -225,6 +266,10 @@ predicate duplicateFiles(File f, File other, int percent) { ) } +/** + * Holds if most member functions of `c` (`numDup` out of `total`) are + * duplicates of member functions in `other`. + */ predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) { numDup = strictcount(FunctionDeclarationEntry m1 | @@ -240,6 +285,11 @@ predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) (numDup * 100) / total > 80 } +/** + * Holds if most member functions of `c` are duplicates of member functions in + * `other`. Provides the human-readable `message` to describe the amount of + * duplication. + */ predicate mostlyDuplicateClass(Class c, Class other, string message) { exists(int numDup, int total | mostlyDuplicateClassBase(c, other, numDup, total) and @@ -264,12 +314,21 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) { ) } +/** Holds if `f` and `other` are similar or duplicates. */ predicate fileLevelDuplication(File f, File other) { similarFiles(f, other, _) or duplicateFiles(f, other, _) } +/** + * Holds if most member functions of `c` are duplicates of member functions in + * `other`. + */ predicate classLevelDuplication(Class c, Class other) { mostlyDuplicateClass(c, other, _) } +/** + * Holds if `line` in `f` should be allowed to be duplicated. This is the case + * for `#include` directives. + */ predicate whitelistedLineForDuplication(File f, int line) { exists(Include i | i.getFile() = f and i.getLocation().getStartLine() = line) } diff --git a/javascript/ql/src/external/CodeDuplication.qll b/javascript/ql/src/external/CodeDuplication.qll index d0f9d97776a..bd9a0481a8a 100644 --- a/javascript/ql/src/external/CodeDuplication.qll +++ b/javascript/ql/src/external/CodeDuplication.qll @@ -261,6 +261,11 @@ predicate similarContainers(StmtContainer sc, StmtContainer other, float percent ) } +/** + * INTERNAL: do not use. + * + * Holds if `line` in `f` is similar to a line somewhere else. + */ predicate similarLines(File f, int line) { exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]) } @@ -275,6 +280,7 @@ private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, Fil ) } +/** Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. */ pragma[noopt] private predicate similarLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getNumberOfLines() | @@ -296,6 +302,11 @@ private predicate similarLinesCovered(File f, int coveredLines, File otherFile) ) } +/** + * INTERNAL: do not use. + * + * Holds if `line` in `f` is duplicated by a line somewhere else. + */ predicate duplicateLines(File f, int line) { exists(DuplicateBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()] @@ -312,6 +323,7 @@ private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, F ) } +/** Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. */ pragma[noopt] private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getNumberOfLines() | @@ -333,6 +345,7 @@ private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile ) } +/** Holds if most of `f` (`percent`%) is similar to `other`. */ predicate similarFiles(File f, File other, int percent) { exists(int covered, int total | similarLinesCovered(f, covered, other) and @@ -343,6 +356,7 @@ predicate similarFiles(File f, File other, int percent) { not duplicateFiles(f, other, _) } +/** Holds if most of `f` (`percent`%) is duplicated by `other`. */ predicate duplicateFiles(File f, File other, int percent) { exists(int covered, int total | duplicateLinesCovered(f, covered, other) and From 357e14b2d2198444b49b3ae2988fb57f7801e0d4 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 20 May 2020 14:51:50 +0200 Subject: [PATCH 078/111] C++: QLDoc for legacy libraries in `external` dir These docs were taken from the corresponding files in JavaScript, and parameter names were changed to match. --- cpp/ql/src/external/DefectFilter.qll | 21 ++++++++++++++ cpp/ql/src/external/ExternalArtifact.qll | 35 +++++++++++++++++++----- cpp/ql/src/external/MetricFilter.qll | 29 ++++++++++++++++++++ 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/external/DefectFilter.qll b/cpp/ql/src/external/DefectFilter.qll index da63893b8bb..675f3b25faa 100644 --- a/cpp/ql/src/external/DefectFilter.qll +++ b/cpp/ql/src/external/DefectFilter.qll @@ -1,31 +1,52 @@ +/** Provides a class for working with defect query results stored in dashboard databases. */ + import cpp +/** + * Holds if `id` in the opaque identifier of a result reported by query `queryPath`, + * such that `message` is the associated message and the location of the result spans + * column `startcolumn` of line `startline` to column `endcolumn` of line `endline` + * in file `filepath`. + * + * For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ external predicate defectResults( int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, string message ); +/** + * A defect query result stored in a dashboard database. + */ class DefectResult extends int { DefectResult() { defectResults(this, _, _, _, _, _, _, _) } + /** Gets the path of the query that reported the result. */ string getQueryPath() { defectResults(this, result, _, _, _, _, _, _) } + /** Gets the file in which this query result was reported. */ File getFile() { exists(string path | defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path ) } + /** Gets the line on which the location of this query result starts. */ int getStartLine() { defectResults(this, _, _, result, _, _, _, _) } + /** Gets the column on which the location of this query result starts. */ int getStartColumn() { defectResults(this, _, _, _, result, _, _, _) } + /** Gets the line on which the location of this query result ends. */ int getEndLine() { defectResults(this, _, _, _, _, result, _, _) } + /** Gets the column on which the location of this query result ends. */ int getEndColumn() { defectResults(this, _, _, _, _, _, result, _) } + /** Gets the message associated with this query result. */ string getMessage() { defectResults(this, _, _, _, _, _, _, result) } + /** Gets the URL corresponding to the location of this query result. */ string getURL() { result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + diff --git a/cpp/ql/src/external/ExternalArtifact.qll b/cpp/ql/src/external/ExternalArtifact.qll index 94fa0d7e31a..abbc96a7b47 100644 --- a/cpp/ql/src/external/ExternalArtifact.qll +++ b/cpp/ql/src/external/ExternalArtifact.qll @@ -1,26 +1,45 @@ +/** + * Provides classes for working with external data. + */ + import cpp +/** + * An external data item. + */ class ExternalData extends @externalDataElement { + /** Gets the path of the file this data was loaded from. */ string getDataPath() { externalData(this, result, _, _) } + /** + * Gets the path of the file this data was loaded from, with its + * extension replaced by `.ql`. + */ string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } + /** Gets the number of fields in this data item. */ int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) } - string getField(int index) { externalData(this, _, index, result) } + /** Gets the value of the `i`th field of this data item. */ + string getField(int i) { externalData(this, _, i, result) } - int getFieldAsInt(int index) { result = getField(index).toInt() } + /** Gets the integer value of the `i`th field of this data item. */ + int getFieldAsInt(int i) { result = getField(i).toInt() } - float getFieldAsFloat(int index) { result = getField(index).toFloat() } + /** Gets the floating-point value of the `i`th field of this data item. */ + float getFieldAsFloat(int i) { result = getField(i).toFloat() } - date getFieldAsDate(int index) { result = getField(index).toDate() } + /** Gets the value of the `i`th field of this data item, interpreted as a date. */ + date getFieldAsDate(int i) { result = getField(i).toDate() } + /** Gets a textual representation of this data item. */ string toString() { result = getQueryPath() + ": " + buildTupleString(0) } - private string buildTupleString(int start) { - start = getNumFields() - 1 and result = getField(start) + /** Gets a textual representation of this data item, starting with the `n`th field. */ + private string buildTupleString(int n) { + n = getNumFields() - 1 and result = getField(n) or - start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1) + n < getNumFields() - 1 and result = getField(n) + "," + buildTupleString(n + 1) } } @@ -33,7 +52,9 @@ class DefectExternalData extends ExternalData { this.getNumFields() = 2 } + /** Gets the URL associated with this data item. */ string getURL() { result = getField(0) } + /** Gets the message associated with this data item. */ string getMessage() { result = getField(1) } } diff --git a/cpp/ql/src/external/MetricFilter.qll b/cpp/ql/src/external/MetricFilter.qll index b159b4cad5c..dd9cece78ce 100644 --- a/cpp/ql/src/external/MetricFilter.qll +++ b/cpp/ql/src/external/MetricFilter.qll @@ -1,31 +1,58 @@ +/** Provides a class for working with metric query results stored in dashboard databases. */ + import cpp +/** + * Holds if `id` in the opaque identifier of a result reported by query `queryPath`, + * such that `value` is the reported metric value and the location of the result spans + * column `startcolumn` of line `startline` to column `endcolumn` of line `endline` + * in file `filepath`. + * + * For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ external predicate metricResults( int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, float value ); +/** + * A metric query result stored in a dashboard database. + */ class MetricResult extends int { MetricResult() { metricResults(this, _, _, _, _, _, _, _) } + /** Gets the path of the query that reported the result. */ string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) } + /** Gets the file in which this query result was reported. */ File getFile() { exists(string path | metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path ) } + /** Gets the line on which the location of this query result starts. */ int getStartLine() { metricResults(this, _, _, result, _, _, _, _) } + /** Gets the column on which the location of this query result starts. */ int getStartColumn() { metricResults(this, _, _, _, result, _, _, _) } + /** Gets the line on which the location of this query result ends. */ int getEndLine() { metricResults(this, _, _, _, _, result, _, _) } + /** Gets the column on which the location of this query result ends. */ int getEndColumn() { metricResults(this, _, _, _, _, _, result, _) } + /** + * Holds if there is a `Location` entity whose location is the same as + * the location of this query result. + */ predicate hasMatchingLocation() { exists(this.getMatchingLocation()) } + /** + * Gets the `Location` entity whose location is the same as the location + * of this query result. + */ Location getMatchingLocation() { result.getFile() = this.getFile() and result.getStartLine() = this.getStartLine() and @@ -34,8 +61,10 @@ class MetricResult extends int { result.getEndColumn() = this.getEndColumn() } + /** Gets the value associated with this query result. */ float getValue() { metricResults(this, _, _, _, _, _, _, result) } + /** Gets the URL corresponding to the location of this query result. */ string getURL() { result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + From 5fc2a3de92b12d441860735049e001c6a2acf09a Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 20 May 2020 14:28:11 +0200 Subject: [PATCH 079/111] C++: QLDoc for default.qll and objc.qll These are both deprecated. --- cpp/ql/src/default.qll | 6 ++++++ cpp/ql/src/objc.qll | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/cpp/ql/src/default.qll b/cpp/ql/src/default.qll index 4996ace8452..6bc0f1b009d 100644 --- a/cpp/ql/src/default.qll +++ b/cpp/ql/src/default.qll @@ -1 +1,7 @@ +/** + * DEPRECATED: use `import cpp` instead of `import default`. + * + * Provides classes and predicates for working with C/C++ code. + */ + import cpp diff --git a/cpp/ql/src/objc.qll b/cpp/ql/src/objc.qll index 4996ace8452..58a9ec50ff7 100644 --- a/cpp/ql/src/objc.qll +++ b/cpp/ql/src/objc.qll @@ -1 +1,7 @@ +/** + * DEPRECATED: Objective C is no longer supported. + * + * Import `cpp` instead of `objc`. + */ + import cpp From 85df60ea659f2d84319b1b8511a5d5021fc2d3fc Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 25 May 2020 19:06:44 +0200 Subject: [PATCH 080/111] C++: Replace `import default` with `import cpp` Some tests still used the old name for the top-level library. --- cpp/ql/test/header-variant-tests/deduplication/classes.ql | 2 +- cpp/ql/test/library-tests/allocators/allocators.ql | 2 +- cpp/ql/test/library-tests/conversions/conversions.ql | 2 +- cpp/ql/test/library-tests/ir/constant_func/constant_func.ql | 2 +- cpp/ql/test/library-tests/ir/escape/escape.ql | 2 +- cpp/ql/test/library-tests/ir/escape/ssa_escape.ql | 2 +- cpp/ql/test/library-tests/literals/uuidof/uuidof.ql | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/ql/test/header-variant-tests/deduplication/classes.ql b/cpp/ql/test/header-variant-tests/deduplication/classes.ql index 2fe0098c9cf..ed44ab124dc 100644 --- a/cpp/ql/test/header-variant-tests/deduplication/classes.ql +++ b/cpp/ql/test/header-variant-tests/deduplication/classes.ql @@ -1,4 +1,4 @@ -import default +import cpp from Class c, string n where n = count(Class x | x.getName() = c.getName()) + " distinct class(es) called " + c.getName() diff --git a/cpp/ql/test/library-tests/allocators/allocators.ql b/cpp/ql/test/library-tests/allocators/allocators.ql index 235ec0451e7..a2126cdfbce 100644 --- a/cpp/ql/test/library-tests/allocators/allocators.ql +++ b/cpp/ql/test/library-tests/allocators/allocators.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.models.implementations.Allocation query predicate newExprs( diff --git a/cpp/ql/test/library-tests/conversions/conversions.ql b/cpp/ql/test/library-tests/conversions/conversions.ql index 6ba2bd8f365..c26881ecbbe 100644 --- a/cpp/ql/test/library-tests/conversions/conversions.ql +++ b/cpp/ql/test/library-tests/conversions/conversions.ql @@ -1,4 +1,4 @@ -import default +import cpp string getValueCategoryString(Expr expr) { if expr.isLValueCategory() diff --git a/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql b/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql index 8701725a18d..8e25ba0e5d4 100644 --- a/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql +++ b/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.implementation.aliased_ssa.constant.ConstantAnalysis import semmle.code.cpp.ir.internal.IntegerConstant diff --git a/cpp/ql/test/library-tests/ir/escape/escape.ql b/cpp/ql/test/library-tests/ir/escape/escape.ql index 9099fea159e..d5c88827af9 100644 --- a/cpp/ql/test/library-tests/ir/escape/escape.ql +++ b/cpp/ql/test/library-tests/ir/escape/escape.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.AliasAnalysis import semmle.code.cpp.ir.implementation.raw.IR import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql b/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql index e97cea7670d..e1693ba3f38 100644 --- a/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql +++ b/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasAnalysis import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasConfiguration import semmle.code.cpp.ir.implementation.unaliased_ssa.IR diff --git a/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql b/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql index b369e26e5bc..bff506957b9 100644 --- a/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql +++ b/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql @@ -1,4 +1,4 @@ -import default +import cpp query predicate classUuids(Class cls, string uuid) { if exists(cls.getUuid()) then uuid = cls.getUuid() else uuid = "" From e28ed848a429e16af5cdfd1089e7b60d1c378506 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 25 May 2020 19:26:36 +0200 Subject: [PATCH 081/111] C++: Remove VCS.qll and all queries using it All these queries have been deprecated since 2018. There is unfortunately no way to deprecate a library, but it's been years since we populated any databases using the VCS library, so nobody should be using it. --- change-notes/1.25/analysis-cpp.md | 1 + cpp/ql/src/Metrics/History/HChurn.ql | 27 ------ cpp/ql/src/Metrics/History/HLinesAdded.ql | 27 ------ cpp/ql/src/Metrics/History/HLinesDeleted.ql | 27 ------ .../src/Metrics/History/HNumberOfAuthors.ql | 18 ---- .../src/Metrics/History/HNumberOfChanges.ql | 19 ---- .../src/Metrics/History/HNumberOfCoCommits.ql | 21 ----- .../src/Metrics/History/HNumberOfReCommits.ql | 37 -------- .../Metrics/History/HNumberOfRecentAuthors.ql | 27 ------ .../History/HNumberOfRecentChangedFiles.ql | 24 ----- .../Metrics/History/HNumberOfRecentChanges.ql | 25 ----- cpp/ql/src/external/VCS.qll | 92 ------------------- cpp/ql/src/external/tests/DefectFromSVN.ql | 20 ---- cpp/ql/src/external/tests/MetricFromSVN.ql | 17 ---- cpp/ql/src/filters/RecentDefects.ql | 25 ----- cpp/ql/src/filters/RecentDefectsForMetric.ql | 25 ----- 16 files changed, 1 insertion(+), 431 deletions(-) delete mode 100644 cpp/ql/src/Metrics/History/HChurn.ql delete mode 100644 cpp/ql/src/Metrics/History/HLinesAdded.ql delete mode 100644 cpp/ql/src/Metrics/History/HLinesDeleted.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfAuthors.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfChanges.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfReCommits.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql delete mode 100644 cpp/ql/src/external/VCS.qll delete mode 100644 cpp/ql/src/external/tests/DefectFromSVN.ql delete mode 100644 cpp/ql/src/external/tests/MetricFromSVN.ql delete mode 100644 cpp/ql/src/filters/RecentDefects.ql delete mode 100644 cpp/ql/src/filters/RecentDefectsForMetric.ql diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md index d282441b092..ff02cc5045b 100644 --- a/change-notes/1.25/analysis-cpp.md +++ b/change-notes/1.25/analysis-cpp.md @@ -16,6 +16,7 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. ## Changes to libraries +* The library `VCS.qll` and all queries that imported it have been removed. * The data-flow library has been improved, which affects most security queries by potentially adding more results. Flow through functions now takes nested field reads/writes into account. For example, the library is able to track flow from `taint()` to `sink()` via the method diff --git a/cpp/ql/src/Metrics/History/HChurn.ql b/cpp/ql/src/Metrics/History/HChurn.ql deleted file mode 100644 index 7ff156b5300..00000000000 --- a/cpp/ql/src/Metrics/History/HChurn.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Churned lines per file - * @description Number of churned lines per file, across the revision - * history in the database. - * @kind treemap - * @id cpp/historical-churn - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - sum(Commit entry, int churn | - churn = entry.getRecentChurnForFile(f) and - not artificialChange(entry) - | - churn - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Metrics/History/HLinesAdded.ql b/cpp/ql/src/Metrics/History/HLinesAdded.ql deleted file mode 100644 index ce03c5b4190..00000000000 --- a/cpp/ql/src/Metrics/History/HLinesAdded.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Added lines per file - * @description Number of added lines per file, across the revision - * history in the database. - * @kind treemap - * @id cpp/historical-lines-added - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - sum(Commit entry, int churn | - churn = entry.getRecentAdditionsForFile(f) and - not artificialChange(entry) - | - churn - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Metrics/History/HLinesDeleted.ql b/cpp/ql/src/Metrics/History/HLinesDeleted.ql deleted file mode 100644 index 3d8ce78b6c4..00000000000 --- a/cpp/ql/src/Metrics/History/HLinesDeleted.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Deleted lines per file - * @description Number of deleted lines per file, across the revision - * history in the database. - * @kind treemap - * @id cpp/historical-lines-deleted - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - sum(Commit entry, int churn | - churn = entry.getRecentDeletionsForFile(f) and - not artificialChange(entry) - | - churn - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Metrics/History/HNumberOfAuthors.ql b/cpp/ql/src/Metrics/History/HNumberOfAuthors.ql deleted file mode 100644 index 2d8f1f382c3..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfAuthors.ql +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @name Number of authors - * @description Number of distinct authors for each file. - * @kind treemap - * @id cpp/historical-number-of-authors - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, count(Author author | author.getAnEditedFile() = f) diff --git a/cpp/ql/src/Metrics/History/HNumberOfChanges.ql b/cpp/ql/src/Metrics/History/HNumberOfChanges.ql deleted file mode 100644 index 451dc575636..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfChanges.ql +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @name Number of file-level changes - * @description The number of file-level changes made (by version - * control history). - * @kind treemap - * @id cpp/historical-number-of-changes - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max sum - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, count(Commit svn | f = svn.getAnAffectedFile() and not artificialChange(svn)) diff --git a/cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql b/cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql deleted file mode 100644 index ecd5c4ccb0d..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @name Number of co-committed files - * @description The average number of other files that are touched - * whenever a file is affected by a commit. - * @kind treemap - * @id cpp/historical-number-of-co-commits - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -int committedFiles(Commit commit) { result = count(commit.getAnAffectedFile()) } - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, avg(Commit commit | commit.getAnAffectedFile() = f | committedFiles(commit) - 1) diff --git a/cpp/ql/src/Metrics/History/HNumberOfReCommits.ql b/cpp/ql/src/Metrics/History/HNumberOfReCommits.ql deleted file mode 100644 index fe98e66964e..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfReCommits.ql +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @name Number of re-commits for each file - * @description A re-commit is taken to mean a commit to a file that - * was touched less than five days ago. - * @kind treemap - * @id cpp/historical-number-of-re-commits - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -predicate inRange(Commit first, Commit second) { - first.getAnAffectedFile() = second.getAnAffectedFile() and - first != second and - exists(int n | - n = first.getDate().daysTo(second.getDate()) and - n >= 0 and - n < 5 - ) -} - -int recommitsForFile(File f) { - result = - count(Commit recommit | - f = recommit.getAnAffectedFile() and - exists(Commit prev | inRange(prev, recommit)) - ) -} - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, recommitsForFile(f) diff --git a/cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql b/cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql deleted file mode 100644 index 7f40c8706d9..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Number of recent authors - * @description Number of distinct authors that have recently made - * changes. - * @kind treemap - * @id cpp/historical-number-of-recent-authors - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, - count(Author author | - exists(Commit e | - e = author.getACommit() and - f = e.getAnAffectedFile() and - e.daysToNow() <= 180 and - not artificialChange(e) - ) - ) diff --git a/cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql b/cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql deleted file mode 100644 index 751449eb5aa..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @name Recently changed files - * @description Number of files recently edited. - * @kind treemap - * @id cpp/historical-number-of-recent-changed-files - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max sum - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where - exists(Commit e | - e.getAnAffectedFile() = f and - e.daysToNow() <= 180 and - not artificialChange(e) - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, 1 diff --git a/cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql b/cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql deleted file mode 100644 index 886e8da6ca8..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @name Recent changes - * @description Number of recent commits to this file. - * @kind treemap - * @id cpp/historical-number-of-recent-changes - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max sum - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - count(Commit e | - e.getAnAffectedFile() = f and - e.daysToNow() <= 180 and - not artificialChange(e) - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/external/VCS.qll b/cpp/ql/src/external/VCS.qll deleted file mode 100644 index ce36ace56d9..00000000000 --- a/cpp/ql/src/external/VCS.qll +++ /dev/null @@ -1,92 +0,0 @@ -import cpp - -class Commit extends @svnentry { - Commit() { - svnaffectedfiles(this, _, _) and - exists(date svnDate, date snapshotDate | - svnentries(this, _, _, svnDate, _) and - snapshotDate(snapshotDate) and - svnDate <= snapshotDate - ) - } - - string toString() { result = this.getRevisionName() } - - string getRevisionName() { svnentries(this, result, _, _, _) } - - string getAuthor() { svnentries(this, _, result, _, _) } - - date getDate() { svnentries(this, _, _, result, _) } - - int getChangeSize() { svnentries(this, _, _, _, result) } - - string getMessage() { svnentrymsg(this, result) } - - string getAnAffectedFilePath(string action) { - exists(File rawFile | svnaffectedfiles(this, unresolveElement(rawFile), action) | - result = rawFile.getAbsolutePath() - ) - } - - string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) } - - File getAnAffectedFile(string action) { - // Workaround for incorrect keys in SVN data - exists(File svnFile | svnFile.getAbsolutePath() = result.getAbsolutePath() | - svnaffectedfiles(this, unresolveElement(svnFile), action) - ) and - exists(result.getMetrics().getNumberOfLinesOfCode()) - } - - File getAnAffectedFile() { exists(string action | result = this.getAnAffectedFile(action)) } - - private predicate churnForFile(File f, int added, int deleted) { - // Workaround for incorrect keys in SVN data - exists(File svnFile | svnFile.getAbsolutePath() = f.getAbsolutePath() | - svnchurn(this, unresolveElement(svnFile), added, deleted) - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) - } - - int getRecentChurnForFile(File f) { - exists(int added, int deleted | churnForFile(f, added, deleted) and result = added + deleted) - } - - int getRecentAdditionsForFile(File f) { churnForFile(f, result, _) } - - int getRecentDeletionsForFile(File f) { churnForFile(f, _, result) } - - predicate isRecent() { recentCommit(this) } - - int daysToNow() { - exists(date now | snapshotDate(now) | result = getDate().daysTo(now) and result >= 0) - } -} - -class Author extends string { - Author() { exists(Commit e | this = e.getAuthor()) } - - Commit getACommit() { result.getAuthor() = this } - - File getAnEditedFile() { result = this.getACommit().getAnAffectedFile() } -} - -predicate recentCommit(Commit e) { - exists(date snapshotDate, date commitDate, int days | - snapshotDate(snapshotDate) and - e.getDate() = commitDate and - days = commitDate.daysTo(snapshotDate) and - days >= 0 and - days <= 60 - ) -} - -date firstChange(File f) { - result = min(Commit e, date toMin | f = e.getAnAffectedFile() and toMin = e.getDate() | toMin) -} - -predicate firstCommit(Commit e) { - not exists(File f | f = e.getAnAffectedFile() | firstChange(f) < e.getDate()) -} - -predicate artificialChange(Commit e) { firstCommit(e) or e.getChangeSize() >= 50000 } diff --git a/cpp/ql/src/external/tests/DefectFromSVN.ql b/cpp/ql/src/external/tests/DefectFromSVN.ql deleted file mode 100644 index 64dd69148eb..00000000000 --- a/cpp/ql/src/external/tests/DefectFromSVN.ql +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @name Defect from SVN - * @description A test case for creating a defect from SVN data. - * @kind problem - * @problem.severity warning - * @tags external-data - * @deprecated - */ - -import cpp -import external.ExternalArtifact -import external.VCS - -predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) } - -predicate maxCommits(int i) { i = max(File f, int j | numCommits(f, j) | j) } - -from File f, int i -where numCommits(f, i) and maxCommits(i) -select f, "This file has " + i + " commits." diff --git a/cpp/ql/src/external/tests/MetricFromSVN.ql b/cpp/ql/src/external/tests/MetricFromSVN.ql deleted file mode 100644 index e81eec18ea5..00000000000 --- a/cpp/ql/src/external/tests/MetricFromSVN.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Metric from SVN - * @description Find number of commits for a file - * @treemap.warnOn lowValues - * @metricType file - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) } - -from File f, int i -where numCommits(f, i) -select f, i diff --git a/cpp/ql/src/filters/RecentDefects.ql b/cpp/ql/src/filters/RecentDefects.ql deleted file mode 100644 index 4b742849fda..00000000000 --- a/cpp/ql/src/filters/RecentDefects.ql +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @name Filter: exclude results from files that have not recently been - * edited - * @description Use this filter to return results only if they are - * located in files that have been modified in the 60 days - * before the date of the snapshot. - * @kind problem - * @id cpp/recent-defects-filter - * @tags filter - * external-data - * @deprecated - */ - -import cpp -import external.DefectFilter -import external.VCS - -pragma[noopt] -private predicate recent(File file) { - exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e)) -} - -from DefectResult res -where recent(res.getFile()) -select res, res.getMessage() diff --git a/cpp/ql/src/filters/RecentDefectsForMetric.ql b/cpp/ql/src/filters/RecentDefectsForMetric.ql deleted file mode 100644 index ee057fe71ca..00000000000 --- a/cpp/ql/src/filters/RecentDefectsForMetric.ql +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @name Metric filter: exclude results from files that have not - * recently been edited - * @description Use this filter to return results only if they are - * located in files that have been modified in the 60 days - * before the snapshot. - * @kind treemap - * @id cpp/recent-defects-for-metric-filter - * @tags filter - * external-data - * @deprecated - */ - -import cpp -import external.MetricFilter -import external.VCS - -pragma[noopt] -private predicate recent(File file) { - exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e)) -} - -from MetricResult res -where recent(res.getFile()) -select res, res.getValue() From 8fac3a14034f6e99696f98be40a8e7e045440fa3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 25 May 2020 14:43:31 +0200 Subject: [PATCH 082/111] add IsEmptyGuard to TaintTracking --- .../javascript/dataflow/TaintTracking.qll | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 5de9ef312d6..7a74c0fa6d8 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -827,6 +827,28 @@ module TaintTracking { override predicate appliesTo(Configuration cfg) { any() } } + /** + * A test of form `x.length === "0"`, preventing `x` from being tainted. + */ + class IsEmptyGuard extends AdditionalSanitizerGuardNode, DataFlow::ValueNode { + override EqualityTest astNode; + boolean polarity; + Expr operand; + + IsEmptyGuard() { + astNode.getPolarity() = polarity and + astNode.getAnOperand().(ConstantExpr).getIntValue() = 0 and + exists(DataFlow::PropRead read | read.asExpr() = astNode.getAnOperand() | + read.getBase().asExpr() = operand and + read.getPropertyName() = "length" + ) + } + + override predicate sanitizes(boolean outcome, Expr e) { polarity = outcome and e = operand } + + override predicate appliesTo(Configuration cfg) { any() } + } + /** DEPRECATED. This class has been renamed to `InclusionSanitizer`. */ deprecated class StringInclusionSanitizer = InclusionSanitizer; From 9254df1f78bd0a254ec7c52bdec2438ae0a996d5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 25 May 2020 14:53:29 +0200 Subject: [PATCH 083/111] sanitize optionally sanitized values --- .../security/dataflow/DomBasedXss.qll | 4 + .../javascript/security/dataflow/Xss.qll | 32 +++++++ .../security/dataflow/XssThroughDom.qll | 4 + .../query-tests/Security/CWE-079/Xss.expected | 86 +++++++++++++++++++ .../CWE-079/XssWithAdditionalSources.expected | 78 +++++++++++++++++ .../Security/CWE-079/optionalSanitizer.js | 46 ++++++++++ 6 files changed, 250 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/optionalSanitizer.js diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll index a1b2a4bf6d9..e58c3ecf55f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll @@ -47,6 +47,10 @@ module DomBasedXss { prop = urlSuffixPseudoProperty() ) } + + override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { + DomBasedXss::isOptionallySanitizedEdge(pred, succ) + } } private string urlSuffixPseudoProperty() { result = "$UrlSuffix$" } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 55be5464a6e..c3056527cef 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -302,6 +302,38 @@ module DomBasedXss { private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { } private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + + /** + * Holds if there exists two dataflow edges to `succ`, where one edges is sanitized, and the other edge starts with `pred`. + */ + predicate isOptionallySanitizedEdge(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::CallNode sanitizer | + sanitizer.getCalleeName().regexpMatch("(?i).*sanitize.*") + | + // sanitized = sanitize ? sanitizer(source) : source; + exists(ConditionalExpr branch, Variable var, VarAccess access | + branch = succ.asExpr() and access = var.getAnAccess() + | + branch.getABranch() = access and + pred.getEnclosingExpr() = access and + sanitizer = branch.getABranch().flow() and + sanitizer.getAnArgument().getEnclosingExpr() = var.getAnAccess() + ) + or + // sanitized = source; if (sanitize) {sanitized = sanitizer(source)}; + exists(SsaPhiNode phi, SsaExplicitDefinition a, SsaDefinition b | + a = phi.getAnInput().getDefinition() and + b = phi.getAnInput().getDefinition() and + count(phi.getAnInput()) = 2 and + not a = b and + sanitizer = DataFlow::valueNode(a.getDef().getSource()) and + sanitizer.getAnArgument().asExpr().(VarAccess).getVariable() = b.getSourceVariable() + | + pred = DataFlow::ssaDefinitionNode(b) and + succ = DataFlow::ssaDefinitionNode(phi) + ) + ) + } } /** Provides classes and predicates for the reflected XSS query. */ diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll index 716002b7db6..7aaca5da604 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll @@ -33,6 +33,10 @@ module XssThroughDom { guard instanceof TypeTestGuard or guard instanceof UnsafeJQuery::PropertyPresenceSanitizer } + + override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { + DomBasedXss::isOptionallySanitizedEdge(pred, succ) + } } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 9235b724e9d..46d4d571144 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -36,6 +36,46 @@ nodes | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | | nodemailer.js:13:50:13:66 | req.query.message | +| optionalSanitizer.js:2:7:2:39 | target | +| optionalSanitizer.js:2:16:2:32 | document.location | +| optionalSanitizer.js:2:16:2:32 | document.location | +| optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:8:7:8:22 | tainted | +| optionalSanitizer.js:8:17:8:22 | target | +| optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:15:9:15:14 | target | +| optionalSanitizer.js:16:18:16:18 | x | +| optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:26:7:26:39 | target | +| optionalSanitizer.js:26:16:26:32 | document.location | +| optionalSanitizer.js:26:16:26:32 | document.location | +| optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:31:7:31:23 | tainted2 | +| optionalSanitizer.js:31:18:31:23 | target | +| optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | +| optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | +| optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | +| optionalSanitizer.js:38:18:38:23 | target | +| optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | +| optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | +| optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | +| optionalSanitizer.js:45:41:45:46 | target | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -417,6 +457,44 @@ edges | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:8:17:8:22 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:15:9:15:14 | target | +| optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:2:16:2:39 | documen ... .search | optionalSanitizer.js:2:7:2:39 | target | +| optionalSanitizer.js:8:7:8:22 | tainted | optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:8:7:8:22 | tainted | optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:8:17:8:22 | target | optionalSanitizer.js:8:7:8:22 | tainted | +| optionalSanitizer.js:15:9:15:14 | target | optionalSanitizer.js:16:18:16:18 | x | +| optionalSanitizer.js:16:18:16:18 | x | optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:16:18:16:18 | x | optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:31:18:31:23 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:38:18:38:23 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:26:7:26:39 | target | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:31:18:31:23 | target | optionalSanitizer.js:31:7:31:23 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | optionalSanitizer.js:34:5:34:36 | tainted2 | +| optionalSanitizer.js:34:28:34:35 | tainted2 | optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:38:18:38:23 | target | optionalSanitizer.js:38:7:38:23 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | optionalSanitizer.js:41:5:41:36 | tainted3 | +| optionalSanitizer.js:41:28:41:35 | tainted3 | optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | @@ -728,6 +806,14 @@ edges | jquery.js:7:5:7:34 | "
    " | jquery.js:2:17:2:33 | document.location | jquery.js:7:5:7:34 | "
    " | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value | | jquery.js:8:18:8:34 | "XSS: " + tainted | jquery.js:2:17:2:33 | document.location | jquery.js:8:18:8:34 | "XSS: " + tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value | | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | HTML injection vulnerability due to $@. | nodemailer.js:13:50:13:66 | req.query.message | user-provided value | +| optionalSanitizer.js:6:18:6:23 | target | optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:6:18:6:23 | target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:2:16:2:32 | document.location | user-provided value | +| optionalSanitizer.js:9:18:9:24 | tainted | optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:9:18:9:24 | tainted | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:2:16:2:32 | document.location | user-provided value | +| optionalSanitizer.js:17:20:17:20 | x | optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:17:20:17:20 | x | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:2:16:2:32 | document.location | user-provided value | +| optionalSanitizer.js:32:18:32:25 | tainted2 | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:32:18:32:25 | tainted2 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | +| optionalSanitizer.js:36:18:36:25 | tainted2 | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:36:18:36:25 | tainted2 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | +| optionalSanitizer.js:39:18:39:25 | tainted3 | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:39:18:39:25 | tainted3 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | +| optionalSanitizer.js:43:18:43:25 | tainted3 | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:43:18:43:25 | tainted3 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | | react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | stored-xss.js:5:20:5:52 | session ... ssion') | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:5:20:5:52 | session ... ssion') | Cross-site scripting vulnerability due to $@. | stored-xss.js:2:39:2:55 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index a73dae129f2..4f70a16f0c8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -36,6 +36,46 @@ nodes | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | | nodemailer.js:13:50:13:66 | req.query.message | +| optionalSanitizer.js:2:7:2:39 | target | +| optionalSanitizer.js:2:16:2:32 | document.location | +| optionalSanitizer.js:2:16:2:32 | document.location | +| optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:8:7:8:22 | tainted | +| optionalSanitizer.js:8:17:8:22 | target | +| optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:15:9:15:14 | target | +| optionalSanitizer.js:16:18:16:18 | x | +| optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:26:7:26:39 | target | +| optionalSanitizer.js:26:16:26:32 | document.location | +| optionalSanitizer.js:26:16:26:32 | document.location | +| optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:31:7:31:23 | tainted2 | +| optionalSanitizer.js:31:18:31:23 | target | +| optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | +| optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | +| optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | +| optionalSanitizer.js:38:18:38:23 | target | +| optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | +| optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | +| optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | +| optionalSanitizer.js:45:41:45:46 | target | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -421,6 +461,44 @@ edges | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:8:17:8:22 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:15:9:15:14 | target | +| optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:2:16:2:39 | documen ... .search | optionalSanitizer.js:2:7:2:39 | target | +| optionalSanitizer.js:8:7:8:22 | tainted | optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:8:7:8:22 | tainted | optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:8:17:8:22 | target | optionalSanitizer.js:8:7:8:22 | tainted | +| optionalSanitizer.js:15:9:15:14 | target | optionalSanitizer.js:16:18:16:18 | x | +| optionalSanitizer.js:16:18:16:18 | x | optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:16:18:16:18 | x | optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:31:18:31:23 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:38:18:38:23 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:26:7:26:39 | target | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:31:18:31:23 | target | optionalSanitizer.js:31:7:31:23 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | optionalSanitizer.js:34:5:34:36 | tainted2 | +| optionalSanitizer.js:34:28:34:35 | tainted2 | optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:38:18:38:23 | target | optionalSanitizer.js:38:7:38:23 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | optionalSanitizer.js:41:5:41:36 | tainted3 | +| optionalSanitizer.js:41:28:41:35 | tainted3 | optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/optionalSanitizer.js b/javascript/ql/test/query-tests/Security/CWE-079/optionalSanitizer.js new file mode 100644 index 00000000000..e8139936bc7 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/optionalSanitizer.js @@ -0,0 +1,46 @@ +function test() { + var target = document.location.search + + $('myId').html(sanitize ? DOMPurify.sanitize(target) : target); // OK + + $('myId').html(target); // NOT OK + + var tainted = target; + $('myId').html(tainted); // NOT OK + if (sanitize) { + tainted = DOMPurify.sanitize(tainted); + } + $('myId').html(tainted); // OK + + inner(target); + function inner(x) { + $('myId').html(x); // NOT OK + if (sanitize) { + x = DOMPurify.sanitize(x); + } + $('myId').html(x); // OK + } +} + +function badSanitizer() { + var target = document.location.search + + function sanitizeBad(x) { + return x; // No sanitization; + } + var tainted2 = target; + $('myId').html(tainted2); // NOT OK + if (sanitize) { + tainted2 = sanitizeBad(tainted2); + } + $('myId').html(tainted2); // NOT OK + + var tainted3 = target; + $('myId').html(tainted3); // NOT OK + if (sanitize) { + tainted3 = sanitizeBad(tainted3); + } + $('myId').html(tainted3); // NOT OK + + $('myId').html(sanitize ? sanitizeBad(target) : target); // NOT OK +} From 3f66c04e12d72868344672eff5ef1c14388b6de5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 25 May 2020 23:59:01 +0200 Subject: [PATCH 084/111] change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0eb939d6801..b6c44da9643 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -47,6 +47,7 @@ | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | | Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Client-side cross-site scripting (`js/xss`) | Less results | This query no longer flags optionally sanitized values. | The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): From a39e8b480287bd6f6b524c15a556de3a47cbb699 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 22 May 2020 11:48:03 +0100 Subject: [PATCH 085/111] JavaScript: Add test for `FlowSteps::argumentPassing` predicate. --- .../ql/test/library-tests/DataFlow/argumentPassing.expected | 6 ++++++ .../ql/test/library-tests/DataFlow/argumentPassing.ql | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 javascript/ql/test/library-tests/DataFlow/argumentPassing.expected create mode 100644 javascript/ql/test/library-tests/DataFlow/argumentPassing.ql diff --git a/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected b/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected new file mode 100644 index 00000000000..546f86b199d --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected @@ -0,0 +1,6 @@ +| sources.js:3:1:5:6 | (functi ... \\n})(23) | sources.js:5:4:5:5 | 23 | sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:3:11:3:11 | x | +| tst.js:16:1:20:9 | (functi ... ("arg") | tst.js:20:4:20:8 | "arg" | tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:13:16:13 | a | +| tst.js:35:1:35:7 | g(true) | tst.js:35:3:35:6 | true | tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:32:12:32:12 | b | +| tst.js:44:1:44:5 | o.m() | tst.js:44:1:44:1 | o | tst.js:39:4:41:3 | () {\\n this;\\n } | tst.js:39:4:39:3 | this | +| tst.js:87:1:96:2 | (functi ... r: 0\\n}) | tst.js:92:4:96:1 | {\\n p: ... r: 0\\n} | tst.js:87:2:92:1 | functio ... + z;\\n} | tst.js:87:11:87:24 | { p: x, ...o } | +| tst.js:98:1:103:17 | (functi ... 3, 0 ]) | tst.js:103:4:103:16 | [ 19, 23, 0 ] | tst.js:98:2:103:1 | functio ... + z;\\n} | tst.js:98:11:98:24 | [ x, ...rest ] | diff --git a/javascript/ql/test/library-tests/DataFlow/argumentPassing.ql b/javascript/ql/test/library-tests/DataFlow/argumentPassing.ql new file mode 100644 index 00000000000..56bb46f695a --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/argumentPassing.ql @@ -0,0 +1,6 @@ +import javascript +import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps + +from DataFlow::Node invk, DataFlow::Node arg, Function f, DataFlow::SourceNode parm +where FlowSteps::argumentPassing(invk, arg, f, parm) +select invk, arg, f, parm From 9d3a9d71f18fbf9fc6421e49beb725f8e3fe91ed Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 22 May 2020 11:50:57 +0100 Subject: [PATCH 086/111] JavaScript: Add basic support for reasoning about reflective parameter accesses. Currently, only `arguments[c]` for a constant value `c` is supported. This allows us to detect the prototype-pollution vulnerabilities in (old versions of) `extend`, `jquery`, and `node.extend`. --- .../dataflow/internal/FlowSteps.qll | 29 +++++++++++++++---- .../DataFlow/argumentPassing.expected | 4 +++ .../test/library-tests/DataFlow/arguments.js | 12 ++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 javascript/ql/test/library-tests/DataFlow/arguments.js diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 948aabb6dc9..e2353b003c7 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -151,11 +151,14 @@ private module CachedSteps { ) { calls(invk, f) and ( - exists(int i, Parameter p | - f.getParameter(i) = p and - not p.isRestParameter() and - arg = invk.getArgument(i) and - parm = DataFlow::parameterNode(p) + exists(int i | arg = invk.getArgument(i) | + exists(Parameter p | + f.getParameter(i) = p and + not p.isRestParameter() and + parm = DataFlow::parameterNode(p) + ) + or + parm = reflectiveParameterAccess(f, i) ) or arg = invk.(DataFlow::CallNode).getReceiver() and @@ -185,6 +188,22 @@ private module CachedSteps { ) } + /** + * Gets a data-flow node inside `f` that refers to the `arguments` object of `f`. + */ + private DataFlow::Node argumentsAccess(Function f) { + result.getContainer().getEnclosingContainer*() = f and + result.analyze().getAValue().(AbstractArguments).getFunction() = f + } + + /** + * Gets a data-flow node that refers to the `i`th parameter of `f` through its `arguments` + * object. + */ + private DataFlow::SourceNode reflectiveParameterAccess(Function f, int i) { + result.(DataFlow::PropRead).accesses(argumentsAccess(f), any(string p | i = p.toInt())) + } + /** * Holds if there is a flow step from `pred` to `succ` through parameter passing * to a function call. diff --git a/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected b/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected index 546f86b199d..37fad6b0f65 100644 --- a/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected +++ b/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected @@ -1,3 +1,7 @@ +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:7:11:7 | 1 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:2:16:2:16 | x | +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:7:11:7 | 1 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:4:28:4:39 | arguments[0] | +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:10:11:10 | 2 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:5:25:5:36 | arguments[1] | +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:13:11:13 | 3 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:7:24:7:30 | args[2] | | sources.js:3:1:5:6 | (functi ... \\n})(23) | sources.js:5:4:5:5 | 23 | sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:3:11:3:11 | x | | tst.js:16:1:20:9 | (functi ... ("arg") | tst.js:20:4:20:8 | "arg" | tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:13:16:13 | a | | tst.js:35:1:35:7 | g(true) | tst.js:35:3:35:6 | true | tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:32:12:32:12 | b | diff --git a/javascript/ql/test/library-tests/DataFlow/arguments.js b/javascript/ql/test/library-tests/DataFlow/arguments.js new file mode 100644 index 00000000000..e0ca10ffc59 --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/arguments.js @@ -0,0 +1,12 @@ +(function() { + function f(x) { + let firstArg = x; + let alsoFirstArg = arguments[0]; + let secondArg = arguments[1]; + let args = arguments; + let thirdArg = args[2]; + arguments = {}; + let notFirstArg = arguments[0]; + } + f(1, 2, 3); +})(); From b205d3693361b2af66872dd3b2611af20ab97835 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 26 May 2020 11:40:26 +0200 Subject: [PATCH 087/111] C++: Remove chi -> load rule from simpleLocalFlowStep and accept tests --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 1 - .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 58 ++++++------------- .../dataflow-ir-consistency.expected | 1 - 3 files changed, 18 insertions(+), 42 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 5087363eee6..3076df93a6d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -229,7 +229,6 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) { // Flow from an element to an array or union that contains it. i2.(ChiInstruction).getPartial() = i1 and not i2.isResultConflated() and - not exists(PartialDefinitionNode n | n.asInstruction() = i2) and exists(Type t | i2.getResultLanguageType().hasType(t, false) | t instanceof Union or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 772754745df..f9e1aad4e66 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -239,8 +239,6 @@ abstract class PostUpdateNode extends InstructionNode { } /** - * INTERNAL: do not use. - * * The base class for nodes that perform "partial definitions". * * In contrast to a normal "definition", which provides a new value for @@ -253,7 +251,7 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } +abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; @@ -272,17 +270,6 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } } -private class FieldStoreWriteSideEffectNode extends PartialDefinitionNode { - override ChiInstruction instr; - - FieldStoreWriteSideEffectNode() { - not instr.isResultConflated() and - exists(WriteSideEffectInstruction sideEffect | instr.getPartial() = sideEffect) - } - - override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } -} - /** * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. * For instance, an update to a field of a struct containing only one field. For these cases we @@ -434,32 +421,6 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) - or - // The next two rules allow flow from partial definitions in setters to succeeding loads in the caller. - // First, we add flow from write side-effects to non-conflated chi instructions through their - // partial operands. Consider the following example: - // ``` - // void setX(Point* p, int new_x) { - // p->x = new_x; - // } - // ... - // setX(&p, taint()); - // ``` - // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to - // `setX`, which will be melded into `p` through a chi instruction. - nodeTo instanceof FieldStoreWriteSideEffectNode and - exists(ChiInstruction chi | chi = nodeTo.asInstruction() | - chi.getPartialOperand().getDef() = nodeFrom.asInstruction().(WriteSideEffectInstruction) and - not chi.isResultConflated() - ) - or - // Next, we add flow from non-conflated chi instructions to loads (even when they are not precise). - // This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above. - nodeFrom instanceof FieldStoreWriteSideEffectNode and - exists(ChiInstruction chi | chi = nodeFrom.asInstruction() | - not chi.isResultConflated() and - nodeTo.asInstruction().(LoadInstruction).getSourceValueOperand().getAnyDef() = chi - ) } pragma[noinline] @@ -497,6 +458,23 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // for now. iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or + // Add flow from write side-effects to non-conflated chi instructions through their + // partial operands. From there, a `readStep` will find subsequent reads of that field. + // Consider the following example: + // ``` + // void setX(Point* p, int new_x) { + // p->x = new_x; + // } + // ... + // setX(&p, taint()); + // ``` + // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to + // `setX`, which will be melded into `p` through a chi instruction. + exists(ChiInstruction chi | chi = iTo | + chi.getPartialOperand().getDef() = iFrom.(WriteSideEffectInstruction) and + not chi.isResultConflated() + ) + or // Flow from stores to structs with a single field to a load of that field. iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and exists(int size, Type type | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index 99bf7799ff2..3940c1e8389 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -31,7 +31,6 @@ postIsNotPre postHasUniquePre uniquePostUpdate | ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. | -| ref.cpp:100:34:100:36 | InitializeIndirection | Node has multiple PostUpdateNodes. | | ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. | postIsInSameCallable reverseRead From 7ddf5ced23433e4083386633d9ad1227ce71ee90 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 26 May 2020 10:49:18 +0100 Subject: [PATCH 088/111] JavaScript: Update expected output for unrelated tests. --- .../DataFlow/enclosingExpr.expected | 39 +++++++++++++++++++ .../library-tests/DataFlow/flowStep.expected | 13 +++++++ .../DataFlow/getIntValue.expected | 7 ++++ .../DataFlow/incomplete.expected | 10 +++++ .../DataFlow/parameters.expected | 1 + .../library-tests/DataFlow/sources.expected | 13 +++++++ 6 files changed, 83 insertions(+) diff --git a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected index 80b838abfc6..e5705fa6f83 100644 --- a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected +++ b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected @@ -1,3 +1,42 @@ +| arguments.js:1:1:12:2 | (functi ... 3);\\n}) | arguments.js:1:1:12:2 | (functi ... 3);\\n}) | +| arguments.js:1:1:12:4 | (functi ... );\\n})() | arguments.js:1:1:12:4 | (functi ... );\\n})() | +| arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:2:12:1 | functio ... , 3);\\n} | +| arguments.js:2:14:2:14 | f | arguments.js:2:14:2:14 | f | +| arguments.js:2:16:2:16 | x | arguments.js:2:16:2:16 | x | +| arguments.js:3:13:3:20 | firstArg | arguments.js:3:13:3:20 | firstArg | +| arguments.js:3:13:3:24 | firstArg = x | arguments.js:3:13:3:24 | firstArg = x | +| arguments.js:3:24:3:24 | x | arguments.js:3:24:3:24 | x | +| arguments.js:4:13:4:24 | alsoFirstArg | arguments.js:4:13:4:24 | alsoFirstArg | +| arguments.js:4:13:4:39 | alsoFir ... ents[0] | arguments.js:4:13:4:39 | alsoFir ... ents[0] | +| arguments.js:4:28:4:36 | arguments | arguments.js:4:28:4:36 | arguments | +| arguments.js:4:28:4:39 | arguments[0] | arguments.js:4:28:4:39 | arguments[0] | +| arguments.js:4:38:4:38 | 0 | arguments.js:4:38:4:38 | 0 | +| arguments.js:5:13:5:21 | secondArg | arguments.js:5:13:5:21 | secondArg | +| arguments.js:5:13:5:36 | secondA ... ents[1] | arguments.js:5:13:5:36 | secondA ... ents[1] | +| arguments.js:5:25:5:33 | arguments | arguments.js:5:25:5:33 | arguments | +| arguments.js:5:25:5:36 | arguments[1] | arguments.js:5:25:5:36 | arguments[1] | +| arguments.js:5:35:5:35 | 1 | arguments.js:5:35:5:35 | 1 | +| arguments.js:6:13:6:16 | args | arguments.js:6:13:6:16 | args | +| arguments.js:6:13:6:28 | args = arguments | arguments.js:6:13:6:28 | args = arguments | +| arguments.js:6:20:6:28 | arguments | arguments.js:6:20:6:28 | arguments | +| arguments.js:7:13:7:20 | thirdArg | arguments.js:7:13:7:20 | thirdArg | +| arguments.js:7:13:7:30 | thirdArg = args[2] | arguments.js:7:13:7:30 | thirdArg = args[2] | +| arguments.js:7:24:7:27 | args | arguments.js:7:24:7:27 | args | +| arguments.js:7:24:7:30 | args[2] | arguments.js:7:24:7:30 | args[2] | +| arguments.js:7:29:7:29 | 2 | arguments.js:7:29:7:29 | 2 | +| arguments.js:8:9:8:17 | arguments | arguments.js:8:9:8:17 | arguments | +| arguments.js:8:9:8:22 | arguments = {} | arguments.js:8:9:8:22 | arguments = {} | +| arguments.js:8:21:8:22 | {} | arguments.js:8:21:8:22 | {} | +| arguments.js:9:13:9:23 | notFirstArg | arguments.js:9:13:9:23 | notFirstArg | +| arguments.js:9:13:9:38 | notFirs ... ents[0] | arguments.js:9:13:9:38 | notFirs ... ents[0] | +| arguments.js:9:27:9:35 | arguments | arguments.js:9:27:9:35 | arguments | +| arguments.js:9:27:9:38 | arguments[0] | arguments.js:9:27:9:38 | arguments[0] | +| arguments.js:9:37:9:37 | 0 | arguments.js:9:37:9:37 | 0 | +| arguments.js:11:5:11:5 | f | arguments.js:11:5:11:5 | f | +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:5:11:14 | f(1, 2, 3) | +| arguments.js:11:7:11:7 | 1 | arguments.js:11:7:11:7 | 1 | +| arguments.js:11:10:11:10 | 2 | arguments.js:11:10:11:10 | 2 | +| arguments.js:11:13:11:13 | 3 | arguments.js:11:13:11:13 | 3 | | eval.js:1:10:1:10 | k | eval.js:1:10:1:10 | k | | eval.js:2:7:2:7 | x | eval.js:2:7:2:7 | x | | eval.js:2:7:2:12 | x = 42 | eval.js:2:7:2:12 | x = 42 | diff --git a/javascript/ql/test/library-tests/DataFlow/flowStep.expected b/javascript/ql/test/library-tests/DataFlow/flowStep.expected index 49f208f89c1..cfb92ff6339 100644 --- a/javascript/ql/test/library-tests/DataFlow/flowStep.expected +++ b/javascript/ql/test/library-tests/DataFlow/flowStep.expected @@ -1,3 +1,16 @@ +| arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:1:12:2 | (functi ... 3);\\n}) | +| arguments.js:2:5:2:5 | arguments | arguments.js:4:28:4:36 | arguments | +| arguments.js:2:5:2:5 | arguments | arguments.js:5:25:5:33 | arguments | +| arguments.js:2:5:2:5 | arguments | arguments.js:6:20:6:28 | arguments | +| arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:2:14:2:14 | f | +| arguments.js:2:14:2:14 | f | arguments.js:11:5:11:5 | f | +| arguments.js:2:16:2:16 | x | arguments.js:2:16:2:16 | x | +| arguments.js:2:16:2:16 | x | arguments.js:3:24:3:24 | x | +| arguments.js:6:13:6:28 | args | arguments.js:7:24:7:27 | args | +| arguments.js:6:20:6:28 | arguments | arguments.js:6:13:6:28 | args | +| arguments.js:8:9:8:22 | arguments | arguments.js:9:27:9:35 | arguments | +| arguments.js:8:21:8:22 | {} | arguments.js:8:9:8:22 | arguments | +| arguments.js:8:21:8:22 | {} | arguments.js:8:9:8:22 | arguments = {} | | eval.js:2:7:2:12 | x | eval.js:4:3:4:3 | x | | eval.js:2:11:2:12 | 42 | eval.js:2:7:2:12 | x | | sources.js:1:6:1:6 | x | sources.js:1:6:1:6 | x | diff --git a/javascript/ql/test/library-tests/DataFlow/getIntValue.expected b/javascript/ql/test/library-tests/DataFlow/getIntValue.expected index fdeffe0b52e..e59b4fdd7c7 100644 --- a/javascript/ql/test/library-tests/DataFlow/getIntValue.expected +++ b/javascript/ql/test/library-tests/DataFlow/getIntValue.expected @@ -1,3 +1,10 @@ +| arguments.js:4:38:4:38 | 0 | 0 | +| arguments.js:5:35:5:35 | 1 | 1 | +| arguments.js:7:29:7:29 | 2 | 2 | +| arguments.js:9:37:9:37 | 0 | 0 | +| arguments.js:11:7:11:7 | 1 | 1 | +| arguments.js:11:10:11:10 | 2 | 2 | +| arguments.js:11:13:11:13 | 3 | 3 | | eval.js:2:11:2:12 | 42 | 42 | | sources.js:4:12:4:13 | 19 | 19 | | sources.js:5:4:5:5 | 23 | 23 | diff --git a/javascript/ql/test/library-tests/DataFlow/incomplete.expected b/javascript/ql/test/library-tests/DataFlow/incomplete.expected index 942748440e5..ae3b700e1a6 100644 --- a/javascript/ql/test/library-tests/DataFlow/incomplete.expected +++ b/javascript/ql/test/library-tests/DataFlow/incomplete.expected @@ -1,3 +1,13 @@ +| arguments.js:1:1:12:4 | exceptional return of (functi ... );\\n})() | call | +| arguments.js:1:2:12:1 | exceptional return of anonymous function | call | +| arguments.js:2:5:10:5 | exceptional return of function f | call | +| arguments.js:2:16:2:16 | x | call | +| arguments.js:4:28:4:39 | arguments[0] | heap | +| arguments.js:5:25:5:36 | arguments[1] | heap | +| arguments.js:7:24:7:30 | args[2] | heap | +| arguments.js:9:27:9:38 | arguments[0] | heap | +| arguments.js:11:5:11:14 | exceptional return of f(1, 2, 3) | call | +| arguments.js:11:5:11:14 | f(1, 2, 3) | call | | eval.js:1:1:5:1 | exceptional return of function k | call | | eval.js:2:7:2:12 | x | eval | | eval.js:3:3:3:6 | eval | global | diff --git a/javascript/ql/test/library-tests/DataFlow/parameters.expected b/javascript/ql/test/library-tests/DataFlow/parameters.expected index 34cc8e6bb66..c6252e77f12 100644 --- a/javascript/ql/test/library-tests/DataFlow/parameters.expected +++ b/javascript/ql/test/library-tests/DataFlow/parameters.expected @@ -1,3 +1,4 @@ +| arguments.js:2:16:2:16 | x | | sources.js:1:6:1:6 | x | | sources.js:3:11:3:11 | x | | sources.js:9:14:9:18 | array | diff --git a/javascript/ql/test/library-tests/DataFlow/sources.expected b/javascript/ql/test/library-tests/DataFlow/sources.expected index ff60d49cf58..faa640a5d84 100644 --- a/javascript/ql/test/library-tests/DataFlow/sources.expected +++ b/javascript/ql/test/library-tests/DataFlow/sources.expected @@ -1,3 +1,16 @@ +| arguments.js:1:1:1:0 | this | +| arguments.js:1:1:12:4 | (functi ... );\\n})() | +| arguments.js:1:2:1:1 | this | +| arguments.js:1:2:12:1 | functio ... , 3);\\n} | +| arguments.js:2:5:2:4 | this | +| arguments.js:2:5:10:5 | functio ... ;\\n } | +| arguments.js:2:16:2:16 | x | +| arguments.js:4:28:4:39 | arguments[0] | +| arguments.js:5:25:5:36 | arguments[1] | +| arguments.js:7:24:7:30 | args[2] | +| arguments.js:8:21:8:22 | {} | +| arguments.js:9:27:9:38 | arguments[0] | +| arguments.js:11:5:11:14 | f(1, 2, 3) | | eval.js:1:1:1:0 | this | | eval.js:1:1:1:0 | this | | eval.js:1:1:5:1 | functio ... eval`\\n} | From 215682f67cda4c1fbb67db5bd32f0845769b5152 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 26 May 2020 09:54:35 +0100 Subject: [PATCH 089/111] JavaScript: Add change note. --- change-notes/1.25/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0eb939d6801..049819d7687 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -47,6 +47,7 @@ | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | | Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more coding patterns that are vulnerable to prototype pollution. | The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): @@ -79,3 +80,4 @@ The following low-precision queries are no longer run by default on LGTM (their - `Parameter.flow()` now gets the correct data flow node for a parameter. Previously this had a result, but the node was disconnected from the data flow graph. - `ParameterNode.asExpr()` and `.getAstNode()` now gets the parameter's AST node, whereas previously it had no result. - `Expr.flow()` now has a more meaningful result for destructuring patterns. Previously this node was disconnected from the data flow graph. Now it represents the values being destructured by the pattern. +* The global data-flow and taint-tracking libraries now model indirect parameter accesses through the `arguments` object in some cases, which may lead to additional results from some of the security queries, particularly "Prototype pollution in utility function". From abfcc4213368d14fc1ef017e906ae1edce773a04 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 26 May 2020 09:56:24 +0100 Subject: [PATCH 090/111] JavaScript: Re-alphabetise change notes. --- change-notes/1.25/analysis-javascript.md | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 049819d7687..ff826af2f54 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -3,6 +3,7 @@ ## General improvements * Support for the following frameworks and libraries has been improved: + - [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) - [bluebird](http://bluebirdjs.com/) - [express](https://www.npmjs.com/package/express) - [fstream](https://www.npmjs.com/package/fstream) @@ -13,12 +14,11 @@ - [mssql](https://www.npmjs.com/package/mssql) - [mysql](https://www.npmjs.com/package/mysql) - [pg](https://www.npmjs.com/package/pg) - - [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) - [sequelize](https://www.npmjs.com/package/sequelize) - [spanner](https://www.npmjs.com/package/spanner) - [sqlite](https://www.npmjs.com/package/sqlite) - - [ssh2](https://www.npmjs.com/package/ssh2) - [ssh2-streams](https://www.npmjs.com/package/ssh2-streams) + - [ssh2](https://www.npmjs.com/package/ssh2) * TypeScript 3.9 is now supported. @@ -35,42 +35,42 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| -| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | -| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | -| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | | Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe strings based on URLs. | -| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | -| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | -| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | -| Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | -| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | -| Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | +| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | +| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | +| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more coding patterns that are vulnerable to prototype pollution. | +| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | +| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | +| Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | +| Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): - `js/angular/dead-event-listener` - `js/angular/unused-dependency` - - `js/conflicting-html-attribute` - - `js/useless-assignment-to-global` - - `js/too-many-parameters` - - `js/unused-property` - `js/bitwise-sign-check` - `js/comparison-of-identical-expressions` - - `js/misspelled-identifier` - - `js/jsdoc/malformed-param-tag` - - `js/jsdoc/unknown-parameter` - - `js/jsdoc/missing-parameter` - - `js/omitted-array-element` + - `js/conflicting-html-attribute` - `js/ignored-setter-parameter` + - `js/jsdoc/malformed-param-tag` + - `js/jsdoc/missing-parameter` + - `js/jsdoc/unknown-parameter` - `js/json-in-javascript-file` + - `js/misspelled-identifier` + - `js/nested-loops-with-same-variable` - `js/node/cyclic-import` - `js/node/unused-npm-dependency` - - `js/single-run-loop` - - `js/nested-loops-with-same-variable` + - `js/omitted-array-element` - `js/return-outside-function` + - `js/single-run-loop` + - `js/too-many-parameters` + - `js/unused-property` + - `js/useless-assignment-to-global` ## Changes to libraries From 5b0a3b9673db2bb15d26e10b11b19a125c00fe12 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 26 May 2020 09:57:53 +0100 Subject: [PATCH 091/111] JavaScript: Change "Less results" to "Fewer results" in change notes. --- change-notes/1.25/analysis-javascript.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index ff826af2f54..512db04a8de 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -35,18 +35,18 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| -| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | -| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe strings based on URLs. | +| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | +| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe strings based on URLs. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | -| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | +| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more coding patterns that are vulnerable to prototype pollution. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | -| Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | -| Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. | +| Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): From a9bea630192401958294f6e7cf588355e105a3f8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 12:36:24 +0200 Subject: [PATCH 092/111] recognize more HTML attribute concatenations --- .../IncompleteHtmlAttributeSanitizationCustomizations.qll | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll index ceb63d013f3..354ae02f9d5 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll @@ -51,8 +51,11 @@ module IncompleteHtmlAttributeSanitization { string lhs; HtmlAttributeConcatenation() { - lhs = this.getPreviousLeaf().getStringValue().regexpCapture("(.*)=\"[^\"]*", 1) and - this.getNextLeaf().getStringValue().regexpMatch(".*\".*") + lhs = this.getPreviousLeaf().getStringValue().regexpCapture("((?:[\n\r]|.)*)=\"[^\"]*", 1) and + ( + this.getNextLeaf().getStringValue().regexpMatch(".*\".*") or + this.getRoot().getConstantStringParts().regexpMatch("(?:[\n\r]|.)* Date: Tue, 26 May 2020 12:36:47 +0200 Subject: [PATCH 093/111] add a sanitizer guard for safe attribute string concatenations --- .../security/dataflow/DomBasedXss.qll | 4 ++ .../security/dataflow/ReflectedXss.qll | 4 ++ .../security/dataflow/StoredXss.qll | 4 ++ .../javascript/security/dataflow/Xss.qll | 38 +++++++++++++++++++ .../security/dataflow/XssThroughDom.qll | 3 +- .../query-tests/Security/CWE-079/Xss.expected | 11 ++++++ .../CWE-079/XssWithAdditionalSources.expected | 10 +++++ .../Security/CWE-079/stored-xss.js | 21 ++++++++++ 8 files changed, 94 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll index a1b2a4bf6d9..c0734b50fa3 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll @@ -24,6 +24,10 @@ module DomBasedXss { node instanceof Sanitizer } + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof SanitizerGuard + } + override predicate isAdditionalLoadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string predProp, string succProp ) { diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ReflectedXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ReflectedXss.qll index ece299d7fa0..b7034996a63 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ReflectedXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ReflectedXss.qll @@ -22,5 +22,9 @@ module ReflectedXss { super.isSanitizer(node) or node instanceof Sanitizer } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof SanitizerGuard + } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/StoredXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/StoredXss.qll index 7741d1e8778..9fbf0933042 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/StoredXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/StoredXss.qll @@ -22,6 +22,10 @@ module StoredXss { super.isSanitizer(node) or node instanceof Sanitizer } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof SanitizerGuard + } } /** A file name, considered as a flow source for stored XSS. */ diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 55be5464a6e..06d0ec53ee0 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -23,6 +23,9 @@ module Shared { /** A sanitizer for XSS vulnerabilities. */ abstract class Sanitizer extends DataFlow::Node { } + /** A sanitizer guard for XSS vulnerabilities. */ + abstract class SanitizerGuard extends TaintTracking::SanitizerGuardNode { } + /** * A regexp replacement involving an HTML meta-character, viewed as a sanitizer for * XSS vulnerabilities. @@ -51,10 +54,30 @@ module Shared { ) } } + + private import semmle.javascript.security.dataflow.IncompleteHtmlAttributeSanitizationCustomizations::IncompleteHtmlAttributeSanitization as IncompleteHTML + + /** + * A guard that checks if a string can contain quotes, which is a guard for strings that are inside a HTML attribute. + */ + class QuoteGuard extends SanitizerGuard, StringOps::Includes { + QuoteGuard() { + this.getSubstring().mayHaveStringValue("\"") and + this + .getBaseString() + .getALocalSource() + .flowsTo(any(IncompleteHTML::HtmlAttributeConcatenation attributeConcat)) + } + + override predicate sanitizes(boolean outcome, Expr e) { + e = this.getBaseString().getEnclosingExpr() and outcome = this.getPolarity().booleanNot() + } + } } /** Provides classes and predicates for the DOM-based XSS query. */ module DomBasedXss { + // StringReplaceCallSequence /** A data flow source for DOM-based XSS vulnerabilities. */ abstract class Source extends Shared::Source { } @@ -64,6 +87,9 @@ module DomBasedXss { /** A sanitizer for DOM-based XSS vulnerabilities. */ abstract class Sanitizer extends Shared::Sanitizer { } + /** A sanitizer guard for DOM-based XSS vulnerabilities. */ + abstract class SanitizerGuard extends Shared::SanitizerGuard { } + /** * An expression whose value is interpreted as HTML * and may be inserted into the DOM through a library. @@ -302,6 +328,8 @@ module DomBasedXss { private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { } private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + + private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } } /** Provides classes and predicates for the reflected XSS query. */ @@ -315,6 +343,9 @@ module ReflectedXss { /** A sanitizer for reflected XSS vulnerabilities. */ abstract class Sanitizer extends Shared::Sanitizer { } + /** A sanitizer guard for reflected XSS vulnerabilities. */ + abstract class SanitizerGuard extends Shared::SanitizerGuard { } + /** * An expression that is sent as part of an HTTP response, considered as an XSS sink. * @@ -401,6 +432,8 @@ module ReflectedXss { private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { } private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + + private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } } /** Provides classes and predicates for the stored XSS query. */ @@ -414,6 +447,9 @@ module StoredXss { /** A sanitizer for stored XSS vulnerabilities. */ abstract class Sanitizer extends Shared::Sanitizer { } + /** A sanitizer guard for stored XSS vulnerabilities. */ + abstract class SanitizerGuard extends Shared::SanitizerGuard { } + /** An arbitrary XSS sink, considered as a flow sink for stored XSS. */ private class AnySink extends Sink { AnySink() { this instanceof Shared::Sink } @@ -429,6 +465,8 @@ module StoredXss { private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { } private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + + private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } } /** Provides classes and predicates for the XSS through DOM query. */ diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll index 716002b7db6..881598b3e3d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll @@ -31,7 +31,8 @@ module XssThroughDom { override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { guard instanceof TypeTestGuard or - guard instanceof UnsafeJQuery::PropertyPresenceSanitizer + guard instanceof UnsafeJQuery::PropertyPresenceSanitizer or + guard instanceof DomBasedXss::SanitizerGuard } } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 9235b724e9d..9948a574f08 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -53,6 +53,11 @@ nodes | stored-xss.js:5:20:5:52 | session ... ssion') | | stored-xss.js:8:20:8:48 | localSt ... local') | | stored-xss.js:8:20:8:48 | localSt ... local') | +| stored-xss.js:10:9:10:44 | href | +| stored-xss.js:10:16:10:44 | localSt ... local') | +| stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:35:12:38 | href | | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:3:16:3:32 | document.location | @@ -431,6 +436,11 @@ edges | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:3:35:3:58 | documen ... .search | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | +| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:10:16:10:44 | localSt ... local') | +| stored-xss.js:10:9:10:44 | href | stored-xss.js:12:35:12:38 | href | +| stored-xss.js:10:16:10:44 | localSt ... local') | stored-xss.js:10:9:10:44 | href | +| stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | @@ -732,6 +742,7 @@ edges | react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | stored-xss.js:5:20:5:52 | session ... ssion') | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:5:20:5:52 | session ... ssion') | Cross-site scripting vulnerability due to $@. | stored-xss.js:2:39:2:55 | document.location | user-provided value | | stored-xss.js:8:20:8:48 | localSt ... local') | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:8:20:8:48 | localSt ... local') | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value | +| stored-xss.js:12:20:12:54 | "" | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:12:20:12:54 | "" | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value | | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | Cross-site scripting vulnerability due to $@. | string-manipulations.js:3:16:3:32 | document.location | user-provided value | | string-manipulations.js:4:16:4:37 | documen ... on.href | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | Cross-site scripting vulnerability due to $@. | string-manipulations.js:4:16:4:32 | document.location | user-provided value | | string-manipulations.js:5:16:5:47 | documen ... lueOf() | string-manipulations.js:5:16:5:32 | document.location | string-manipulations.js:5:16:5:47 | documen ... lueOf() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:5:16:5:32 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index a73dae129f2..3dfb4864440 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -53,6 +53,11 @@ nodes | stored-xss.js:5:20:5:52 | session ... ssion') | | stored-xss.js:8:20:8:48 | localSt ... local') | | stored-xss.js:8:20:8:48 | localSt ... local') | +| stored-xss.js:10:9:10:44 | href | +| stored-xss.js:10:16:10:44 | localSt ... local') | +| stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:35:12:38 | href | | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:3:16:3:32 | document.location | @@ -435,6 +440,11 @@ edges | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:3:35:3:58 | documen ... .search | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | +| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:10:16:10:44 | localSt ... local') | +| stored-xss.js:10:9:10:44 | href | stored-xss.js:12:35:12:38 | href | +| stored-xss.js:10:16:10:44 | localSt ... local') | stored-xss.js:10:9:10:44 | href | +| stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/stored-xss.js b/javascript/ql/test/query-tests/Security/CWE-079/stored-xss.js index 4a9cc51bce7..6c13ae8cc3e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/stored-xss.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/stored-xss.js @@ -6,4 +6,25 @@ $('myId').html(localStorage.getItem('session')); // OK $('myId').html(sessionStorage.getItem('local')); // OK $('myId').html(localStorage.getItem('local')); // NOT OK + + var href = localStorage.getItem('local'); + + $('myId').html("foobar"); // NOT OK + + if (href.indexOf("\"") !== -1) { + return; + } + $('myId').html(""); // OK + + var href2 = localStorage.getItem('local'); + if (href2.indexOf("\"") !== -1) { + return; + } + $('myId').html("\nfoobar"); // OK + + var href3 = localStorage.getItem('local'); + if (href3.indexOf("\"") !== -1) { + return; + } + $('myId').html('\r\n' + "something" + ''); // OK }); From 75fee22f1eeee2b0cdd3188779a9d839b81d7c4c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 26 May 2020 12:03:02 +0100 Subject: [PATCH 094/111] JS: Avoid string coercion in JSXName.getValue --- javascript/ql/src/semmle/javascript/JSX.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/JSX.qll b/javascript/ql/src/semmle/javascript/JSX.qll index 7684ef2b314..a8c1cfa86a2 100644 --- a/javascript/ql/src/semmle/javascript/JSX.qll +++ b/javascript/ql/src/semmle/javascript/JSX.qll @@ -196,7 +196,7 @@ class JSXName extends Expr { ) or exists(JSXQualifiedName qual | qual = this | - result = qual.getNamespace() + ":" + qual.getName() + result = qual.getNamespace().getName() + ":" + qual.getName().getName() ) } } From c5c3ffaef083d545311b7e399cb4e3cbf23aa7df Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 26 May 2020 13:14:11 +0200 Subject: [PATCH 095/111] C++: Add asPartialDefinition testcases --- .../fields/partial-definition-diff.expected | 390 ++++++++++++++++++ .../fields/partial-definition-diff.ql | 52 +++ .../fields/partial-definition-ir.expected | 0 .../dataflow/fields/partial-definition-ir.ql | 8 + .../fields/partial-definition.expected | 390 ++++++++++++++++++ .../dataflow/fields/partial-definition.ql | 8 + 6 files changed, 848 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected new file mode 100644 index 00000000000..51c175a8528 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -0,0 +1,390 @@ +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| * ... | AST only | +| * ... | AST only | +| * ... | AST only | +| * ... | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a_ | AST only | +| a_ | AST only | +| a_ | AST only | +| ab | AST only | +| ab | AST only | +| ab | AST only | +| ab | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b3 | AST only | +| b3 | AST only | +| b3 | AST only | +| b4 | AST only | +| b_ | AST only | +| b_ | AST only | +| b_ | AST only | +| box | AST only | +| box | AST only | +| box | AST only | +| box | AST only | +| box | AST only | +| box | AST only | +| box1 | AST only | +| box1 | AST only | +| box1 | AST only | +| box1 | AST only | +| box1 | AST only | +| boxfield | AST only | +| boxfield | AST only | +| boxfield | AST only | +| buffer | AST only | +| buffer | AST only | +| buffer | AST only | +| buffer | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c1 | AST only | +| c1 | AST only | +| c1 | AST only | +| c1 | AST only | +| call to get | AST only | +| call to get | AST only | +| call to getBox1 | AST only | +| call to getBox1 | AST only | +| call to getBox1 | AST only | +| call to getDirectly | AST only | +| call to getElem | AST only | +| call to getIndirectly | AST only | +| call to getInner | AST only | +| call to getInner | AST only | +| call to getInner | AST only | +| call to getInner | AST only | +| call to getThroughNonMember | AST only | +| call to nonMemberGetA | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| cc | AST only | +| copy1 | AST only | +| ct | AST only | +| d | AST only | +| d | AST only | +| data | AST only | +| data | AST only | +| e | AST only | +| e | AST only | +| e | AST only | +| e | AST only | +| elem | AST only | +| elem | AST only | +| elem | AST only | +| elem | AST only | +| elem | AST only | +| elem | AST only | +| elem1 | AST only | +| elem1 | AST only | +| elem1 | AST only | +| elem2 | AST only | +| elem2 | AST only | +| elem2 | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f1 | AST only | +| f2 | AST only | +| g | AST only | +| g | AST only | +| g | AST only | +| h | AST only | +| h | AST only | +| h | AST only | +| h | AST only | +| head | AST only | +| head | AST only | +| head | AST only | +| head | AST only | +| head | AST only | +| head | AST only | +| i | AST only | +| i | AST only | +| i | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| l | AST only | +| l1 | AST only | +| l2 | AST only | +| l3 | AST only | +| l3 | AST only | +| l3 | AST only | +| l3 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| nestedAB | AST only | +| nestedAB | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| p | AST only | +| p | AST only | +| pointerAB | AST only | +| pointerAB | AST only | +| pointerAB | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| raw | AST only | +| raw | AST only | +| ref1 | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s2 | AST only | +| s2 | AST only | +| s2 | AST only | +| s2 | AST only | +| s3 | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| value | AST only | +| value | AST only | +| w | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql new file mode 100644 index 00000000000..9607754d965 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql @@ -0,0 +1,52 @@ +/** + * @kind problem + */ + +import cpp +import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IR +import semmle.code.cpp.dataflow.DataFlow::DataFlow as AST + +newtype TNode = + TASTNode(AST::Node n) or + TIRNode(IR::Node n) + +class Node extends TNode { + string toString() { none() } + + IR::Node asIR() { none() } + + AST::Node asAST() { none() } +} + +class ASTNode extends Node, TASTNode { + AST::Node n; + + ASTNode() { this = TASTNode(n) } + + override string toString() { result = n.asPartialDefinition().toString() } + + override AST::Node asAST() { result = n } +} + +class IRNode extends Node, TIRNode { + IR::Node n; + + IRNode() { this = TIRNode(n) } + + override string toString() { result = n.asPartialDefinition().toString() } + + override IR::Node asIR() { result = n } +} + +from Node node, AST::Node astNode, IR::Node irNode, string msg +where + node.asIR() = irNode and + exists(irNode.asPartialDefinition()) and + not exists(AST::Node otherNode | otherNode.asPartialDefinition() = irNode.asPartialDefinition()) and + msg = "IR only" + or + node.asAST() = astNode and + exists(astNode.asPartialDefinition()) and + not exists(IR::Node otherNode | otherNode.asPartialDefinition() = astNode.asPartialDefinition()) and + msg = "AST only" +select node, msg diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql new file mode 100644 index 00000000000..0f0d3c41b88 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql @@ -0,0 +1,8 @@ +/** + * @kind problem + */ + +import cpp +import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow + +select any(Node n).asPartialDefinition() diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected new file mode 100644 index 00000000000..8ba1638dc8d --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -0,0 +1,390 @@ +| A.cpp:25:7:25:10 | this | +| A.cpp:25:13:25:13 | c | +| A.cpp:27:22:27:25 | this | +| A.cpp:27:28:27:28 | c | +| A.cpp:31:20:31:20 | c | +| A.cpp:40:5:40:6 | cc | +| A.cpp:41:5:41:6 | ct | +| A.cpp:42:10:42:12 | & ... | +| A.cpp:43:10:43:12 | & ... | +| A.cpp:48:20:48:20 | c | +| A.cpp:49:10:49:10 | b | +| A.cpp:49:13:49:13 | c | +| A.cpp:55:5:55:5 | b | +| A.cpp:56:10:56:10 | b | +| A.cpp:56:13:56:15 | call to get | +| A.cpp:57:28:57:30 | call to get | +| A.cpp:64:17:64:18 | b1 | +| A.cpp:65:10:65:11 | b1 | +| A.cpp:65:14:65:14 | c | +| A.cpp:66:10:66:11 | b2 | +| A.cpp:66:14:66:14 | c | +| A.cpp:73:21:73:22 | b1 | +| A.cpp:74:10:74:11 | b1 | +| A.cpp:74:14:74:14 | c | +| A.cpp:75:10:75:11 | b2 | +| A.cpp:75:14:75:14 | c | +| A.cpp:81:17:81:18 | b1 | +| A.cpp:81:21:81:21 | c | +| A.cpp:90:7:90:8 | b2 | +| A.cpp:90:15:90:15 | c | +| A.cpp:100:5:100:6 | c1 | +| A.cpp:100:9:100:9 | a | +| A.cpp:101:8:101:9 | c1 | +| A.cpp:107:12:107:13 | c1 | +| A.cpp:107:16:107:16 | a | +| A.cpp:120:12:120:13 | c1 | +| A.cpp:120:16:120:16 | a | +| A.cpp:126:5:126:5 | b | +| A.cpp:131:8:131:8 | b | +| A.cpp:132:10:132:10 | b | +| A.cpp:132:13:132:13 | c | +| A.cpp:142:7:142:7 | b | +| A.cpp:142:10:142:10 | c | +| A.cpp:143:7:143:10 | this | +| A.cpp:143:13:143:13 | b | +| A.cpp:151:18:151:18 | b | +| A.cpp:152:10:152:10 | d | +| A.cpp:152:13:152:13 | b | +| A.cpp:153:10:153:10 | d | +| A.cpp:153:13:153:13 | b | +| A.cpp:153:16:153:16 | c | +| A.cpp:154:10:154:10 | b | +| A.cpp:154:13:154:13 | c | +| A.cpp:160:29:160:29 | b | +| A.cpp:161:38:161:39 | l1 | +| A.cpp:162:38:162:39 | l2 | +| A.cpp:163:10:163:11 | l3 | +| A.cpp:163:14:163:17 | head | +| A.cpp:164:10:164:11 | l3 | +| A.cpp:164:14:164:17 | next | +| A.cpp:164:20:164:23 | head | +| A.cpp:165:10:165:11 | l3 | +| A.cpp:165:14:165:17 | next | +| A.cpp:165:20:165:23 | next | +| A.cpp:165:26:165:29 | head | +| A.cpp:166:10:166:11 | l3 | +| A.cpp:166:14:166:17 | next | +| A.cpp:166:20:166:23 | next | +| A.cpp:166:26:166:29 | next | +| A.cpp:166:32:166:35 | head | +| A.cpp:169:12:169:12 | l | +| A.cpp:169:15:169:18 | head | +| A.cpp:183:7:183:10 | head | +| A.cpp:184:7:184:10 | this | +| A.cpp:184:13:184:16 | next | +| B.cpp:7:25:7:25 | e | +| B.cpp:8:25:8:26 | b1 | +| B.cpp:9:10:9:11 | b2 | +| B.cpp:9:14:9:17 | box1 | +| B.cpp:9:20:9:24 | elem1 | +| B.cpp:10:10:10:11 | b2 | +| B.cpp:10:14:10:17 | box1 | +| B.cpp:10:20:10:24 | elem2 | +| B.cpp:16:37:16:37 | e | +| B.cpp:17:25:17:26 | b1 | +| B.cpp:18:10:18:11 | b2 | +| B.cpp:18:14:18:17 | box1 | +| B.cpp:18:20:18:24 | elem1 | +| B.cpp:19:10:19:11 | b2 | +| B.cpp:19:14:19:17 | box1 | +| B.cpp:19:20:19:24 | elem2 | +| B.cpp:35:7:35:10 | this | +| B.cpp:35:13:35:17 | elem1 | +| B.cpp:36:7:36:10 | this | +| B.cpp:36:13:36:17 | elem2 | +| B.cpp:46:7:46:10 | this | +| B.cpp:46:13:46:16 | box1 | +| C.cpp:19:5:19:5 | c | +| C.cpp:24:5:24:8 | this | +| C.cpp:24:11:24:12 | s3 | +| D.cpp:9:21:9:24 | elem | +| D.cpp:11:29:11:32 | elem | +| D.cpp:16:21:16:23 | box | +| D.cpp:18:29:18:31 | box | +| D.cpp:22:10:22:11 | b2 | +| D.cpp:22:14:22:20 | call to getBox1 | +| D.cpp:22:25:22:31 | call to getElem | +| D.cpp:30:5:30:5 | b | +| D.cpp:30:8:30:10 | box | +| D.cpp:30:13:30:16 | elem | +| D.cpp:31:14:31:14 | b | +| D.cpp:37:5:37:5 | b | +| D.cpp:37:8:37:10 | box | +| D.cpp:37:21:37:21 | e | +| D.cpp:38:14:38:14 | b | +| D.cpp:44:5:44:5 | b | +| D.cpp:44:8:44:14 | call to getBox1 | +| D.cpp:44:19:44:22 | elem | +| D.cpp:45:14:45:14 | b | +| D.cpp:51:5:51:5 | b | +| D.cpp:51:8:51:14 | call to getBox1 | +| D.cpp:51:27:51:27 | e | +| D.cpp:52:14:52:14 | b | +| D.cpp:57:5:57:12 | boxfield | +| D.cpp:58:5:58:12 | boxfield | +| D.cpp:58:15:58:17 | box | +| D.cpp:58:20:58:23 | elem | +| D.cpp:64:10:64:17 | boxfield | +| D.cpp:64:20:64:22 | box | +| D.cpp:64:25:64:28 | elem | +| E.cpp:21:10:21:10 | p | +| E.cpp:21:13:21:16 | data | +| E.cpp:21:18:21:23 | buffer | +| E.cpp:28:21:28:23 | raw | +| E.cpp:29:21:29:21 | b | +| E.cpp:29:24:29:29 | buffer | +| E.cpp:30:21:30:21 | p | +| E.cpp:30:23:30:26 | data | +| E.cpp:30:28:30:33 | buffer | +| E.cpp:31:10:31:12 | raw | +| E.cpp:32:10:32:10 | b | +| E.cpp:32:13:32:18 | buffer | +| E.cpp:33:18:33:19 | & ... | +| aliasing.cpp:9:3:9:3 | s | +| aliasing.cpp:9:6:9:7 | m1 | +| aliasing.cpp:13:3:13:3 | s | +| aliasing.cpp:13:5:13:6 | m1 | +| aliasing.cpp:17:3:17:3 | s | +| aliasing.cpp:17:5:17:6 | m1 | +| aliasing.cpp:25:17:25:19 | & ... | +| aliasing.cpp:26:19:26:20 | s2 | +| aliasing.cpp:37:3:37:6 | ref1 | +| aliasing.cpp:37:8:37:9 | m1 | +| aliasing.cpp:42:3:42:4 | s2 | +| aliasing.cpp:42:6:42:7 | m1 | +| aliasing.cpp:49:3:49:7 | copy1 | +| aliasing.cpp:49:9:49:10 | m1 | +| aliasing.cpp:54:3:54:4 | s2 | +| aliasing.cpp:54:6:54:7 | m1 | +| aliasing.cpp:60:3:60:4 | s2 | +| aliasing.cpp:60:6:60:7 | m1 | +| aliasing.cpp:72:3:72:3 | s | +| aliasing.cpp:72:5:72:6 | m1 | +| aliasing.cpp:79:3:79:3 | s | +| aliasing.cpp:79:6:79:7 | m1 | +| aliasing.cpp:86:3:86:3 | s | +| aliasing.cpp:86:5:86:6 | m1 | +| aliasing.cpp:92:3:92:3 | w | +| aliasing.cpp:92:5:92:5 | s | +| aliasing.cpp:92:7:92:8 | m1 | +| by_reference.cpp:12:5:12:5 | s | +| by_reference.cpp:12:8:12:8 | a | +| by_reference.cpp:16:5:16:8 | this | +| by_reference.cpp:16:11:16:11 | a | +| by_reference.cpp:20:5:20:8 | this | +| by_reference.cpp:20:23:20:27 | value | +| by_reference.cpp:24:19:24:22 | this | +| by_reference.cpp:24:25:24:29 | value | +| by_reference.cpp:50:3:50:3 | s | +| by_reference.cpp:50:17:50:26 | call to user_input | +| by_reference.cpp:51:10:51:20 | call to getDirectly | +| by_reference.cpp:56:3:56:3 | s | +| by_reference.cpp:56:19:56:28 | call to user_input | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | s | +| by_reference.cpp:62:25:62:34 | call to user_input | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | +| by_reference.cpp:68:17:68:18 | & ... | +| by_reference.cpp:68:21:68:30 | call to user_input | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:7 | inner | +| by_reference.cpp:84:10:84:10 | a | +| by_reference.cpp:88:3:88:7 | inner | +| by_reference.cpp:88:9:88:9 | a | +| by_reference.cpp:102:21:102:39 | & ... | +| by_reference.cpp:102:22:102:26 | outer | +| by_reference.cpp:103:21:103:25 | outer | +| by_reference.cpp:103:27:103:35 | inner_ptr | +| by_reference.cpp:104:15:104:22 | & ... | +| by_reference.cpp:104:16:104:20 | outer | +| by_reference.cpp:106:21:106:41 | & ... | +| by_reference.cpp:106:22:106:27 | pouter | +| by_reference.cpp:107:21:107:26 | pouter | +| by_reference.cpp:107:29:107:37 | inner_ptr | +| by_reference.cpp:108:15:108:24 | & ... | +| by_reference.cpp:108:16:108:21 | pouter | +| by_reference.cpp:110:8:110:12 | outer | +| by_reference.cpp:110:14:110:25 | inner_nested | +| by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:111:8:111:12 | outer | +| by_reference.cpp:111:14:111:22 | inner_ptr | +| by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:112:8:112:12 | outer | +| by_reference.cpp:112:14:112:14 | a | +| by_reference.cpp:114:8:114:13 | pouter | +| by_reference.cpp:114:16:114:27 | inner_nested | +| by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:115:8:115:13 | pouter | +| by_reference.cpp:115:16:115:24 | inner_ptr | +| by_reference.cpp:115:27:115:27 | a | +| by_reference.cpp:116:8:116:13 | pouter | +| by_reference.cpp:116:16:116:16 | a | +| by_reference.cpp:122:21:122:25 | outer | +| by_reference.cpp:122:27:122:38 | inner_nested | +| by_reference.cpp:123:21:123:36 | * ... | +| by_reference.cpp:123:22:123:26 | outer | +| by_reference.cpp:124:15:124:19 | outer | +| by_reference.cpp:124:21:124:21 | a | +| by_reference.cpp:126:21:126:26 | pouter | +| by_reference.cpp:126:29:126:40 | inner_nested | +| by_reference.cpp:127:21:127:38 | * ... | +| by_reference.cpp:127:22:127:27 | pouter | +| by_reference.cpp:128:15:128:20 | pouter | +| by_reference.cpp:128:23:128:23 | a | +| by_reference.cpp:130:8:130:12 | outer | +| by_reference.cpp:130:14:130:25 | inner_nested | +| by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:131:8:131:12 | outer | +| by_reference.cpp:131:14:131:22 | inner_ptr | +| by_reference.cpp:131:25:131:25 | a | +| by_reference.cpp:132:8:132:12 | outer | +| by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:134:8:134:13 | pouter | +| by_reference.cpp:134:16:134:27 | inner_nested | +| by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:135:8:135:13 | pouter | +| by_reference.cpp:135:16:135:24 | inner_ptr | +| by_reference.cpp:135:27:135:27 | a | +| by_reference.cpp:136:8:136:13 | pouter | +| by_reference.cpp:136:16:136:16 | a | +| complex.cpp:11:22:11:23 | a_ | +| complex.cpp:12:22:12:23 | b_ | +| complex.cpp:51:8:51:8 | b | +| complex.cpp:51:10:51:14 | inner | +| complex.cpp:51:16:51:16 | f | +| complex.cpp:52:8:52:8 | b | +| complex.cpp:52:10:52:14 | inner | +| complex.cpp:52:16:52:16 | f | +| complex.cpp:62:3:62:4 | b1 | +| complex.cpp:62:6:62:10 | inner | +| complex.cpp:62:12:62:12 | f | +| complex.cpp:63:3:63:4 | b2 | +| complex.cpp:63:6:63:10 | inner | +| complex.cpp:63:12:63:12 | f | +| complex.cpp:64:3:64:4 | b3 | +| complex.cpp:64:6:64:10 | inner | +| complex.cpp:64:12:64:12 | f | +| complex.cpp:65:3:65:4 | b3 | +| complex.cpp:65:6:65:10 | inner | +| complex.cpp:65:12:65:12 | f | +| complex.cpp:68:7:68:8 | b1 | +| complex.cpp:71:7:71:8 | b2 | +| complex.cpp:74:7:74:8 | b3 | +| complex.cpp:77:7:77:8 | b4 | +| constructors.cpp:20:24:20:25 | a_ | +| constructors.cpp:21:24:21:25 | b_ | +| constructors.cpp:28:10:28:10 | f | +| constructors.cpp:29:10:29:10 | f | +| constructors.cpp:40:9:40:9 | f | +| constructors.cpp:43:9:43:9 | g | +| constructors.cpp:46:9:46:9 | h | +| constructors.cpp:49:9:49:9 | i | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| qualifiers.cpp:9:30:9:33 | this | +| qualifiers.cpp:9:36:9:36 | a | +| qualifiers.cpp:12:49:12:53 | inner | +| qualifiers.cpp:12:56:12:56 | a | +| qualifiers.cpp:13:51:13:55 | inner | +| qualifiers.cpp:13:57:13:57 | a | +| qualifiers.cpp:22:5:22:9 | outer | +| qualifiers.cpp:22:11:22:18 | call to getInner | +| qualifiers.cpp:22:23:22:23 | a | +| qualifiers.cpp:23:10:23:14 | outer | +| qualifiers.cpp:23:16:23:20 | inner | +| qualifiers.cpp:23:23:23:23 | a | +| qualifiers.cpp:27:5:27:9 | outer | +| qualifiers.cpp:27:11:27:18 | call to getInner | +| qualifiers.cpp:27:28:27:37 | call to user_input | +| qualifiers.cpp:28:10:28:14 | outer | +| qualifiers.cpp:28:16:28:20 | inner | +| qualifiers.cpp:28:23:28:23 | a | +| qualifiers.cpp:32:17:32:21 | outer | +| qualifiers.cpp:32:23:32:30 | call to getInner | +| qualifiers.cpp:32:35:32:44 | call to user_input | +| qualifiers.cpp:33:10:33:14 | outer | +| qualifiers.cpp:33:16:33:20 | inner | +| qualifiers.cpp:33:23:33:23 | a | +| qualifiers.cpp:37:19:37:35 | * ... | +| qualifiers.cpp:37:20:37:24 | outer | +| qualifiers.cpp:37:38:37:47 | call to user_input | +| qualifiers.cpp:38:10:38:14 | outer | +| qualifiers.cpp:38:16:38:20 | inner | +| qualifiers.cpp:38:23:38:23 | a | +| qualifiers.cpp:42:6:42:22 | * ... | +| qualifiers.cpp:42:7:42:11 | outer | +| qualifiers.cpp:42:25:42:25 | a | +| qualifiers.cpp:43:10:43:14 | outer | +| qualifiers.cpp:43:16:43:20 | inner | +| qualifiers.cpp:43:23:43:23 | a | +| qualifiers.cpp:47:6:47:11 | & ... | +| qualifiers.cpp:47:15:47:22 | call to getInner | +| qualifiers.cpp:47:27:47:27 | a | +| qualifiers.cpp:48:10:48:14 | outer | +| qualifiers.cpp:48:16:48:20 | inner | +| qualifiers.cpp:48:23:48:23 | a | +| simple.cpp:20:24:20:25 | a_ | +| simple.cpp:21:24:21:25 | b_ | +| simple.cpp:28:10:28:10 | f | +| simple.cpp:29:10:29:10 | f | +| simple.cpp:39:5:39:5 | f | +| simple.cpp:40:5:40:5 | g | +| simple.cpp:41:5:41:5 | h | +| simple.cpp:42:5:42:5 | h | +| simple.cpp:45:9:45:9 | f | +| simple.cpp:48:9:48:9 | g | +| simple.cpp:51:9:51:9 | h | +| simple.cpp:54:9:54:9 | i | +| simple.cpp:65:5:65:5 | a | +| simple.cpp:65:7:65:7 | i | +| simple.cpp:83:9:83:10 | f2 | +| simple.cpp:83:12:83:13 | f1 | +| struct_init.c:15:8:15:9 | ab | +| struct_init.c:15:12:15:12 | a | +| struct_init.c:16:8:16:9 | ab | +| struct_init.c:16:12:16:12 | b | +| struct_init.c:22:8:22:9 | ab | +| struct_init.c:22:11:22:11 | a | +| struct_init.c:23:8:23:9 | ab | +| struct_init.c:23:11:23:11 | b | +| struct_init.c:24:10:24:12 | & ... | +| struct_init.c:31:8:31:12 | outer | +| struct_init.c:31:14:31:21 | nestedAB | +| struct_init.c:31:23:31:23 | a | +| struct_init.c:32:8:32:12 | outer | +| struct_init.c:32:14:32:21 | nestedAB | +| struct_init.c:32:23:32:23 | b | +| struct_init.c:33:8:33:12 | outer | +| struct_init.c:33:14:33:22 | pointerAB | +| struct_init.c:33:25:33:25 | a | +| struct_init.c:34:8:34:12 | outer | +| struct_init.c:34:14:34:22 | pointerAB | +| struct_init.c:34:25:34:25 | b | +| struct_init.c:36:10:36:24 | & ... | +| struct_init.c:36:11:36:15 | outer | +| struct_init.c:46:10:46:14 | outer | +| struct_init.c:46:16:46:24 | pointerAB | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql new file mode 100644 index 00000000000..8acd1f3e5fe --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql @@ -0,0 +1,8 @@ +/** + * @kind problem + */ + +import cpp +import semmle.code.cpp.dataflow.DataFlow::DataFlow + +select any(Node n).asPartialDefinition() From 251240376bb5de23467e7e497a2bff727f863c12 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 26 May 2020 13:14:38 +0200 Subject: [PATCH 096/111] C++: Fix asPartialDefinition for IR dataflow nodes and accept testcases --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 28 ++++++++++++------- .../fields/partial-definition-diff.expected | 20 ------------- .../fields/partial-definition-ir.expected | 20 +++++++++++++ 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9f9659a506e..e8c63469c2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -71,9 +71,7 @@ class Node extends TIRDataFlowNode { * `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is * a partial definition of `&x`). */ - Expr asPartialDefinition() { - result = this.(PartialDefinitionNode).getInstruction().getUnconvertedResultExpression() - } + Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() } /** * DEPRECATED: See UninitializedNode. @@ -251,14 +249,17 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } +abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { + abstract Expr getDefinedExpr(); +} -private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { +class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; + FieldAddressInstruction field; ExplicitFieldStoreQualifierNode() { not instr.isResultConflated() and - exists(StoreInstruction store, FieldInstruction field | + exists(StoreInstruction store | instr.getPartial() = store and field = store.getDestinationAddress() ) } @@ -268,6 +269,10 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications // this consistency failure has. override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } } /** @@ -278,15 +283,18 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { */ private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { override StoreInstruction instr; + FieldAddressInstruction field; ExplicitSingleFieldStoreQualifierNode() { - exists(FieldAddressInstruction field | - field = instr.getDestinationAddress() and - not exists(ChiInstruction chi | chi.getPartial() = instr) - ) + field = instr.getDestinationAddress() and + not exists(ChiInstruction chi | chi.getPartial() = instr) } override Node getPreUpdateNode() { none() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } } /** diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 51c175a8528..20da36f2dde 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -51,7 +51,6 @@ | a | AST only | | a | AST only | | a | AST only | -| a | AST only | | a_ | AST only | | a_ | AST only | | a_ | AST only | @@ -87,7 +86,6 @@ | b | AST only | | b | AST only | | b | AST only | -| b | AST only | | b1 | AST only | | b1 | AST only | | b1 | AST only | @@ -151,7 +149,6 @@ | c1 | AST only | | c1 | AST only | | c1 | AST only | -| c1 | AST only | | call to get | AST only | | call to get | AST only | | call to getBox1 | AST only | @@ -174,7 +171,6 @@ | call to user_input | AST only | | call to user_input | AST only | | cc | AST only | -| copy1 | AST only | | ct | AST only | | d | AST only | | d | AST only | @@ -239,10 +235,6 @@ | inner | AST only | | inner | AST only | | inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | | inner_nested | AST only | | inner_nested | AST only | | inner_nested | AST only | @@ -331,21 +323,9 @@ | pouter | AST only | | raw | AST only | | raw | AST only | -| ref1 | AST only | | s | AST only | | s | AST only | | s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s2 | AST only | -| s2 | AST only | -| s2 | AST only | | s2 | AST only | | s3 | AST only | | this | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index e69de29bb2d..fdaab4a95e9 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -0,0 +1,20 @@ +| A.cpp:100:5:100:6 | c1 | +| A.cpp:142:7:142:7 | b | +| aliasing.cpp:9:3:9:3 | s | +| aliasing.cpp:13:3:13:3 | s | +| aliasing.cpp:17:3:17:3 | s | +| aliasing.cpp:37:3:37:6 | ref1 | +| aliasing.cpp:42:3:42:4 | s2 | +| aliasing.cpp:49:3:49:7 | copy1 | +| aliasing.cpp:54:3:54:4 | s2 | +| aliasing.cpp:60:3:60:4 | s2 | +| aliasing.cpp:72:3:72:3 | s | +| aliasing.cpp:79:3:79:3 | s | +| aliasing.cpp:86:3:86:3 | s | +| aliasing.cpp:92:5:92:5 | s | +| by_reference.cpp:12:5:12:5 | s | +| by_reference.cpp:84:3:84:7 | inner | +| by_reference.cpp:88:3:88:7 | inner | +| qualifiers.cpp:12:49:12:53 | inner | +| qualifiers.cpp:13:51:13:55 | inner | +| simple.cpp:65:5:65:5 | a | From 3e3372be4bfa24be47b881dad3ef65634ba5c888 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 13:34:33 +0200 Subject: [PATCH 097/111] recognize DOMPurify.sanitize as a HTML sanitizer --- javascript/ql/src/semmle/javascript/HtmlSanitizers.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll b/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll index 47f88f0390c..870cde4bbce 100644 --- a/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll +++ b/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll @@ -48,6 +48,11 @@ private class DefaultHtmlSanitizerCall extends HtmlSanitizerCall { or callee = LodashUnderscore::member("escape") or + exists(DataFlow::PropRead read | read = callee | + read.getPropertyName() = "sanitize" and + read.getBase().asExpr().(VarAccess).getName() = "DOMPurify" + ) + or exists(string name | name = "encode" or name = "encodeNonUTF" | callee = DataFlow::moduleMember("html-entities", _).getAnInstantiation().getAPropertyRead(name) or From e5afdc53bebeb6510c53a0f33dac9e7c27964108 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 13:34:49 +0200 Subject: [PATCH 098/111] use HtmlSanitizerCall to recognize sanitizers --- .../ql/src/semmle/javascript/security/dataflow/Xss.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index c3056527cef..663e2794f57 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -304,12 +304,10 @@ module DomBasedXss { private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } /** - * Holds if there exists two dataflow edges to `succ`, where one edges is sanitized, and the other edge starts with `pred`. + * Holds if there exists two dataflow edges to `succ`, where one edges is sanitized, and the other edge starts with `pred`. */ predicate isOptionallySanitizedEdge(DataFlow::Node pred, DataFlow::Node succ) { - exists(DataFlow::CallNode sanitizer | - sanitizer.getCalleeName().regexpMatch("(?i).*sanitize.*") - | + exists(HtmlSanitizerCall sanitizer | // sanitized = sanitize ? sanitizer(source) : source; exists(ConditionalExpr branch, Variable var, VarAccess access | branch = succ.asExpr() and access = var.getAnAccess() From 08fa3141cdafde38630c7e126e05b47a77918dec Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 26 May 2020 14:15:46 +0200 Subject: [PATCH 099/111] C++: Fix accidential removal of private annotations --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index e8c63469c2f..94b03eb47ad 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -249,11 +249,11 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { +abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { abstract Expr getDefinedExpr(); } -class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { +private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; FieldAddressInstruction field; From 0c003315271ddbc4f3ba3bbd2f57c0e4fc33737e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 14:30:29 +0200 Subject: [PATCH 100/111] less -> fewer Co-authored-by: Asger F --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0beabeb8c62..ac76e7ffe56 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -36,7 +36,7 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| -| Client-side cross-site scripting (`js/xss`) | Less results | This query no longer flags optionally sanitized values. | +| Client-side cross-site scripting (`js/xss`) | Fewer results | This query no longer flags optionally sanitized values. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | | Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe strings based on URLs. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | From fd561d1ce297091e170fecf4dd1b446fbbf80dc1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 14:37:02 +0200 Subject: [PATCH 101/111] remove temporary comment Co-authored-by: Asger F --- javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 06d0ec53ee0..3eed799f070 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -77,7 +77,6 @@ module Shared { /** Provides classes and predicates for the DOM-based XSS query. */ module DomBasedXss { - // StringReplaceCallSequence /** A data flow source for DOM-based XSS vulnerabilities. */ abstract class Source extends Shared::Source { } From 9b047f6f03554b03086052b640e67fbdca3ce657 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 14:41:16 +0200 Subject: [PATCH 102/111] use the DOTALL flag --- .../IncompleteHtmlAttributeSanitizationCustomizations.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll index 354ae02f9d5..446f55d3aa0 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll @@ -51,10 +51,10 @@ module IncompleteHtmlAttributeSanitization { string lhs; HtmlAttributeConcatenation() { - lhs = this.getPreviousLeaf().getStringValue().regexpCapture("((?:[\n\r]|.)*)=\"[^\"]*", 1) and + lhs = this.getPreviousLeaf().getStringValue().regexpCapture("(?s)(.*)=\"[^\"]*", 1) and ( this.getNextLeaf().getStringValue().regexpMatch(".*\".*") or - this.getRoot().getConstantStringParts().regexpMatch("(?:[\n\r]|.)* Date: Tue, 26 May 2020 18:33:29 +0200 Subject: [PATCH 103/111] use HtmlConcatenationLeaf --- .../IncompleteHtmlAttributeSanitizationCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll index 446f55d3aa0..cd1d9c1cc6c 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll @@ -54,7 +54,7 @@ module IncompleteHtmlAttributeSanitization { lhs = this.getPreviousLeaf().getStringValue().regexpCapture("(?s)(.*)=\"[^\"]*", 1) and ( this.getNextLeaf().getStringValue().regexpMatch(".*\".*") or - this.getRoot().getConstantStringParts().regexpMatch("(?s).* Date: Tue, 26 May 2020 18:47:04 +0200 Subject: [PATCH 104/111] update expected output --- .../ql/test/query-tests/Security/CWE-079/Xss.expected | 8 ++++++++ .../Security/CWE-079/XssWithAdditionalSources.expected | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 46d4d571144..f16568124ae 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -76,6 +76,7 @@ nodes | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:45:51:45:56 | target | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -473,12 +474,15 @@ edges | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:31:18:31:23 | target | | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:38:18:38:23 | target | | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:51:45:56 | target | | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | | optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:26:7:26:39 | target | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | | optionalSanitizer.js:31:18:31:23 | target | optionalSanitizer.js:31:7:31:23 | tainted2 | | optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | | optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | @@ -487,6 +491,8 @@ edges | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | | optionalSanitizer.js:38:18:38:23 | target | optionalSanitizer.js:38:7:38:23 | tainted3 | | optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | | optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | @@ -495,6 +501,8 @@ edges | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | +| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index 4f70a16f0c8..da33bf9332f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -76,6 +76,7 @@ nodes | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:45:51:45:56 | target | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -477,12 +478,15 @@ edges | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:31:18:31:23 | target | | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:38:18:38:23 | target | | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:51:45:56 | target | | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | | optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:26:7:26:39 | target | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | | optionalSanitizer.js:31:18:31:23 | target | optionalSanitizer.js:31:7:31:23 | tainted2 | | optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | | optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | @@ -491,6 +495,8 @@ edges | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | | optionalSanitizer.js:38:18:38:23 | target | optionalSanitizer.js:38:7:38:23 | tainted3 | | optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | | optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | @@ -499,6 +505,8 @@ edges | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | +| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | From d96bf797ef282f4d63f2a2d981d3b4a8a0592b20 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 29 Jan 2020 15:03:03 +0000 Subject: [PATCH 105/111] C++: Test layout. --- .../dataflow/taint-tests/format.cpp | 4 + .../dataflow/taint-tests/localTaint.expected | 212 +++++++++--------- .../dataflow/taint-tests/taint.expected | 20 +- .../dataflow/taint-tests/test_diff.expected | 20 +- 4 files changed, 130 insertions(+), 126 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp index 2080707f17f..7271cbbf85e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp @@ -15,10 +15,14 @@ int vsnprintf(char *s, size_t n, const char *format, va_list arg); int mysprintf(char *s, size_t n, const char *format, ...) { + + va_list args; va_start(args, format); vsnprintf(s, n, format, args); va_end(args); + + } int sscanf(const char *s, const char *format, ...); diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index 764cc9f24e9..8d16904e0ba 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3,112 +3,112 @@ | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | -| format.cpp:16:21:16:21 | s | format.cpp:20:13:20:13 | s | | -| format.cpp:16:31:16:31 | n | format.cpp:20:16:20:16 | n | | -| format.cpp:16:46:16:51 | format | format.cpp:20:19:20:24 | format | | -| format.cpp:18:10:18:13 | args | format.cpp:20:27:20:30 | args | | -| format.cpp:46:21:46:24 | {...} | format.cpp:47:17:47:22 | buffer | | -| format.cpp:46:21:46:24 | {...} | format.cpp:48:8:48:13 | buffer | | -| format.cpp:46:23:46:23 | 0 | format.cpp:46:21:46:24 | {...} | TAINT | -| format.cpp:47:17:47:22 | ref arg buffer | format.cpp:48:8:48:13 | buffer | | -| format.cpp:47:30:47:33 | %s | format.cpp:47:17:47:22 | ref arg buffer | TAINT | -| format.cpp:47:36:47:43 | Hello. | format.cpp:47:17:47:22 | ref arg buffer | TAINT | -| format.cpp:51:21:51:24 | {...} | format.cpp:52:17:52:22 | buffer | | -| format.cpp:51:21:51:24 | {...} | format.cpp:53:8:53:13 | buffer | | -| format.cpp:51:23:51:23 | 0 | format.cpp:51:21:51:24 | {...} | TAINT | -| format.cpp:52:17:52:22 | ref arg buffer | format.cpp:53:8:53:13 | buffer | | -| format.cpp:52:30:52:33 | %s | format.cpp:52:17:52:22 | ref arg buffer | TAINT | -| format.cpp:52:36:52:49 | call to source | format.cpp:52:17:52:22 | ref arg buffer | TAINT | -| format.cpp:56:21:56:24 | {...} | format.cpp:57:17:57:22 | buffer | | -| format.cpp:56:21:56:24 | {...} | format.cpp:58:8:58:13 | buffer | | -| format.cpp:56:23:56:23 | 0 | format.cpp:56:21:56:24 | {...} | TAINT | -| format.cpp:57:17:57:22 | ref arg buffer | format.cpp:58:8:58:13 | buffer | | -| format.cpp:57:30:57:43 | call to source | format.cpp:57:17:57:22 | ref arg buffer | TAINT | -| format.cpp:57:48:57:55 | Hello. | format.cpp:57:17:57:22 | ref arg buffer | TAINT | -| format.cpp:61:21:61:24 | {...} | format.cpp:62:17:62:22 | buffer | | -| format.cpp:61:21:61:24 | {...} | format.cpp:63:8:63:13 | buffer | | -| format.cpp:61:23:61:23 | 0 | format.cpp:61:21:61:24 | {...} | TAINT | -| format.cpp:62:17:62:22 | ref arg buffer | format.cpp:63:8:63:13 | buffer | | -| format.cpp:62:30:62:39 | %s %s %s | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:62:42:62:44 | a | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:62:47:62:49 | b | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:62:52:62:65 | call to source | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:66:21:66:24 | {...} | format.cpp:67:17:67:22 | buffer | | -| format.cpp:66:21:66:24 | {...} | format.cpp:68:8:68:13 | buffer | | -| format.cpp:66:23:66:23 | 0 | format.cpp:66:21:66:24 | {...} | TAINT | -| format.cpp:67:17:67:22 | ref arg buffer | format.cpp:68:8:68:13 | buffer | | -| format.cpp:67:30:67:35 | %.*s | format.cpp:67:17:67:22 | ref arg buffer | TAINT | -| format.cpp:67:38:67:39 | 10 | format.cpp:67:17:67:22 | ref arg buffer | TAINT | -| format.cpp:67:42:67:55 | call to source | format.cpp:67:17:67:22 | ref arg buffer | TAINT | -| format.cpp:72:21:72:24 | {...} | format.cpp:73:17:73:22 | buffer | | -| format.cpp:72:21:72:24 | {...} | format.cpp:74:8:74:13 | buffer | | -| format.cpp:72:23:72:23 | 0 | format.cpp:72:21:72:24 | {...} | TAINT | -| format.cpp:73:17:73:22 | ref arg buffer | format.cpp:74:8:74:13 | buffer | | -| format.cpp:73:30:73:33 | %i | format.cpp:73:17:73:22 | ref arg buffer | TAINT | -| format.cpp:73:36:73:36 | 0 | format.cpp:73:17:73:22 | ref arg buffer | TAINT | -| format.cpp:77:21:77:24 | {...} | format.cpp:78:17:78:22 | buffer | | -| format.cpp:77:21:77:24 | {...} | format.cpp:79:8:79:13 | buffer | | -| format.cpp:77:23:77:23 | 0 | format.cpp:77:21:77:24 | {...} | TAINT | -| format.cpp:78:17:78:22 | ref arg buffer | format.cpp:79:8:79:13 | buffer | | -| format.cpp:78:30:78:33 | %i | format.cpp:78:17:78:22 | ref arg buffer | TAINT | -| format.cpp:78:36:78:41 | call to source | format.cpp:78:17:78:22 | ref arg buffer | TAINT | -| format.cpp:82:21:82:24 | {...} | format.cpp:83:17:83:22 | buffer | | -| format.cpp:82:21:82:24 | {...} | format.cpp:84:8:84:13 | buffer | | -| format.cpp:82:23:82:23 | 0 | format.cpp:82:21:82:24 | {...} | TAINT | -| format.cpp:83:17:83:22 | ref arg buffer | format.cpp:84:8:84:13 | buffer | | -| format.cpp:83:30:83:35 | %.*s | format.cpp:83:17:83:22 | ref arg buffer | TAINT | -| format.cpp:83:38:83:43 | call to source | format.cpp:83:17:83:22 | ref arg buffer | TAINT | -| format.cpp:83:48:83:55 | Hello. | format.cpp:83:17:83:22 | ref arg buffer | TAINT | -| format.cpp:88:21:88:24 | {...} | format.cpp:89:17:89:22 | buffer | | -| format.cpp:88:21:88:24 | {...} | format.cpp:90:8:90:13 | buffer | | -| format.cpp:88:23:88:23 | 0 | format.cpp:88:21:88:24 | {...} | TAINT | -| format.cpp:89:17:89:22 | ref arg buffer | format.cpp:90:8:90:13 | buffer | | -| format.cpp:89:30:89:33 | %p | format.cpp:89:17:89:22 | ref arg buffer | TAINT | -| format.cpp:89:36:89:49 | call to source | format.cpp:89:17:89:22 | ref arg buffer | TAINT | -| format.cpp:94:21:94:24 | {...} | format.cpp:95:16:95:21 | buffer | | -| format.cpp:94:21:94:24 | {...} | format.cpp:96:8:96:13 | buffer | | -| format.cpp:94:23:94:23 | 0 | format.cpp:94:21:94:24 | {...} | TAINT | -| format.cpp:95:16:95:21 | ref arg buffer | format.cpp:96:8:96:13 | buffer | | -| format.cpp:95:24:95:27 | %s | format.cpp:95:16:95:21 | ref arg buffer | TAINT | -| format.cpp:95:30:95:43 | call to source | format.cpp:95:16:95:21 | ref arg buffer | TAINT | -| format.cpp:99:21:99:24 | {...} | format.cpp:100:16:100:21 | buffer | | -| format.cpp:99:21:99:24 | {...} | format.cpp:101:8:101:13 | buffer | | -| format.cpp:99:23:99:23 | 0 | format.cpp:99:21:99:24 | {...} | TAINT | -| format.cpp:100:16:100:21 | ref arg buffer | format.cpp:101:8:101:13 | buffer | | -| format.cpp:100:24:100:28 | %ls | format.cpp:100:16:100:21 | ref arg buffer | TAINT | -| format.cpp:100:31:100:45 | call to source | format.cpp:100:16:100:21 | ref arg buffer | TAINT | -| format.cpp:104:25:104:28 | {...} | format.cpp:105:17:105:23 | wbuffer | | -| format.cpp:104:25:104:28 | {...} | format.cpp:106:8:106:14 | wbuffer | | -| format.cpp:104:27:104:27 | 0 | format.cpp:104:25:104:28 | {...} | TAINT | -| format.cpp:105:17:105:23 | ref arg wbuffer | format.cpp:106:8:106:14 | wbuffer | | -| format.cpp:105:31:105:35 | %s | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT | -| format.cpp:105:38:105:52 | call to source | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT | -| format.cpp:109:21:109:24 | {...} | format.cpp:110:18:110:23 | buffer | | -| format.cpp:109:21:109:24 | {...} | format.cpp:111:8:111:13 | buffer | | -| format.cpp:109:23:109:23 | 0 | format.cpp:109:21:109:24 | {...} | TAINT | -| format.cpp:110:18:110:23 | ref arg buffer | format.cpp:111:8:111:13 | buffer | | -| format.cpp:115:10:115:11 | 0 | format.cpp:116:29:116:29 | i | | -| format.cpp:115:10:115:11 | 0 | format.cpp:117:8:117:8 | i | | -| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:116:29:116:29 | i [inner post update] | | -| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:117:8:117:8 | i | | -| format.cpp:116:29:116:29 | i | format.cpp:116:28:116:29 | & ... | | -| format.cpp:120:10:120:11 | 0 | format.cpp:121:40:121:40 | i | | -| format.cpp:120:10:120:11 | 0 | format.cpp:122:8:122:8 | i | | -| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:121:40:121:40 | i [inner post update] | | -| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:122:8:122:8 | i | | -| format.cpp:121:40:121:40 | i | format.cpp:121:39:121:40 | & ... | | -| format.cpp:125:21:125:24 | {...} | format.cpp:126:32:126:37 | buffer | | -| format.cpp:125:21:125:24 | {...} | format.cpp:127:8:127:13 | buffer | | -| format.cpp:125:23:125:23 | 0 | format.cpp:125:21:125:24 | {...} | TAINT | -| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:126:32:126:37 | buffer [inner post update] | | -| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:127:8:127:13 | buffer | | -| format.cpp:126:32:126:37 | buffer | format.cpp:126:31:126:37 | & ... | | -| format.cpp:130:21:130:24 | {...} | format.cpp:131:40:131:45 | buffer | | -| format.cpp:130:21:130:24 | {...} | format.cpp:132:8:132:13 | buffer | | -| format.cpp:130:23:130:23 | 0 | format.cpp:130:21:130:24 | {...} | TAINT | -| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:131:40:131:45 | buffer [inner post update] | | -| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:132:8:132:13 | buffer | | -| format.cpp:131:40:131:45 | buffer | format.cpp:131:39:131:45 | & ... | | +| format.cpp:16:21:16:21 | s | format.cpp:22:13:22:13 | s | | +| format.cpp:16:31:16:31 | n | format.cpp:22:16:22:16 | n | | +| format.cpp:16:46:16:51 | format | format.cpp:22:19:22:24 | format | | +| format.cpp:20:10:20:13 | args | format.cpp:22:27:22:30 | args | | +| format.cpp:50:21:50:24 | {...} | format.cpp:51:17:51:22 | buffer | | +| format.cpp:50:21:50:24 | {...} | format.cpp:52:8:52:13 | buffer | | +| format.cpp:50:23:50:23 | 0 | format.cpp:50:21:50:24 | {...} | TAINT | +| format.cpp:51:17:51:22 | ref arg buffer | format.cpp:52:8:52:13 | buffer | | +| format.cpp:51:30:51:33 | %s | format.cpp:51:17:51:22 | ref arg buffer | TAINT | +| format.cpp:51:36:51:43 | Hello. | format.cpp:51:17:51:22 | ref arg buffer | TAINT | +| format.cpp:55:21:55:24 | {...} | format.cpp:56:17:56:22 | buffer | | +| format.cpp:55:21:55:24 | {...} | format.cpp:57:8:57:13 | buffer | | +| format.cpp:55:23:55:23 | 0 | format.cpp:55:21:55:24 | {...} | TAINT | +| format.cpp:56:17:56:22 | ref arg buffer | format.cpp:57:8:57:13 | buffer | | +| format.cpp:56:30:56:33 | %s | format.cpp:56:17:56:22 | ref arg buffer | TAINT | +| format.cpp:56:36:56:49 | call to source | format.cpp:56:17:56:22 | ref arg buffer | TAINT | +| format.cpp:60:21:60:24 | {...} | format.cpp:61:17:61:22 | buffer | | +| format.cpp:60:21:60:24 | {...} | format.cpp:62:8:62:13 | buffer | | +| format.cpp:60:23:60:23 | 0 | format.cpp:60:21:60:24 | {...} | TAINT | +| format.cpp:61:17:61:22 | ref arg buffer | format.cpp:62:8:62:13 | buffer | | +| format.cpp:61:30:61:43 | call to source | format.cpp:61:17:61:22 | ref arg buffer | TAINT | +| format.cpp:61:48:61:55 | Hello. | format.cpp:61:17:61:22 | ref arg buffer | TAINT | +| format.cpp:65:21:65:24 | {...} | format.cpp:66:17:66:22 | buffer | | +| format.cpp:65:21:65:24 | {...} | format.cpp:67:8:67:13 | buffer | | +| format.cpp:65:23:65:23 | 0 | format.cpp:65:21:65:24 | {...} | TAINT | +| format.cpp:66:17:66:22 | ref arg buffer | format.cpp:67:8:67:13 | buffer | | +| format.cpp:66:30:66:39 | %s %s %s | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:66:42:66:44 | a | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:66:47:66:49 | b | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:66:52:66:65 | call to source | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:70:21:70:24 | {...} | format.cpp:71:17:71:22 | buffer | | +| format.cpp:70:21:70:24 | {...} | format.cpp:72:8:72:13 | buffer | | +| format.cpp:70:23:70:23 | 0 | format.cpp:70:21:70:24 | {...} | TAINT | +| format.cpp:71:17:71:22 | ref arg buffer | format.cpp:72:8:72:13 | buffer | | +| format.cpp:71:30:71:35 | %.*s | format.cpp:71:17:71:22 | ref arg buffer | TAINT | +| format.cpp:71:38:71:39 | 10 | format.cpp:71:17:71:22 | ref arg buffer | TAINT | +| format.cpp:71:42:71:55 | call to source | format.cpp:71:17:71:22 | ref arg buffer | TAINT | +| format.cpp:76:21:76:24 | {...} | format.cpp:77:17:77:22 | buffer | | +| format.cpp:76:21:76:24 | {...} | format.cpp:78:8:78:13 | buffer | | +| format.cpp:76:23:76:23 | 0 | format.cpp:76:21:76:24 | {...} | TAINT | +| format.cpp:77:17:77:22 | ref arg buffer | format.cpp:78:8:78:13 | buffer | | +| format.cpp:77:30:77:33 | %i | format.cpp:77:17:77:22 | ref arg buffer | TAINT | +| format.cpp:77:36:77:36 | 0 | format.cpp:77:17:77:22 | ref arg buffer | TAINT | +| format.cpp:81:21:81:24 | {...} | format.cpp:82:17:82:22 | buffer | | +| format.cpp:81:21:81:24 | {...} | format.cpp:83:8:83:13 | buffer | | +| format.cpp:81:23:81:23 | 0 | format.cpp:81:21:81:24 | {...} | TAINT | +| format.cpp:82:17:82:22 | ref arg buffer | format.cpp:83:8:83:13 | buffer | | +| format.cpp:82:30:82:33 | %i | format.cpp:82:17:82:22 | ref arg buffer | TAINT | +| format.cpp:82:36:82:41 | call to source | format.cpp:82:17:82:22 | ref arg buffer | TAINT | +| format.cpp:86:21:86:24 | {...} | format.cpp:87:17:87:22 | buffer | | +| format.cpp:86:21:86:24 | {...} | format.cpp:88:8:88:13 | buffer | | +| format.cpp:86:23:86:23 | 0 | format.cpp:86:21:86:24 | {...} | TAINT | +| format.cpp:87:17:87:22 | ref arg buffer | format.cpp:88:8:88:13 | buffer | | +| format.cpp:87:30:87:35 | %.*s | format.cpp:87:17:87:22 | ref arg buffer | TAINT | +| format.cpp:87:38:87:43 | call to source | format.cpp:87:17:87:22 | ref arg buffer | TAINT | +| format.cpp:87:48:87:55 | Hello. | format.cpp:87:17:87:22 | ref arg buffer | TAINT | +| format.cpp:92:21:92:24 | {...} | format.cpp:93:17:93:22 | buffer | | +| format.cpp:92:21:92:24 | {...} | format.cpp:94:8:94:13 | buffer | | +| format.cpp:92:23:92:23 | 0 | format.cpp:92:21:92:24 | {...} | TAINT | +| format.cpp:93:17:93:22 | ref arg buffer | format.cpp:94:8:94:13 | buffer | | +| format.cpp:93:30:93:33 | %p | format.cpp:93:17:93:22 | ref arg buffer | TAINT | +| format.cpp:93:36:93:49 | call to source | format.cpp:93:17:93:22 | ref arg buffer | TAINT | +| format.cpp:98:21:98:24 | {...} | format.cpp:99:16:99:21 | buffer | | +| format.cpp:98:21:98:24 | {...} | format.cpp:100:8:100:13 | buffer | | +| format.cpp:98:23:98:23 | 0 | format.cpp:98:21:98:24 | {...} | TAINT | +| format.cpp:99:16:99:21 | ref arg buffer | format.cpp:100:8:100:13 | buffer | | +| format.cpp:99:24:99:27 | %s | format.cpp:99:16:99:21 | ref arg buffer | TAINT | +| format.cpp:99:30:99:43 | call to source | format.cpp:99:16:99:21 | ref arg buffer | TAINT | +| format.cpp:103:21:103:24 | {...} | format.cpp:104:16:104:21 | buffer | | +| format.cpp:103:21:103:24 | {...} | format.cpp:105:8:105:13 | buffer | | +| format.cpp:103:23:103:23 | 0 | format.cpp:103:21:103:24 | {...} | TAINT | +| format.cpp:104:16:104:21 | ref arg buffer | format.cpp:105:8:105:13 | buffer | | +| format.cpp:104:24:104:28 | %ls | format.cpp:104:16:104:21 | ref arg buffer | TAINT | +| format.cpp:104:31:104:45 | call to source | format.cpp:104:16:104:21 | ref arg buffer | TAINT | +| format.cpp:108:25:108:28 | {...} | format.cpp:109:17:109:23 | wbuffer | | +| format.cpp:108:25:108:28 | {...} | format.cpp:110:8:110:14 | wbuffer | | +| format.cpp:108:27:108:27 | 0 | format.cpp:108:25:108:28 | {...} | TAINT | +| format.cpp:109:17:109:23 | ref arg wbuffer | format.cpp:110:8:110:14 | wbuffer | | +| format.cpp:109:31:109:35 | %s | format.cpp:109:17:109:23 | ref arg wbuffer | TAINT | +| format.cpp:109:38:109:52 | call to source | format.cpp:109:17:109:23 | ref arg wbuffer | TAINT | +| format.cpp:113:21:113:24 | {...} | format.cpp:114:18:114:23 | buffer | | +| format.cpp:113:21:113:24 | {...} | format.cpp:115:8:115:13 | buffer | | +| format.cpp:113:23:113:23 | 0 | format.cpp:113:21:113:24 | {...} | TAINT | +| format.cpp:114:18:114:23 | ref arg buffer | format.cpp:115:8:115:13 | buffer | | +| format.cpp:119:10:119:11 | 0 | format.cpp:120:29:120:29 | i | | +| format.cpp:119:10:119:11 | 0 | format.cpp:121:8:121:8 | i | | +| format.cpp:120:28:120:29 | ref arg & ... | format.cpp:120:29:120:29 | i [inner post update] | | +| format.cpp:120:28:120:29 | ref arg & ... | format.cpp:121:8:121:8 | i | | +| format.cpp:120:29:120:29 | i | format.cpp:120:28:120:29 | & ... | | +| format.cpp:124:10:124:11 | 0 | format.cpp:125:40:125:40 | i | | +| format.cpp:124:10:124:11 | 0 | format.cpp:126:8:126:8 | i | | +| format.cpp:125:39:125:40 | ref arg & ... | format.cpp:125:40:125:40 | i [inner post update] | | +| format.cpp:125:39:125:40 | ref arg & ... | format.cpp:126:8:126:8 | i | | +| format.cpp:125:40:125:40 | i | format.cpp:125:39:125:40 | & ... | | +| format.cpp:129:21:129:24 | {...} | format.cpp:130:32:130:37 | buffer | | +| format.cpp:129:21:129:24 | {...} | format.cpp:131:8:131:13 | buffer | | +| format.cpp:129:23:129:23 | 0 | format.cpp:129:21:129:24 | {...} | TAINT | +| format.cpp:130:31:130:37 | ref arg & ... | format.cpp:130:32:130:37 | buffer [inner post update] | | +| format.cpp:130:31:130:37 | ref arg & ... | format.cpp:131:8:131:13 | buffer | | +| format.cpp:130:32:130:37 | buffer | format.cpp:130:31:130:37 | & ... | | +| format.cpp:134:21:134:24 | {...} | format.cpp:135:40:135:45 | buffer | | +| format.cpp:134:21:134:24 | {...} | format.cpp:136:8:136:13 | buffer | | +| format.cpp:134:23:134:23 | 0 | format.cpp:134:21:134:24 | {...} | TAINT | +| format.cpp:135:39:135:45 | ref arg & ... | format.cpp:135:40:135:45 | buffer [inner post update] | | +| format.cpp:135:39:135:45 | ref arg & ... | format.cpp:136:8:136:13 | buffer | | +| format.cpp:135:40:135:45 | buffer | format.cpp:135:39:135:45 | & ... | | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index b9294f5b7ae..e873ff91915 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -1,13 +1,13 @@ -| format.cpp:53:8:53:13 | buffer | format.cpp:52:36:52:49 | call to source | -| format.cpp:58:8:58:13 | buffer | format.cpp:57:30:57:43 | call to source | -| format.cpp:63:8:63:13 | buffer | format.cpp:62:52:62:65 | call to source | -| format.cpp:68:8:68:13 | buffer | format.cpp:67:42:67:55 | call to source | -| format.cpp:79:8:79:13 | buffer | format.cpp:78:36:78:41 | call to source | -| format.cpp:84:8:84:13 | buffer | format.cpp:83:38:83:43 | call to source | -| format.cpp:90:8:90:13 | buffer | format.cpp:89:36:89:49 | call to source | -| format.cpp:96:8:96:13 | buffer | format.cpp:95:30:95:43 | call to source | -| format.cpp:101:8:101:13 | buffer | format.cpp:100:31:100:45 | call to source | -| format.cpp:106:8:106:14 | wbuffer | format.cpp:105:38:105:52 | call to source | +| format.cpp:57:8:57:13 | buffer | format.cpp:56:36:56:49 | call to source | +| format.cpp:62:8:62:13 | buffer | format.cpp:61:30:61:43 | call to source | +| format.cpp:67:8:67:13 | buffer | format.cpp:66:52:66:65 | call to source | +| format.cpp:72:8:72:13 | buffer | format.cpp:71:42:71:55 | call to source | +| format.cpp:83:8:83:13 | buffer | format.cpp:82:36:82:41 | call to source | +| format.cpp:88:8:88:13 | buffer | format.cpp:87:38:87:43 | call to source | +| format.cpp:94:8:94:13 | buffer | format.cpp:93:36:93:49 | call to source | +| format.cpp:100:8:100:13 | buffer | format.cpp:99:30:99:43 | call to source | +| format.cpp:105:8:105:13 | buffer | format.cpp:104:31:104:45 | call to source | +| format.cpp:110:8:110:14 | wbuffer | format.cpp:109:38:109:52 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | | stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source | | stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index 58a7255accb..fa0807f204e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -1,13 +1,13 @@ -| format.cpp:53:8:53:13 | format.cpp:52:36:52:49 | AST only | -| format.cpp:58:8:58:13 | format.cpp:57:30:57:43 | AST only | -| format.cpp:63:8:63:13 | format.cpp:62:52:62:65 | AST only | -| format.cpp:68:8:68:13 | format.cpp:67:42:67:55 | AST only | -| format.cpp:79:8:79:13 | format.cpp:78:36:78:41 | AST only | -| format.cpp:84:8:84:13 | format.cpp:83:38:83:43 | AST only | -| format.cpp:90:8:90:13 | format.cpp:89:36:89:49 | AST only | -| format.cpp:96:8:96:13 | format.cpp:95:30:95:43 | AST only | -| format.cpp:101:8:101:13 | format.cpp:100:31:100:45 | AST only | -| format.cpp:106:8:106:14 | format.cpp:105:38:105:52 | AST only | +| format.cpp:57:8:57:13 | format.cpp:56:36:56:49 | AST only | +| format.cpp:62:8:62:13 | format.cpp:61:30:61:43 | AST only | +| format.cpp:67:8:67:13 | format.cpp:66:52:66:65 | AST only | +| format.cpp:72:8:72:13 | format.cpp:71:42:71:55 | AST only | +| format.cpp:83:8:83:13 | format.cpp:82:36:82:41 | AST only | +| format.cpp:88:8:88:13 | format.cpp:87:38:87:43 | AST only | +| format.cpp:94:8:94:13 | format.cpp:93:36:93:49 | AST only | +| format.cpp:100:8:100:13 | format.cpp:99:30:99:43 | AST only | +| format.cpp:105:8:105:13 | format.cpp:104:31:104:45 | AST only | +| format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only | | stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | From 95537ed26fbd74d37314aced3c9756f622132776 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 26 May 2020 18:05:44 +0100 Subject: [PATCH 106/111] C++: Fix mysprintf in test. --- .../test/library-tests/dataflow/taint-tests/format.cpp | 6 +++--- .../dataflow/taint-tests/localTaint.expected | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp index 7271cbbf85e..974ea6040e8 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp @@ -15,14 +15,14 @@ int vsnprintf(char *s, size_t n, const char *format, va_list arg); int mysprintf(char *s, size_t n, const char *format, ...) { - + int result; va_list args; va_start(args, format); - vsnprintf(s, n, format, args); + result = vsnprintf(s, n, format, args); va_end(args); - + return result; } int sscanf(const char *s, const char *format, ...); diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index 8d16904e0ba..c7d58f99966 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3,10 +3,12 @@ | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | -| format.cpp:16:21:16:21 | s | format.cpp:22:13:22:13 | s | | -| format.cpp:16:31:16:31 | n | format.cpp:22:16:22:16 | n | | -| format.cpp:16:46:16:51 | format | format.cpp:22:19:22:24 | format | | -| format.cpp:20:10:20:13 | args | format.cpp:22:27:22:30 | args | | +| format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | | +| format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | | +| format.cpp:16:46:16:51 | format | format.cpp:22:28:22:33 | format | | +| format.cpp:20:10:20:13 | args | format.cpp:22:36:22:39 | args | | +| format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:22:3:22:40 | ... = ... | | +| format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:25:9:25:14 | result | | | format.cpp:50:21:50:24 | {...} | format.cpp:51:17:51:22 | buffer | | | format.cpp:50:21:50:24 | {...} | format.cpp:52:8:52:13 | buffer | | | format.cpp:50:23:50:23 | 0 | format.cpp:50:21:50:24 | {...} | TAINT | From 97edd9777861d76c5825220305ab420e741a4414 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 27 May 2020 08:28:18 +0200 Subject: [PATCH 107/111] C++: Add getLocation to TNode IPA type in testcase --- .../fields/partial-definition-diff.expected | 740 +++++++++--------- .../fields/partial-definition-diff.ql | 6 + 2 files changed, 376 insertions(+), 370 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 20da36f2dde..0b4a738b7df 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -1,370 +1,370 @@ -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| * ... | AST only | -| * ... | AST only | -| * ... | AST only | -| * ... | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a_ | AST only | -| a_ | AST only | -| a_ | AST only | -| ab | AST only | -| ab | AST only | -| ab | AST only | -| ab | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b3 | AST only | -| b3 | AST only | -| b3 | AST only | -| b4 | AST only | -| b_ | AST only | -| b_ | AST only | -| b_ | AST only | -| box | AST only | -| box | AST only | -| box | AST only | -| box | AST only | -| box | AST only | -| box | AST only | -| box1 | AST only | -| box1 | AST only | -| box1 | AST only | -| box1 | AST only | -| box1 | AST only | -| boxfield | AST only | -| boxfield | AST only | -| boxfield | AST only | -| buffer | AST only | -| buffer | AST only | -| buffer | AST only | -| buffer | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c1 | AST only | -| c1 | AST only | -| c1 | AST only | -| call to get | AST only | -| call to get | AST only | -| call to getBox1 | AST only | -| call to getBox1 | AST only | -| call to getBox1 | AST only | -| call to getDirectly | AST only | -| call to getElem | AST only | -| call to getIndirectly | AST only | -| call to getInner | AST only | -| call to getInner | AST only | -| call to getInner | AST only | -| call to getInner | AST only | -| call to getThroughNonMember | AST only | -| call to nonMemberGetA | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| cc | AST only | -| ct | AST only | -| d | AST only | -| d | AST only | -| data | AST only | -| data | AST only | -| e | AST only | -| e | AST only | -| e | AST only | -| e | AST only | -| elem | AST only | -| elem | AST only | -| elem | AST only | -| elem | AST only | -| elem | AST only | -| elem | AST only | -| elem1 | AST only | -| elem1 | AST only | -| elem1 | AST only | -| elem2 | AST only | -| elem2 | AST only | -| elem2 | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f1 | AST only | -| f2 | AST only | -| g | AST only | -| g | AST only | -| g | AST only | -| h | AST only | -| h | AST only | -| h | AST only | -| h | AST only | -| head | AST only | -| head | AST only | -| head | AST only | -| head | AST only | -| head | AST only | -| head | AST only | -| i | AST only | -| i | AST only | -| i | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| l | AST only | -| l1 | AST only | -| l2 | AST only | -| l3 | AST only | -| l3 | AST only | -| l3 | AST only | -| l3 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| nestedAB | AST only | -| nestedAB | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| p | AST only | -| p | AST only | -| pointerAB | AST only | -| pointerAB | AST only | -| pointerAB | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| raw | AST only | -| raw | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s2 | AST only | -| s3 | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| value | AST only | -| value | AST only | -| w | AST only | +| A.cpp:25:7:25:10 | this | AST only | +| A.cpp:25:13:25:13 | c | AST only | +| A.cpp:27:22:27:25 | this | AST only | +| A.cpp:27:28:27:28 | c | AST only | +| A.cpp:31:20:31:20 | c | AST only | +| A.cpp:40:5:40:6 | cc | AST only | +| A.cpp:41:5:41:6 | ct | AST only | +| A.cpp:42:10:42:12 | & ... | AST only | +| A.cpp:43:10:43:12 | & ... | AST only | +| A.cpp:48:20:48:20 | c | AST only | +| A.cpp:49:10:49:10 | b | AST only | +| A.cpp:49:13:49:13 | c | AST only | +| A.cpp:55:5:55:5 | b | AST only | +| A.cpp:56:10:56:10 | b | AST only | +| A.cpp:56:13:56:15 | call to get | AST only | +| A.cpp:57:28:57:30 | call to get | AST only | +| A.cpp:64:17:64:18 | b1 | AST only | +| A.cpp:65:10:65:11 | b1 | AST only | +| A.cpp:65:14:65:14 | c | AST only | +| A.cpp:66:10:66:11 | b2 | AST only | +| A.cpp:66:14:66:14 | c | AST only | +| A.cpp:73:21:73:22 | b1 | AST only | +| A.cpp:74:10:74:11 | b1 | AST only | +| A.cpp:74:14:74:14 | c | AST only | +| A.cpp:75:10:75:11 | b2 | AST only | +| A.cpp:75:14:75:14 | c | AST only | +| A.cpp:81:17:81:18 | b1 | AST only | +| A.cpp:81:21:81:21 | c | AST only | +| A.cpp:90:7:90:8 | b2 | AST only | +| A.cpp:90:15:90:15 | c | AST only | +| A.cpp:100:9:100:9 | a | AST only | +| A.cpp:101:8:101:9 | c1 | AST only | +| A.cpp:107:12:107:13 | c1 | AST only | +| A.cpp:107:16:107:16 | a | AST only | +| A.cpp:120:12:120:13 | c1 | AST only | +| A.cpp:120:16:120:16 | a | AST only | +| A.cpp:126:5:126:5 | b | AST only | +| A.cpp:131:8:131:8 | b | AST only | +| A.cpp:132:10:132:10 | b | AST only | +| A.cpp:132:13:132:13 | c | AST only | +| A.cpp:142:10:142:10 | c | AST only | +| A.cpp:143:7:143:10 | this | AST only | +| A.cpp:143:13:143:13 | b | AST only | +| A.cpp:151:18:151:18 | b | AST only | +| A.cpp:152:10:152:10 | d | AST only | +| A.cpp:152:13:152:13 | b | AST only | +| A.cpp:153:10:153:10 | d | AST only | +| A.cpp:153:13:153:13 | b | AST only | +| A.cpp:153:16:153:16 | c | AST only | +| A.cpp:154:10:154:10 | b | AST only | +| A.cpp:154:13:154:13 | c | AST only | +| A.cpp:160:29:160:29 | b | AST only | +| A.cpp:161:38:161:39 | l1 | AST only | +| A.cpp:162:38:162:39 | l2 | AST only | +| A.cpp:163:10:163:11 | l3 | AST only | +| A.cpp:163:14:163:17 | head | AST only | +| A.cpp:164:10:164:11 | l3 | AST only | +| A.cpp:164:14:164:17 | next | AST only | +| A.cpp:164:20:164:23 | head | AST only | +| A.cpp:165:10:165:11 | l3 | AST only | +| A.cpp:165:14:165:17 | next | AST only | +| A.cpp:165:20:165:23 | next | AST only | +| A.cpp:165:26:165:29 | head | AST only | +| A.cpp:166:10:166:11 | l3 | AST only | +| A.cpp:166:14:166:17 | next | AST only | +| A.cpp:166:20:166:23 | next | AST only | +| A.cpp:166:26:166:29 | next | AST only | +| A.cpp:166:32:166:35 | head | AST only | +| A.cpp:169:12:169:12 | l | AST only | +| A.cpp:169:15:169:18 | head | AST only | +| A.cpp:183:7:183:10 | head | AST only | +| A.cpp:183:7:183:10 | this | AST only | +| A.cpp:184:7:184:10 | this | AST only | +| A.cpp:184:13:184:16 | next | AST only | +| B.cpp:7:25:7:25 | e | AST only | +| B.cpp:8:25:8:26 | b1 | AST only | +| B.cpp:9:10:9:11 | b2 | AST only | +| B.cpp:9:14:9:17 | box1 | AST only | +| B.cpp:9:20:9:24 | elem1 | AST only | +| B.cpp:10:10:10:11 | b2 | AST only | +| B.cpp:10:14:10:17 | box1 | AST only | +| B.cpp:10:20:10:24 | elem2 | AST only | +| B.cpp:16:37:16:37 | e | AST only | +| B.cpp:17:25:17:26 | b1 | AST only | +| B.cpp:18:10:18:11 | b2 | AST only | +| B.cpp:18:14:18:17 | box1 | AST only | +| B.cpp:18:20:18:24 | elem1 | AST only | +| B.cpp:19:10:19:11 | b2 | AST only | +| B.cpp:19:14:19:17 | box1 | AST only | +| B.cpp:19:20:19:24 | elem2 | AST only | +| B.cpp:35:7:35:10 | this | AST only | +| B.cpp:35:13:35:17 | elem1 | AST only | +| B.cpp:36:7:36:10 | this | AST only | +| B.cpp:36:13:36:17 | elem2 | AST only | +| B.cpp:46:7:46:10 | this | AST only | +| B.cpp:46:13:46:16 | box1 | AST only | +| C.cpp:19:5:19:5 | c | AST only | +| C.cpp:24:5:24:8 | this | AST only | +| C.cpp:24:11:24:12 | s3 | AST only | +| D.cpp:9:21:9:24 | elem | AST only | +| D.cpp:9:21:9:24 | this | AST only | +| D.cpp:11:29:11:32 | elem | AST only | +| D.cpp:11:29:11:32 | this | AST only | +| D.cpp:16:21:16:23 | box | AST only | +| D.cpp:16:21:16:23 | this | AST only | +| D.cpp:18:29:18:31 | box | AST only | +| D.cpp:18:29:18:31 | this | AST only | +| D.cpp:22:10:22:11 | b2 | AST only | +| D.cpp:22:14:22:20 | call to getBox1 | AST only | +| D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:30:5:30:5 | b | AST only | +| D.cpp:30:8:30:10 | box | AST only | +| D.cpp:30:13:30:16 | elem | AST only | +| D.cpp:31:14:31:14 | b | AST only | +| D.cpp:37:5:37:5 | b | AST only | +| D.cpp:37:8:37:10 | box | AST only | +| D.cpp:37:21:37:21 | e | AST only | +| D.cpp:38:14:38:14 | b | AST only | +| D.cpp:44:5:44:5 | b | AST only | +| D.cpp:44:8:44:14 | call to getBox1 | AST only | +| D.cpp:44:19:44:22 | elem | AST only | +| D.cpp:45:14:45:14 | b | AST only | +| D.cpp:51:5:51:5 | b | AST only | +| D.cpp:51:8:51:14 | call to getBox1 | AST only | +| D.cpp:51:27:51:27 | e | AST only | +| D.cpp:52:14:52:14 | b | AST only | +| D.cpp:57:5:57:12 | boxfield | AST only | +| D.cpp:57:5:57:12 | this | AST only | +| D.cpp:58:5:58:12 | boxfield | AST only | +| D.cpp:58:5:58:12 | this | AST only | +| D.cpp:58:15:58:17 | box | AST only | +| D.cpp:58:20:58:23 | elem | AST only | +| D.cpp:64:10:64:17 | boxfield | AST only | +| D.cpp:64:10:64:17 | this | AST only | +| D.cpp:64:20:64:22 | box | AST only | +| D.cpp:64:25:64:28 | elem | AST only | +| E.cpp:21:10:21:10 | p | AST only | +| E.cpp:21:13:21:16 | data | AST only | +| E.cpp:21:18:21:23 | buffer | AST only | +| E.cpp:28:21:28:23 | raw | AST only | +| E.cpp:29:21:29:21 | b | AST only | +| E.cpp:29:24:29:29 | buffer | AST only | +| E.cpp:30:21:30:21 | p | AST only | +| E.cpp:30:23:30:26 | data | AST only | +| E.cpp:30:28:30:33 | buffer | AST only | +| E.cpp:31:10:31:12 | raw | AST only | +| E.cpp:32:10:32:10 | b | AST only | +| E.cpp:32:13:32:18 | buffer | AST only | +| E.cpp:33:18:33:19 | & ... | AST only | +| aliasing.cpp:9:6:9:7 | m1 | AST only | +| aliasing.cpp:13:5:13:6 | m1 | AST only | +| aliasing.cpp:17:5:17:6 | m1 | AST only | +| aliasing.cpp:25:17:25:19 | & ... | AST only | +| aliasing.cpp:26:19:26:20 | s2 | AST only | +| aliasing.cpp:37:8:37:9 | m1 | AST only | +| aliasing.cpp:42:6:42:7 | m1 | AST only | +| aliasing.cpp:49:9:49:10 | m1 | AST only | +| aliasing.cpp:54:6:54:7 | m1 | AST only | +| aliasing.cpp:60:6:60:7 | m1 | AST only | +| aliasing.cpp:72:5:72:6 | m1 | AST only | +| aliasing.cpp:79:6:79:7 | m1 | AST only | +| aliasing.cpp:86:5:86:6 | m1 | AST only | +| aliasing.cpp:92:3:92:3 | w | AST only | +| aliasing.cpp:92:7:92:8 | m1 | AST only | +| by_reference.cpp:12:8:12:8 | a | AST only | +| by_reference.cpp:16:5:16:8 | this | AST only | +| by_reference.cpp:16:11:16:11 | a | AST only | +| by_reference.cpp:20:5:20:8 | this | AST only | +| by_reference.cpp:20:23:20:27 | value | AST only | +| by_reference.cpp:24:19:24:22 | this | AST only | +| by_reference.cpp:24:25:24:29 | value | AST only | +| by_reference.cpp:50:3:50:3 | s | AST only | +| by_reference.cpp:50:17:50:26 | call to user_input | AST only | +| by_reference.cpp:51:10:51:20 | call to getDirectly | AST only | +| by_reference.cpp:56:3:56:3 | s | AST only | +| by_reference.cpp:56:19:56:28 | call to user_input | AST only | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | AST only | +| by_reference.cpp:62:3:62:3 | s | AST only | +| by_reference.cpp:62:25:62:34 | call to user_input | AST only | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | AST only | +| by_reference.cpp:68:17:68:18 | & ... | AST only | +| by_reference.cpp:68:21:68:30 | call to user_input | AST only | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | AST only | +| by_reference.cpp:84:10:84:10 | a | AST only | +| by_reference.cpp:88:9:88:9 | a | AST only | +| by_reference.cpp:102:21:102:39 | & ... | AST only | +| by_reference.cpp:102:22:102:26 | outer | AST only | +| by_reference.cpp:103:21:103:25 | outer | AST only | +| by_reference.cpp:103:27:103:35 | inner_ptr | AST only | +| by_reference.cpp:104:15:104:22 | & ... | AST only | +| by_reference.cpp:104:16:104:20 | outer | AST only | +| by_reference.cpp:106:21:106:41 | & ... | AST only | +| by_reference.cpp:106:22:106:27 | pouter | AST only | +| by_reference.cpp:107:21:107:26 | pouter | AST only | +| by_reference.cpp:107:29:107:37 | inner_ptr | AST only | +| by_reference.cpp:108:15:108:24 | & ... | AST only | +| by_reference.cpp:108:16:108:21 | pouter | AST only | +| by_reference.cpp:110:8:110:12 | outer | AST only | +| by_reference.cpp:110:14:110:25 | inner_nested | AST only | +| by_reference.cpp:110:27:110:27 | a | AST only | +| by_reference.cpp:111:8:111:12 | outer | AST only | +| by_reference.cpp:111:14:111:22 | inner_ptr | AST only | +| by_reference.cpp:111:25:111:25 | a | AST only | +| by_reference.cpp:112:8:112:12 | outer | AST only | +| by_reference.cpp:112:14:112:14 | a | AST only | +| by_reference.cpp:114:8:114:13 | pouter | AST only | +| by_reference.cpp:114:16:114:27 | inner_nested | AST only | +| by_reference.cpp:114:29:114:29 | a | AST only | +| by_reference.cpp:115:8:115:13 | pouter | AST only | +| by_reference.cpp:115:16:115:24 | inner_ptr | AST only | +| by_reference.cpp:115:27:115:27 | a | AST only | +| by_reference.cpp:116:8:116:13 | pouter | AST only | +| by_reference.cpp:116:16:116:16 | a | AST only | +| by_reference.cpp:122:21:122:25 | outer | AST only | +| by_reference.cpp:122:27:122:38 | inner_nested | AST only | +| by_reference.cpp:123:21:123:36 | * ... | AST only | +| by_reference.cpp:123:22:123:26 | outer | AST only | +| by_reference.cpp:124:15:124:19 | outer | AST only | +| by_reference.cpp:124:21:124:21 | a | AST only | +| by_reference.cpp:126:21:126:26 | pouter | AST only | +| by_reference.cpp:126:29:126:40 | inner_nested | AST only | +| by_reference.cpp:127:21:127:38 | * ... | AST only | +| by_reference.cpp:127:22:127:27 | pouter | AST only | +| by_reference.cpp:128:15:128:20 | pouter | AST only | +| by_reference.cpp:128:23:128:23 | a | AST only | +| by_reference.cpp:130:8:130:12 | outer | AST only | +| by_reference.cpp:130:14:130:25 | inner_nested | AST only | +| by_reference.cpp:130:27:130:27 | a | AST only | +| by_reference.cpp:131:8:131:12 | outer | AST only | +| by_reference.cpp:131:14:131:22 | inner_ptr | AST only | +| by_reference.cpp:131:25:131:25 | a | AST only | +| by_reference.cpp:132:8:132:12 | outer | AST only | +| by_reference.cpp:132:14:132:14 | a | AST only | +| by_reference.cpp:134:8:134:13 | pouter | AST only | +| by_reference.cpp:134:16:134:27 | inner_nested | AST only | +| by_reference.cpp:134:29:134:29 | a | AST only | +| by_reference.cpp:135:8:135:13 | pouter | AST only | +| by_reference.cpp:135:16:135:24 | inner_ptr | AST only | +| by_reference.cpp:135:27:135:27 | a | AST only | +| by_reference.cpp:136:8:136:13 | pouter | AST only | +| by_reference.cpp:136:16:136:16 | a | AST only | +| complex.cpp:11:22:11:23 | a_ | AST only | +| complex.cpp:11:22:11:23 | this | AST only | +| complex.cpp:12:22:12:23 | b_ | AST only | +| complex.cpp:12:22:12:23 | this | AST only | +| complex.cpp:51:8:51:8 | b | AST only | +| complex.cpp:51:10:51:14 | inner | AST only | +| complex.cpp:51:16:51:16 | f | AST only | +| complex.cpp:52:8:52:8 | b | AST only | +| complex.cpp:52:10:52:14 | inner | AST only | +| complex.cpp:52:16:52:16 | f | AST only | +| complex.cpp:62:3:62:4 | b1 | AST only | +| complex.cpp:62:6:62:10 | inner | AST only | +| complex.cpp:62:12:62:12 | f | AST only | +| complex.cpp:63:3:63:4 | b2 | AST only | +| complex.cpp:63:6:63:10 | inner | AST only | +| complex.cpp:63:12:63:12 | f | AST only | +| complex.cpp:64:3:64:4 | b3 | AST only | +| complex.cpp:64:6:64:10 | inner | AST only | +| complex.cpp:64:12:64:12 | f | AST only | +| complex.cpp:65:3:65:4 | b3 | AST only | +| complex.cpp:65:6:65:10 | inner | AST only | +| complex.cpp:65:12:65:12 | f | AST only | +| complex.cpp:68:7:68:8 | b1 | AST only | +| complex.cpp:71:7:71:8 | b2 | AST only | +| complex.cpp:74:7:74:8 | b3 | AST only | +| complex.cpp:77:7:77:8 | b4 | AST only | +| constructors.cpp:20:24:20:25 | a_ | AST only | +| constructors.cpp:20:24:20:25 | this | AST only | +| constructors.cpp:21:24:21:25 | b_ | AST only | +| constructors.cpp:21:24:21:25 | this | AST only | +| constructors.cpp:28:10:28:10 | f | AST only | +| constructors.cpp:29:10:29:10 | f | AST only | +| constructors.cpp:40:9:40:9 | f | AST only | +| constructors.cpp:43:9:43:9 | g | AST only | +| constructors.cpp:46:9:46:9 | h | AST only | +| constructors.cpp:49:9:49:9 | i | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| qualifiers.cpp:9:30:9:33 | this | AST only | +| qualifiers.cpp:9:36:9:36 | a | AST only | +| qualifiers.cpp:12:56:12:56 | a | AST only | +| qualifiers.cpp:13:57:13:57 | a | AST only | +| qualifiers.cpp:22:5:22:9 | outer | AST only | +| qualifiers.cpp:22:11:22:18 | call to getInner | AST only | +| qualifiers.cpp:22:23:22:23 | a | AST only | +| qualifiers.cpp:23:10:23:14 | outer | AST only | +| qualifiers.cpp:23:16:23:20 | inner | AST only | +| qualifiers.cpp:23:23:23:23 | a | AST only | +| qualifiers.cpp:27:5:27:9 | outer | AST only | +| qualifiers.cpp:27:11:27:18 | call to getInner | AST only | +| qualifiers.cpp:27:28:27:37 | call to user_input | AST only | +| qualifiers.cpp:28:10:28:14 | outer | AST only | +| qualifiers.cpp:28:16:28:20 | inner | AST only | +| qualifiers.cpp:28:23:28:23 | a | AST only | +| qualifiers.cpp:32:17:32:21 | outer | AST only | +| qualifiers.cpp:32:23:32:30 | call to getInner | AST only | +| qualifiers.cpp:32:35:32:44 | call to user_input | AST only | +| qualifiers.cpp:33:10:33:14 | outer | AST only | +| qualifiers.cpp:33:16:33:20 | inner | AST only | +| qualifiers.cpp:33:23:33:23 | a | AST only | +| qualifiers.cpp:37:19:37:35 | * ... | AST only | +| qualifiers.cpp:37:20:37:24 | outer | AST only | +| qualifiers.cpp:37:38:37:47 | call to user_input | AST only | +| qualifiers.cpp:38:10:38:14 | outer | AST only | +| qualifiers.cpp:38:16:38:20 | inner | AST only | +| qualifiers.cpp:38:23:38:23 | a | AST only | +| qualifiers.cpp:42:6:42:22 | * ... | AST only | +| qualifiers.cpp:42:7:42:11 | outer | AST only | +| qualifiers.cpp:42:25:42:25 | a | AST only | +| qualifiers.cpp:43:10:43:14 | outer | AST only | +| qualifiers.cpp:43:16:43:20 | inner | AST only | +| qualifiers.cpp:43:23:43:23 | a | AST only | +| qualifiers.cpp:47:6:47:11 | & ... | AST only | +| qualifiers.cpp:47:15:47:22 | call to getInner | AST only | +| qualifiers.cpp:47:27:47:27 | a | AST only | +| qualifiers.cpp:48:10:48:14 | outer | AST only | +| qualifiers.cpp:48:16:48:20 | inner | AST only | +| qualifiers.cpp:48:23:48:23 | a | AST only | +| simple.cpp:20:24:20:25 | a_ | AST only | +| simple.cpp:20:24:20:25 | this | AST only | +| simple.cpp:21:24:21:25 | b_ | AST only | +| simple.cpp:21:24:21:25 | this | AST only | +| simple.cpp:28:10:28:10 | f | AST only | +| simple.cpp:29:10:29:10 | f | AST only | +| simple.cpp:39:5:39:5 | f | AST only | +| simple.cpp:40:5:40:5 | g | AST only | +| simple.cpp:41:5:41:5 | h | AST only | +| simple.cpp:42:5:42:5 | h | AST only | +| simple.cpp:45:9:45:9 | f | AST only | +| simple.cpp:48:9:48:9 | g | AST only | +| simple.cpp:51:9:51:9 | h | AST only | +| simple.cpp:54:9:54:9 | i | AST only | +| simple.cpp:65:7:65:7 | i | AST only | +| simple.cpp:83:9:83:10 | f2 | AST only | +| simple.cpp:83:9:83:10 | this | AST only | +| simple.cpp:83:12:83:13 | f1 | AST only | +| struct_init.c:15:8:15:9 | ab | AST only | +| struct_init.c:15:12:15:12 | a | AST only | +| struct_init.c:16:8:16:9 | ab | AST only | +| struct_init.c:16:12:16:12 | b | AST only | +| struct_init.c:22:8:22:9 | ab | AST only | +| struct_init.c:22:11:22:11 | a | AST only | +| struct_init.c:23:8:23:9 | ab | AST only | +| struct_init.c:23:11:23:11 | b | AST only | +| struct_init.c:24:10:24:12 | & ... | AST only | +| struct_init.c:31:8:31:12 | outer | AST only | +| struct_init.c:31:14:31:21 | nestedAB | AST only | +| struct_init.c:31:23:31:23 | a | AST only | +| struct_init.c:32:8:32:12 | outer | AST only | +| struct_init.c:32:14:32:21 | nestedAB | AST only | +| struct_init.c:32:23:32:23 | b | AST only | +| struct_init.c:33:8:33:12 | outer | AST only | +| struct_init.c:33:14:33:22 | pointerAB | AST only | +| struct_init.c:33:25:33:25 | a | AST only | +| struct_init.c:34:8:34:12 | outer | AST only | +| struct_init.c:34:14:34:22 | pointerAB | AST only | +| struct_init.c:34:25:34:25 | b | AST only | +| struct_init.c:36:10:36:24 | & ... | AST only | +| struct_init.c:36:11:36:15 | outer | AST only | +| struct_init.c:46:10:46:14 | outer | AST only | +| struct_init.c:46:16:46:24 | pointerAB | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql index 9607754d965..8f6296290e9 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql @@ -16,6 +16,8 @@ class Node extends TNode { IR::Node asIR() { none() } AST::Node asAST() { none() } + + Location getLocation() { none() } } class ASTNode extends Node, TASTNode { @@ -26,6 +28,8 @@ class ASTNode extends Node, TASTNode { override string toString() { result = n.asPartialDefinition().toString() } override AST::Node asAST() { result = n } + + override Location getLocation() { result = n.getLocation() } } class IRNode extends Node, TIRNode { @@ -36,6 +40,8 @@ class IRNode extends Node, TIRNode { override string toString() { result = n.asPartialDefinition().toString() } override IR::Node asIR() { result = n } + + override Location getLocation() { result = n.getLocation() } } from Node node, AST::Node astNode, IR::Node irNode, string msg From 3ae4e90902a6f2333a0c638ed313fdca61184eca Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 27 May 2020 09:45:49 +0000 Subject: [PATCH 108/111] change note --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0eb939d6801..59b6428feab 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -39,7 +39,7 @@ | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | -| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe strings based on URLs. | +| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe patterns of constructing HTML. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | From 1c5da67cd8fa67ff45f3d48a1bdb0f08a606f6ed Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 27 May 2020 15:26:03 +0200 Subject: [PATCH 109/111] C#: Fix performance issue in unification library --- csharp/ql/src/semmle/code/csharp/Unification.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/csharp/Unification.qll b/csharp/ql/src/semmle/code/csharp/Unification.qll index 77aeae0813a..48256a59a29 100644 --- a/csharp/ql/src/semmle/code/csharp/Unification.qll +++ b/csharp/ql/src/semmle/code/csharp/Unification.qll @@ -474,7 +474,8 @@ module Gvn { sourceDecl = any(GenericType t).getSourceDeclaration() and not sourceDecl instanceof PointerType and not sourceDecl instanceof NullableType and - not sourceDecl instanceof ArrayType + not sourceDecl instanceof ArrayType and + not sourceDecl instanceof TupleType } cached From 3d27b6bbde04c27639081f509c99a3ecdbffbf0c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 28 May 2020 10:10:26 +0200 Subject: [PATCH 110/111] C++: QLDoc for BasicBlock, ControlFlowGraph and Dataflow --- .../code/cpp/controlflow/BasicBlocks.qll | 21 +++++++++++++++++++ .../code/cpp/controlflow/ControlFlowGraph.qll | 16 ++++++++++++++ .../semmle/code/cpp/controlflow/Dataflow.qll | 20 ++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll index 681d0b710f6..3d8202cdf90 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll @@ -1,3 +1,8 @@ +/** + * Provides a library for reasoning about control-flow at the granularity of basic blocks. + * This is usually much more efficient than reasoning directly at the level of `ControlFlowNode`s. + */ + import cpp private import internal.PrimitiveBasicBlocks private import internal.ConstantExprs @@ -148,22 +153,37 @@ predicate bb_successor = bb_successor_cached/2; class BasicBlock extends ControlFlowNodeBase { BasicBlock() { basic_block_entry_node(this) } + /** Holds if this basic block contains `node`. */ predicate contains(ControlFlowNode node) { basic_block_member(node, this, _) } + /** Gets the `ControlFlowNode` at position `pos` in this basic block. */ ControlFlowNode getNode(int pos) { basic_block_member(result, this, pos) } + /** Gets all `ControlFlowNode`s in this basic block. */ ControlFlowNode getANode() { basic_block_member(result, this, _) } + /** Gets all `BasicBlock`s that are direct successors of this basic block. */ BasicBlock getASuccessor() { bb_successor(this, result) } + /** Gets all `BasicBlock`s that are direct predecessors of this basic block. */ BasicBlock getAPredecessor() { bb_successor(result, this) } + /** + * Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken + * when the outgoing edge of this basic block is an expression that is true. + */ BasicBlock getATrueSuccessor() { result.getStart() = this.getEnd().getATrueSuccessor() } + /** + * Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken + * when the outgoing edge of this basic block is an expression that is false. + */ BasicBlock getAFalseSuccessor() { result.getStart() = this.getEnd().getAFalseSuccessor() } + /** Gets the final `ControlFlowNode` of this basic block. */ ControlFlowNode getEnd() { basic_block_member(result, this, bb_length(this) - 1) } + /** Gets the first `ControlFlowNode` of this basic block. */ ControlFlowNode getStart() { result = this } /** Gets the number of `ControlFlowNode`s in this basic block. */ @@ -192,6 +212,7 @@ class BasicBlock extends ControlFlowNodeBase { this.getEnd().getLocation().hasLocationInfo(endf, _, _, endl, endc) } + /** Gets the function containing this basic block. */ Function getEnclosingFunction() { result = this.getStart().getControlFlowScope() } /** diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll index 9174f474a8f..f05b9814ef1 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll @@ -1,3 +1,8 @@ +/** + * Provides a library for reasoning about control-flow at the granularity of + * individual nodes in the control-flow graph. + */ + import cpp import BasicBlocks private import semmle.code.cpp.controlflow.internal.ConstantExprs @@ -29,8 +34,10 @@ private import semmle.code.cpp.controlflow.internal.CFG * `Handler`. There are no edges from function calls to `Handler`s. */ class ControlFlowNode extends Locatable, ControlFlowNodeBase { + /** Gets a direct successor of this control-flow node, if any. */ ControlFlowNode getASuccessor() { successors_adapted(this, result) } + /** Gets a direct predecessor of this control-flow node, if any. */ ControlFlowNode getAPredecessor() { this = result.getASuccessor() } /** Gets the function containing this control-flow node. */ @@ -71,6 +78,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase { result = getASuccessor() } + /** Gets the `BasicBlock` containing this control-flow node. */ BasicBlock getBasicBlock() { result.getANode() = this } } @@ -86,10 +94,18 @@ import ControlFlowGraphPublic */ class ControlFlowNodeBase extends ElementBase, @cfgnode { } +/** + * Holds when `n2` is a control-flow node such that the control-flow + * edge `(n1, n2)` may be taken when `n1` is an expression that is true. + */ predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { qlCFGTrueSuccessor(n1, n2) } +/** + * Holds when `n2` is a control-flow node such that the control-flow + * edge `(n1, n2)` may be taken when `n1` is an expression that is false. + */ predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { qlCFGFalseSuccessor(n1, n2) } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll index 99fb6966099..1a5d81ee9f3 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll @@ -15,14 +15,25 @@ import Dereferenced abstract class DataflowAnnotation extends string { DataflowAnnotation() { this = "pointer-null" or this = "pointer-valid" } + /** Holds if this annotation is the default annotation. */ abstract predicate isDefault(); + /** Holds if this annotation is generated when analyzing expression `e`. */ abstract predicate generatedOn(Expr e); + /** + * Holds if this annotation is generated for the variable `v` when + * the control-flow edge `(src, dest)` is taken. + */ abstract predicate generatedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest); + /** + * Holds if this annotation is removed for the variable `v` when + * the control-flow edge `(src, dest)` is taken. + */ abstract predicate killedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest); + /** Holds if expression `e` is given this annotation. */ predicate marks(Expr e) { this.generatedOn(e) and reachable(e) or @@ -31,6 +42,7 @@ abstract class DataflowAnnotation extends string { exists(LocalScopeVariable v | this.marks(v, e) and e = v.getAnAccess()) } + /** Holds if the variable `v` accessed in control-flow node `n` is given this annotation. */ predicate marks(LocalScopeVariable v, ControlFlowNode n) { v.getAnAccess().getEnclosingFunction().getBlock() = n and this.isDefault() @@ -57,6 +69,10 @@ abstract class DataflowAnnotation extends string { ) } + /** + * Holds if the variable `v` preserves this annotation when the control-flow + * edge `(src, dest)` is taken. + */ predicate preservedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) { this.marks(v, src) and src.getASuccessor() = dest and @@ -64,6 +80,10 @@ abstract class DataflowAnnotation extends string { not v.getAnAssignment() = src } + /** + * Holds if the variable `v` is assigned this annotation when `src` is an assignment + * expression that assigns to `v` and the control-flow edge `(src, dest)` is taken. + */ predicate assignedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) { this.marks(src.(AssignExpr).getRValue()) and src = v.getAnAssignment() and From 52da5755b33e8d9f6aecd7a1dd261d90ddba7d9c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 28 May 2020 11:20:13 +0200 Subject: [PATCH 111/111] C++: Respond to review comments. --- cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll | 8 ++++---- .../src/semmle/code/cpp/controlflow/ControlFlowGraph.qll | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll index 3d8202cdf90..16947019f54 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll @@ -1,5 +1,5 @@ /** - * Provides a library for reasoning about control-flow at the granularity of basic blocks. + * Provides a library for reasoning about control flow at the granularity of basic blocks. * This is usually much more efficient than reasoning directly at the level of `ControlFlowNode`s. */ @@ -159,13 +159,13 @@ class BasicBlock extends ControlFlowNodeBase { /** Gets the `ControlFlowNode` at position `pos` in this basic block. */ ControlFlowNode getNode(int pos) { basic_block_member(result, this, pos) } - /** Gets all `ControlFlowNode`s in this basic block. */ + /** Gets a `ControlFlowNode` in this basic block. */ ControlFlowNode getANode() { basic_block_member(result, this, _) } - /** Gets all `BasicBlock`s that are direct successors of this basic block. */ + /** Gets a `BasicBlock` that is a direct successor of this basic block. */ BasicBlock getASuccessor() { bb_successor(this, result) } - /** Gets all `BasicBlock`s that are direct predecessors of this basic block. */ + /** Gets a `BasicBlock` that is a direct predecessor of this basic block. */ BasicBlock getAPredecessor() { bb_successor(result, this) } /** diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll index f05b9814ef1..1f79d6c5bc2 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll @@ -1,5 +1,5 @@ /** - * Provides a library for reasoning about control-flow at the granularity of + * Provides a library for reasoning about control flow at the granularity of * individual nodes in the control-flow graph. */