mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
upgrade query to detect redash CVE too
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
## 0.9.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.9.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* It is now possible to specify flow summaries in the format "MyPkg;Member[list_map];Argument[1].ListElement;Argument[0].Parameter[0];value"
|
||||
3
python/ql/lib/change-notes/released/0.9.3.md
Normal file
3
python/ql/lib/change-notes/released/0.9.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.9.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.9.2
|
||||
lastReleaseVersion: 0.9.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/python-all
|
||||
version: 0.9.3-dev
|
||||
version: 0.9.4-dev
|
||||
groups: python
|
||||
dbscheme: semmlecode.python.dbscheme
|
||||
extractor: python
|
||||
|
||||
@@ -90,39 +90,32 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari
|
||||
}
|
||||
|
||||
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
|
||||
// // This gives access to getNodeFromPath, which is not constrained to `CallNode`s
|
||||
// // as `resolvedSummaryBase` is.
|
||||
// private import semmle.python.frameworks.data.internal.ApiGraphModels as AGM
|
||||
//
|
||||
// private class SummarizedCallableFromModel extends SummarizedCallable {
|
||||
// string package;
|
||||
// string type;
|
||||
// string path;
|
||||
// SummarizedCallableFromModel() {
|
||||
// ModelOutput::relevantSummaryModel(package, type, path, _, _, _) and
|
||||
// this = package + ";" + type + ";" + path
|
||||
// }
|
||||
// override CallCfgNode getACall() {
|
||||
// exists(API::CallNode base |
|
||||
// ModelOutput::resolvedSummaryBase(package, type, path, base) and
|
||||
// result = base.getACall()
|
||||
// )
|
||||
// }
|
||||
// override ArgumentNode getACallback() {
|
||||
// exists(API::Node base |
|
||||
// base = AGM::getNodeFromPath(package, type, path) and
|
||||
// result = base.getAValueReachableFromSource()
|
||||
// )
|
||||
// }
|
||||
// override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
// exists(string kind |
|
||||
// ModelOutput::relevantSummaryModel(package, type, path, input, output, kind)
|
||||
// |
|
||||
// kind = "value" and
|
||||
// preservesValue = true
|
||||
// or
|
||||
// kind = "taint" and
|
||||
// preservesValue = false
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
private class SummarizedCallableFromModel extends SummarizedCallable {
|
||||
string type;
|
||||
string path;
|
||||
|
||||
SummarizedCallableFromModel() {
|
||||
ModelOutput::relevantSummaryModel(type, path, _, _, _) and
|
||||
this = type + ";" + path
|
||||
}
|
||||
|
||||
override CallCfgNode getACall() { ModelOutput::resolvedSummaryBase(type, path, result) }
|
||||
|
||||
override ArgumentNode getACallback() {
|
||||
exists(API::Node base |
|
||||
ModelOutput::resolvedSummaryRefBase(type, path, base) and
|
||||
result = base.getAValueReachableFromSource()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
exists(string kind | ModelOutput::relevantSummaryModel(type, path, input, output, kind) |
|
||||
kind = "value" and
|
||||
preservesValue = true
|
||||
or
|
||||
kind = "taint" and
|
||||
preservesValue = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -643,6 +643,15 @@ module ModelOutput {
|
||||
baseNode = getInvocationFromPath(type, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `baseNode` is a callable identified by the `type,path` part of a summary row.
|
||||
*/
|
||||
cached
|
||||
predicate resolvedSummaryRefBase(string type, string path, API::Node baseNode) {
|
||||
summaryModel(type, path, _, _, _) and
|
||||
baseNode = getNodeFromPath(type, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is seen as an instance of `type` due to a type definition
|
||||
* contributed by a CSV model.
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 0.7.3
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The display name (`@name`) of the `py/unsafe-deserialization` query has been updated in favor of consistency with other languages.
|
||||
|
||||
## 0.7.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
5
python/ql/src/change-notes/released/0.7.3.md
Normal file
5
python/ql/src/change-notes/released/0.7.3.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.7.3
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The display name (`@name`) of the `py/unsafe-deserialization` query has been updated in favor of consistency with other languages.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.2
|
||||
lastReleaseVersion: 0.7.3
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Flask and Django require a Securely signed key for singing the session cookies. most of the time developers rely on load hardcoded secret keys from a config file or python code. this proves that the way of hardcoded secret can make problems when you forgot to change the constant secret keys.
|
||||
</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
In Flask Consider using a secure random generator with <a href="https://docs.python.org/3/library/secrets.html#secrets.token_hex">Python standard secrets library</a>
|
||||
</p>
|
||||
<p>
|
||||
In Django Consider using a secure random generator with "get_random_secret_key()"" method from "django.core.management.utils".
|
||||
</p>
|
||||
</recommendation>
|
||||
<example>
|
||||
<sample src="examples/example_Django_safe.py" />
|
||||
<sample src="examples/example_Django_snsafe.py" />
|
||||
<sample src="examples/example_Flask_safe.py" />
|
||||
<sample src="examples/example_Flask_unsafe.py" />
|
||||
<sample src="examples/example_Flask_unsafe2.py" />
|
||||
<sample src="examples/config1.py" />
|
||||
<sample src="examples/config2.py" />
|
||||
<sample src="examples/config3.py" />
|
||||
<sample src="examples/settings/__init__.py" />
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://flask.palletsprojects.com/en/2.3.x/config/#SECRET_KEY">Flask Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://docs.djangoproject.com/en/4.2/ref/settings/#secret-key">Django Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://flask-jwt-extended.readthedocs.io/en/stable/basic_usage.html#basic-usage">Flask-JWT-Extended Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.horizon3.ai/cve-2023-27524-insecure-default-configuration-in-apache-superset-leads-to-remote-code-execution/">CVE-2023-27524 - Apache Superset had multiple CVEs related to this kind of Vulnerability</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://nvd.nist.gov/vuln/detail/CVE-2020-17526">CVE-2020-17526 - Apache Airflow had multiple CVEs related to this kind of Vulnerability</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://nvd.nist.gov/vuln/detail/CVE-2021-41192">CVE-2021-41192 - Redash was assigning a environment variable with a default value which it was assigning the default secrect if the environment variable does not exists</a>
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -12,6 +12,19 @@ module DjangoConstantSecretKeyConfig {
|
||||
*/
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
(
|
||||
// because Env return an Exeption if there isan't any value (instead of none) we should check whether
|
||||
// there is a default value of there is a config file which mostly these config files have a default value
|
||||
exists(API::Node env | env = API::moduleImport("environ").getMember("Env") |
|
||||
(
|
||||
// has default value
|
||||
exists(env.getKeywordParameter("SECRET_KEY").asSource())
|
||||
or
|
||||
// get value from a config file which is not best security practice
|
||||
exists(env.getReturn().getMember("read_env"))
|
||||
) and
|
||||
source = env.getReturn().getReturn().asSource()
|
||||
)
|
||||
or
|
||||
source.asExpr().isConstant()
|
||||
or
|
||||
exists(API::Node cn |
|
||||
@@ -47,13 +60,13 @@ module DjangoConstantSecretKeyConfig {
|
||||
source.asExpr() = cn.asExpr()
|
||||
)
|
||||
or
|
||||
source.asExpr() =
|
||||
API::moduleImport("os").getMember("environ").getASubscript().asSource().asExpr()
|
||||
source = API::moduleImport("os").getMember("environ").getASubscript().asSource()
|
||||
) and
|
||||
// followings will sanitize the get_random_secret_key of django.core.management.utils and similar random generators which we have their source code and some of them can be tracking by taint tracking because they are initilized by a constant!
|
||||
exists(source.getScope().getLocation().getFile().getRelativePath()) and
|
||||
// special case for get_random_secret_key
|
||||
not source.getScope().getLocation().getFile().getBaseName() = "crypto.py"
|
||||
not source.getScope().getLocation().getFile().inStdlib() and
|
||||
// special sanitize case for get_random_secret_key and django-environ
|
||||
not source.getScope().getLocation().getFile().getBaseName() = ["environ.py", "crypto.py"]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +103,7 @@ module DjangoConstantSecretKeyConfig {
|
||||
sink = attr.getValue()
|
||||
)
|
||||
) and
|
||||
exists(sink.getScope().getLocation().getFile().getRelativePath())
|
||||
exists(sink.getScope().getLocation().getFile().getRelativePath()) and
|
||||
not sink.getScope().getLocation().getFile().inStdlib()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,19 @@ module FlaskConstantSecretKeyConfig {
|
||||
*/
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
(
|
||||
// because Env return an Exeption if there isan't any value (instead of none) we should check whether
|
||||
// there is a default value of there is a config file which mostly these config files have a default value
|
||||
exists(API::Node env | env = API::moduleImport("environ").getMember("Env") |
|
||||
(
|
||||
// has default value
|
||||
exists(env.getKeywordParameter("SECRET_KEY").asSource())
|
||||
or
|
||||
// get value from a config file which is not best security practice
|
||||
exists(env.getReturn().getMember("read_env"))
|
||||
) and
|
||||
source = env.getReturn().getReturn().asSource()
|
||||
)
|
||||
or
|
||||
source.asExpr().isConstant()
|
||||
or
|
||||
exists(API::Node cn |
|
||||
@@ -65,7 +78,10 @@ module FlaskConstantSecretKeyConfig {
|
||||
source.asExpr() =
|
||||
API::moduleImport("os").getMember("environ").getASubscript().asSource().asExpr()
|
||||
) and
|
||||
exists(source.getScope().getLocation().getFile().getRelativePath())
|
||||
exists(source.getScope().getLocation().getFile().getRelativePath()) and
|
||||
not source.getScope().getLocation().getFile().inStdlib() and
|
||||
// special sanitize case for django-environ
|
||||
not source.getScope().getLocation().getFile().getBaseName() = "crypto.py"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,14 +118,14 @@ module FlaskConstantSecretKeyConfig {
|
||||
attr.getAttributeName() = ["secret_key", "jwt_secret_key"] and
|
||||
sink = attr.getValue()
|
||||
)
|
||||
or
|
||||
exists(SecretKeyAssignStmt e |
|
||||
sink.asExpr() = e.getValue()
|
||||
// | sameAsHardCodedConstantSanitizer(e.getTarget(0))
|
||||
)
|
||||
) and
|
||||
exists(sink.getScope().getLocation().getFile().getRelativePath())
|
||||
or
|
||||
exists(SecretKeyAssignStmt e |
|
||||
sink.asExpr() = e.getValue()
|
||||
// | sameAsHardCodedConstantSanitizer(e.getTarget(0))
|
||||
) and
|
||||
exists(sink.getScope().getLocation().getFile().getRelativePath())
|
||||
exists(sink.getScope().getLocation().getFile().getRelativePath()) and
|
||||
not sink.getScope().getLocation().getFile().inStdlib()
|
||||
}
|
||||
|
||||
// for case check whether SECRECT_KEY is empty or not or whether it is == to a hardcoded constant value
|
||||
@@ -129,23 +145,32 @@ module FlaskConstantSecretKeyConfig {
|
||||
*/
|
||||
class SecretKeyAssignStmt extends AssignStmt {
|
||||
SecretKeyAssignStmt() {
|
||||
exists(string configFileName, string fileNamehelper, DataFlow::Node n1 |
|
||||
fileNamehelper = flaskConfiFileName(n1) and
|
||||
exists(string configFileName, string fileNamehelper, DataFlow::Node n1, File file |
|
||||
fileNamehelper = [flaskConfiFileName(n1), flaskConfiFileName2(n1)] and
|
||||
// because of `from_object` we want first part of `Config.AClassName` which `Config` is a python file name
|
||||
configFileName = fileNamehelper.splitAt(".") and
|
||||
// after spliting, don't look at %py% pattern
|
||||
configFileName != "py"
|
||||
file = this.getLocation().getFile()
|
||||
|
|
||||
(
|
||||
if configFileName = "__name__"
|
||||
if fileNamehelper = "__name__"
|
||||
then
|
||||
this.getLocation().getFile().getShortName() =
|
||||
flaskInstance().asSource().getLocation().getFile().getShortName()
|
||||
else this.getLocation().getFile().getShortName().matches("%" + configFileName + "%")
|
||||
file.getShortName() = flaskInstance().asSource().getLocation().getFile().getShortName()
|
||||
else (
|
||||
fileNamehelper.matches("%.py") and
|
||||
file.getShortName().matches("%" + configFileName + "%") and
|
||||
// after spliting, don't look at %py% pattern
|
||||
configFileName != ".py"
|
||||
or
|
||||
// in case of referencing to a directory which then we must look for __init__.py file
|
||||
not fileNamehelper.matches("%.py") and
|
||||
file.getRelativePath()
|
||||
.matches("%" + fileNamehelper.replaceAll(".", "/") + "/__init__.py")
|
||||
)
|
||||
) and
|
||||
this.getTarget(0).toString() = ["SECRET_KEY", "JWT_SECRET_KEY"]
|
||||
this.getTarget(0).(Name).getId() = ["SECRET_KEY", "JWT_SECRET_KEY"]
|
||||
) and
|
||||
exists(this.getScope().getLocation().getFile().getRelativePath())
|
||||
exists(this.getScope().getLocation().getFile().getRelativePath()) and
|
||||
not this.getScope().getLocation().getFile().inStdlib()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,14 +183,27 @@ module FlaskConstantSecretKeyConfig {
|
||||
* `app.config.from_object("configFileName.ClassName")`
|
||||
*/
|
||||
string flaskConfiFileName(API::CallNode cn) {
|
||||
exists(API::Node app |
|
||||
app = flaskInstance().getACall().getReturn() and
|
||||
cn = app.getMember("config").getMember(["from_object", "from_pyfile"]).getACall() and
|
||||
result =
|
||||
[
|
||||
cn.getParameter(0).getAValueReachingSink().asExpr().(StrConst).getText(),
|
||||
cn.getParameter(0).asSink().asExpr().(Name).getId()
|
||||
]
|
||||
)
|
||||
cn =
|
||||
flaskInstance()
|
||||
.getReturn()
|
||||
.getMember("config")
|
||||
.getMember(["from_object", "from_pyfile"])
|
||||
.getACall() and
|
||||
result =
|
||||
[
|
||||
cn.getParameter(0).getAValueReachingSink().asExpr().(StrConst).getText(),
|
||||
cn.getParameter(0).asSink().asExpr().(Name).getId()
|
||||
]
|
||||
}
|
||||
|
||||
string flaskConfiFileName2(API::CallNode cn) {
|
||||
cn =
|
||||
API::moduleImport("flask")
|
||||
.getMember("Flask")
|
||||
.getASubclass*()
|
||||
.getASuccessor*()
|
||||
.getMember("from_object")
|
||||
.getACall() and
|
||||
result = cn.getParameter(0).asSink().asExpr().(StrConst).getText()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
"""Flask App configuration."""
|
||||
from os import environ
|
||||
import os
|
||||
import random
|
||||
import configparser
|
||||
|
||||
FLASK_DEBUG = True
|
||||
aConstant = 'CHANGEME2'
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
|
||||
class Config:
|
||||
SECRET_KEY = config["a"]["Secret"]
|
||||
SECRET_KEY = config.get("key", "value")
|
||||
SECRET_KEY = environ.get("envKey")
|
||||
SECRET_KEY = aConstant
|
||||
SECRET_KEY = os.getenv('envKey')
|
||||
SECRET_KEY = os.environ.get('envKey')
|
||||
SECRET_KEY = os.environ.get('envKey', random.randint)
|
||||
SECRET_KEY = os.getenv('envKey', random.randint)
|
||||
SECRET_KEY = os.getenv('envKey', aConstant)
|
||||
SECRET_KEY = os.environ.get('envKey', aConstant)
|
||||
SECRET_KEY = os.environ['envKey']
|
||||
@@ -5,9 +5,13 @@ from django.conf import global_settings
|
||||
from django.urls import path
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
||||
env = environ.Env(
|
||||
SECRET_KEY=(bool, False)
|
||||
SECRET_KEY=(str, "AConstantKey")
|
||||
)
|
||||
env.read_env(env_file='.env')
|
||||
# following is not safe if there is a call to read_env or if there is default value in Env(..)
|
||||
settings.SECRET_KEY = env('SECRET_KEY')
|
||||
|
||||
settings.configure(
|
||||
DEBUG=True,
|
||||
|
||||
@@ -10,6 +10,7 @@ app.config.from_pyfile("config.py")
|
||||
app.config.from_pyfile("config2.py")
|
||||
app.config.from_object('config.Config')
|
||||
app.config.from_object('config2.Config')
|
||||
app.config.from_object('settings')
|
||||
|
||||
|
||||
@app.route('/')
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import os
|
||||
|
||||
SECRET_KEY = "REDASH_COOKIE_SECRET"
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/python-queries
|
||||
version: 0.7.3-dev
|
||||
version: 0.7.4-dev
|
||||
groups:
|
||||
- python
|
||||
- queries
|
||||
|
||||
@@ -3,12 +3,10 @@ import semmle.python.dataflow.new.DataFlow
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
private import semmle.python.dataflow.new.internal.PrintNode
|
||||
|
||||
class DataFlowQueryTest extends InlineExpectationsTest {
|
||||
DataFlowQueryTest() { this = "DataFlowQueryTest" }
|
||||
module DataFlowQueryTest implements TestSig {
|
||||
string getARelevantTag() { result = "result" }
|
||||
|
||||
override string getARelevantTag() { result = "result" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Configuration cfg, DataFlow::Node sink | cfg.hasFlowTo(sink) |
|
||||
location = sink.getLocation() and
|
||||
tag = "result" and
|
||||
@@ -22,7 +20,7 @@ class DataFlowQueryTest extends InlineExpectationsTest {
|
||||
// Sometimes a line contains both an alert and a safe sink.
|
||||
// In this situation, the annotation form `OK(safe sink)`
|
||||
// can be useful.
|
||||
override predicate hasOptionalResult(Location location, string element, string tag, string value) {
|
||||
predicate hasOptionalResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Configuration cfg, DataFlow::Node sink |
|
||||
cfg.isSink(sink) or cfg.isSink(sink, _)
|
||||
|
|
||||
@@ -34,6 +32,8 @@ class DataFlowQueryTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<DataFlowQueryTest>
|
||||
|
||||
query predicate missingAnnotationOnSink(Location location, string error, string element) {
|
||||
error = "ERROR, you should add `# $ MISSING: result=BAD` or `result=OK` annotation" and
|
||||
exists(DataFlow::Node sink |
|
||||
@@ -42,13 +42,13 @@ query predicate missingAnnotationOnSink(Location location, string error, string
|
||||
location = sink.getLocation() and
|
||||
element = prettyExpr(sink.asExpr()) and
|
||||
not exists(DataFlow::Configuration cfg | cfg.hasFlowTo(sink)) and
|
||||
not exists(FalseNegativeExpectation missingResult |
|
||||
not exists(FalseNegativeTestExpectation missingResult |
|
||||
missingResult.getTag() = "result" and
|
||||
missingResult.getValue() = "BAD" and
|
||||
missingResult.getLocation().getFile() = location.getFile() and
|
||||
missingResult.getLocation().getStartLine() = location.getStartLine()
|
||||
) and
|
||||
not exists(GoodExpectation okResult |
|
||||
not exists(GoodTestExpectation okResult |
|
||||
okResult.getTag() = "result" and
|
||||
okResult.getValue() in ["OK", "OK(" + prettyNode(sink) + ")"] and
|
||||
okResult.getLocation().getFile() = location.getFile() and
|
||||
|
||||
@@ -3,22 +3,21 @@ import semmle.python.dataflow.new.DataFlow
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
private import semmle.python.dataflow.new.internal.PrintNode
|
||||
|
||||
abstract class FlowTest extends InlineExpectationsTest {
|
||||
bindingset[this]
|
||||
FlowTest() { any() }
|
||||
signature module FlowTestSig {
|
||||
string flowTag();
|
||||
|
||||
abstract string flowTag();
|
||||
predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode);
|
||||
}
|
||||
|
||||
abstract predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode);
|
||||
private module FlowTest<FlowTestSig Impl> implements TestSig {
|
||||
string getARelevantTag() { result = Impl::flowTag() }
|
||||
|
||||
override string getARelevantTag() { result = this.flowTag() }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node fromNode, DataFlow::Node toNode | this.relevantFlow(fromNode, toNode) |
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node fromNode, DataFlow::Node toNode | Impl::relevantFlow(fromNode, toNode) |
|
||||
location = toNode.getLocation() and
|
||||
tag = this.flowTag() and
|
||||
tag = Impl::flowTag() and
|
||||
value =
|
||||
"\"" + prettyNode(fromNode).replaceAll("\"", "'") + this.lineStr(fromNode, toNode) + " -> " +
|
||||
"\"" + prettyNode(fromNode).replaceAll("\"", "'") + lineStr(fromNode, toNode) + " -> " +
|
||||
prettyNode(toNode).replaceAll("\"", "'") + "\"" and
|
||||
element = toNode.toString()
|
||||
)
|
||||
@@ -38,3 +37,11 @@ abstract class FlowTest extends InlineExpectationsTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module MakeFlowTest<FlowTestSig Impl> {
|
||||
import MakeTest<FlowTest<Impl>>
|
||||
}
|
||||
|
||||
module MakeFlowTest2<FlowTestSig Impl1, FlowTestSig Impl2> {
|
||||
import MakeTest<MergeTests<FlowTest<Impl1>, FlowTest<Impl2>>>
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import FlowTest
|
||||
|
||||
class LocalFlowStepTest extends FlowTest {
|
||||
LocalFlowStepTest() { this = "LocalFlowStepTest" }
|
||||
module LocalFlowStepTest implements FlowTestSig {
|
||||
string flowTag() { result = "step" }
|
||||
|
||||
override string flowTag() { result = "step" }
|
||||
|
||||
override predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
DataFlow::localFlowStep(fromNode, toNode)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeFlowTest<LocalFlowStepTest>
|
||||
|
||||
@@ -3,25 +3,23 @@ import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.internal.DataFlowPrivate
|
||||
import FlowTest
|
||||
|
||||
class MaximalFlowTest extends FlowTest {
|
||||
MaximalFlowTest() { this = "MaximalFlowTest" }
|
||||
module MaximalFlowTest implements FlowTestSig {
|
||||
string flowTag() { result = "flow" }
|
||||
|
||||
override string flowTag() { result = "flow" }
|
||||
|
||||
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
source != sink and
|
||||
exists(MaximalFlowsConfig cfg | cfg.hasFlow(source, sink))
|
||||
MaximalFlows::flow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeFlowTest<MaximalFlowTest>
|
||||
|
||||
/**
|
||||
* A configuration to find all "maximal" flows.
|
||||
* To be used on small programs.
|
||||
*/
|
||||
class MaximalFlowsConfig extends DataFlow::Configuration {
|
||||
MaximalFlowsConfig() { this = "MaximalFlowsConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) {
|
||||
module MaximalFlowsConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
exists(node.getLocation().getFile().getRelativePath()) and
|
||||
not node.asCfgNode() instanceof CallNode and
|
||||
not node.asCfgNode().getNode() instanceof Return and
|
||||
@@ -32,7 +30,7 @@ class MaximalFlowsConfig extends DataFlow::Configuration {
|
||||
not DataFlow::localFlowStep(_, node)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node node) {
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(node.getLocation().getFile().getRelativePath()) and
|
||||
not any(CallNode c).getArg(_) = node.asCfgNode() and
|
||||
not node instanceof DataFlow::ArgumentNode and
|
||||
@@ -40,3 +38,5 @@ class MaximalFlowsConfig extends DataFlow::Configuration {
|
||||
not DataFlow::localFlowStep(node, _)
|
||||
}
|
||||
}
|
||||
|
||||
module MaximalFlows = DataFlow::Global<MaximalFlowsConfig>;
|
||||
|
||||
@@ -3,20 +3,20 @@ import experimental.dataflow.TestUtil.FlowTest
|
||||
import experimental.dataflow.testConfig
|
||||
private import semmle.python.dataflow.new.internal.PrintNode
|
||||
|
||||
class DataFlowTest extends FlowTest {
|
||||
DataFlowTest() { this = "DataFlowTest" }
|
||||
module DataFlowTest implements FlowTestSig {
|
||||
string flowTag() { result = "flow" }
|
||||
|
||||
override string flowTag() { result = "flow" }
|
||||
|
||||
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
exists(TestConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
TestFlow::flow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeFlowTest<DataFlowTest>
|
||||
|
||||
query predicate missingAnnotationOnSink(Location location, string error, string element) {
|
||||
error = "ERROR, you should add `# $ MISSING: flow` annotation" and
|
||||
exists(DataFlow::Node sink |
|
||||
any(TestConfiguration config).isSink(sink) and
|
||||
TestConfig::isSink(sink) and
|
||||
// note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually.
|
||||
exists(DataFlow::CallCfgNode call |
|
||||
call.getFunction().asCfgNode().(NameNode).getId() = "SINK" and
|
||||
@@ -24,8 +24,8 @@ query predicate missingAnnotationOnSink(Location location, string error, string
|
||||
) and
|
||||
location = sink.getLocation() and
|
||||
element = prettyExpr(sink.asExpr()) and
|
||||
not any(TestConfiguration config).hasFlow(_, sink) and
|
||||
not exists(FalseNegativeExpectation missingResult |
|
||||
not TestFlow::flowTo(sink) and
|
||||
not exists(FalseNegativeTestExpectation missingResult |
|
||||
missingResult.getTag() = "flow" and
|
||||
missingResult.getLocation().getFile() = location.getFile() and
|
||||
missingResult.getLocation().getStartLine() = location.getStartLine()
|
||||
|
||||
@@ -3,16 +3,16 @@ import experimental.dataflow.TestUtil.FlowTest
|
||||
import experimental.dataflow.testTaintConfig
|
||||
private import semmle.python.dataflow.new.internal.PrintNode
|
||||
|
||||
class DataFlowTest extends FlowTest {
|
||||
DataFlowTest() { this = "DataFlowTest" }
|
||||
module DataFlowTest implements FlowTestSig {
|
||||
string flowTag() { result = "flow" }
|
||||
|
||||
override string flowTag() { result = "flow" }
|
||||
|
||||
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
exists(TestConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
TestFlow::flow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeFlowTest<DataFlowTest>
|
||||
|
||||
query predicate missingAnnotationOnSink(Location location, string error, string element) {
|
||||
error = "ERROR, you should add `# $ MISSING: flow` annotation" and
|
||||
exists(DataFlow::Node sink |
|
||||
@@ -23,8 +23,8 @@ query predicate missingAnnotationOnSink(Location location, string error, string
|
||||
) and
|
||||
location = sink.getLocation() and
|
||||
element = prettyExpr(sink.asExpr()) and
|
||||
not any(TestConfiguration config).hasFlow(_, sink) and
|
||||
not exists(FalseNegativeExpectation missingResult |
|
||||
not TestFlow::flowTo(sink) and
|
||||
not exists(FalseNegativeTestExpectation missingResult |
|
||||
missingResult.getTag() = "flow" and
|
||||
missingResult.getLocation().getFile() = location.getFile() and
|
||||
missingResult.getLocation().getStartLine() = location.getStartLine()
|
||||
|
||||
@@ -4,11 +4,11 @@ private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPr
|
||||
private import semmle.python.ApiGraphs
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class UnresolvedCallExpectations extends InlineExpectationsTest {
|
||||
UnresolvedCallExpectations() { this = "UnresolvedCallExpectations" }
|
||||
|
||||
override string getARelevantTag() { result = "unresolved_call" }
|
||||
signature module UnresolvedCallExpectationsSig {
|
||||
predicate unresolvedCall(CallNode call);
|
||||
}
|
||||
|
||||
module DefaultUnresolvedCallExpectations implements UnresolvedCallExpectationsSig {
|
||||
predicate unresolvedCall(CallNode call) {
|
||||
not exists(DataFlowPrivate::DataFlowCall dfc |
|
||||
exists(dfc.getCallable()) and dfc.getNode() = call
|
||||
@@ -16,14 +16,22 @@ class UnresolvedCallExpectations extends InlineExpectationsTest {
|
||||
not DataFlowPrivate::resolveClassCall(call, _) and
|
||||
not call = API::builtin(_).getACall().asCfgNode()
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(CallNode call | this.unresolvedCall(call) |
|
||||
location = call.getLocation() and
|
||||
tag = "unresolved_call" and
|
||||
value = prettyExpr(call.getNode()) and
|
||||
element = call.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module MakeUnresolvedCallExpectations<UnresolvedCallExpectationsSig Impl> {
|
||||
private module UnresolvedCallExpectations implements TestSig {
|
||||
string getARelevantTag() { result = "unresolved_call" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(CallNode call | Impl::unresolvedCall(call) |
|
||||
location = call.getLocation() and
|
||||
tag = "unresolved_call" and
|
||||
value = prettyExpr(call.getNode()) and
|
||||
element = call.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<UnresolvedCallExpectations>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -2,11 +2,13 @@ import python
|
||||
import experimental.dataflow.TestUtil.UnresolvedCalls
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
|
||||
class IgnoreDictMethod extends UnresolvedCallExpectations {
|
||||
override predicate unresolvedCall(CallNode call) {
|
||||
super.unresolvedCall(call) and
|
||||
module IgnoreDictMethod implements UnresolvedCallExpectationsSig {
|
||||
predicate unresolvedCall(CallNode call) {
|
||||
DefaultUnresolvedCallExpectations::unresolvedCall(call) and
|
||||
not any(DataFlow::MethodCallNode methodCall |
|
||||
methodCall.getMethodName() in ["get", "setdefault"]
|
||||
).asCfgNode() = call
|
||||
}
|
||||
}
|
||||
|
||||
import MakeUnresolvedCallExpectations<IgnoreDictMethod>
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
testFailures
|
||||
@@ -0,0 +1,4 @@
|
||||
import python
|
||||
private import TestSummaries
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
@@ -0,0 +1,3 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
testFailures
|
||||
@@ -0,0 +1,3 @@
|
||||
import python
|
||||
private import TestSummaries
|
||||
import experimental.dataflow.TestUtil.NormalDataflowTest
|
||||
@@ -0,0 +1,25 @@
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.FlowSummary
|
||||
private import semmle.python.frameworks.data.ModelsAsData
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
private class StepsFromModel extends ModelInput::SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"foo;Member[MS_identity];Argument[0];ReturnValue;value",
|
||||
"foo;Member[MS_apply_lambda];Argument[1];Argument[0].Parameter[0];value",
|
||||
"foo;Member[MS_apply_lambda];Argument[0].ReturnValue;ReturnValue;value",
|
||||
"foo;Member[MS_reversed];Argument[0].ListElement;ReturnValue.ListElement;value",
|
||||
"foo;Member[MS_reversed];Argument[0];ReturnValue;taint",
|
||||
"foo;Member[MS_list_map];Argument[1].ListElement;Argument[0].Parameter[0];value",
|
||||
"foo;Member[MS_list_map];Argument[0].ReturnValue;ReturnValue.ListElement;value",
|
||||
"foo;Member[MS_list_map];Argument[1];ReturnValue;taint",
|
||||
"foo;Member[MS_append_to_list];Argument[0].ListElement;ReturnValue.ListElement;value",
|
||||
"foo;Member[MS_append_to_list];Argument[1];ReturnValue.ListElement;value",
|
||||
"foo;Member[MS_append_to_list];Argument[0];ReturnValue;taint",
|
||||
"foo;Member[MS_append_to_list];Argument[1];ReturnValue;taint",
|
||||
"json;Member[MS_loads];Argument[0];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
|
||||
from testlib import expects
|
||||
|
||||
# These are defined so that we can evaluate the test code.
|
||||
NONSOURCE = "not a source"
|
||||
SOURCE = "source"
|
||||
|
||||
|
||||
def is_source(x):
|
||||
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
|
||||
|
||||
|
||||
def SINK(x):
|
||||
if is_source(x):
|
||||
print("OK")
|
||||
else:
|
||||
print("Unexpected flow", x)
|
||||
|
||||
|
||||
def SINK_F(x):
|
||||
if is_source(x):
|
||||
print("Unexpected flow", x)
|
||||
else:
|
||||
print("OK")
|
||||
|
||||
ensure_tainted = ensure_not_tainted = print
|
||||
TAINTED_STRING = "TAINTED_STRING"
|
||||
|
||||
from foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_append_to_list
|
||||
|
||||
# Simple summary
|
||||
via_identity = MS_identity(SOURCE)
|
||||
SINK(via_identity) # $ flow="SOURCE, l:-1 -> via_identity"
|
||||
|
||||
# Lambda summary
|
||||
via_lambda = MS_apply_lambda(lambda x: [x], SOURCE)
|
||||
SINK(via_lambda[0]) # $ flow="SOURCE, l:-1 -> via_lambda[0]"
|
||||
|
||||
# A lambda that breaks the flow
|
||||
not_via_lambda = MS_apply_lambda(lambda x: 1, SOURCE)
|
||||
SINK_F(not_via_lambda)
|
||||
|
||||
|
||||
# Collection summaries
|
||||
via_reversed = MS_reversed([SOURCE])
|
||||
SINK(via_reversed[0]) # $ flow="SOURCE, l:-1 -> via_reversed[0]"
|
||||
|
||||
tainted_list = MS_reversed(TAINTED_LIST)
|
||||
ensure_tainted(
|
||||
tainted_list, # $ tainted
|
||||
tainted_list[0], # $ tainted
|
||||
)
|
||||
|
||||
# Complex summaries
|
||||
def box(x):
|
||||
return [x]
|
||||
|
||||
via_map = MS_list_map(box, [SOURCE])
|
||||
SINK(via_map[0][0]) # $ flow="SOURCE, l:-1 -> via_map[0][0]"
|
||||
|
||||
tainted_mapped = MS_list_map(box, TAINTED_LIST)
|
||||
ensure_tainted(
|
||||
tainted_mapped, # $ tainted
|
||||
tainted_mapped[0][0], # $ tainted
|
||||
)
|
||||
|
||||
def explicit_identity(x):
|
||||
return x
|
||||
|
||||
via_map_explicit = MS_list_map(explicit_identity, [SOURCE])
|
||||
SINK(via_map_explicit[0]) # $ flow="SOURCE, l:-1 -> via_map_explicit[0]"
|
||||
|
||||
tainted_mapped_explicit = MS_list_map(explicit_identity, TAINTED_LIST)
|
||||
ensure_tainted(
|
||||
tainted_mapped_explicit, # $ tainted
|
||||
tainted_mapped_explicit[0], # $ tainted
|
||||
)
|
||||
|
||||
via_map_summary = MS_list_map(MS_identity, [SOURCE])
|
||||
SINK(via_map_summary[0]) # $ flow="SOURCE, l:-1 -> via_map_summary[0]"
|
||||
|
||||
tainted_mapped_summary = MS_list_map(MS_identity, TAINTED_LIST)
|
||||
ensure_tainted(
|
||||
tainted_mapped_summary, # $ tainted
|
||||
tainted_mapped_summary[0], # $ tainted
|
||||
)
|
||||
|
||||
via_append_el = MS_append_to_list([], SOURCE)
|
||||
SINK(via_append_el[0]) # $ flow="SOURCE, l:-1 -> via_append_el[0]"
|
||||
|
||||
tainted_list_el = MS_append_to_list([], TAINTED_STRING)
|
||||
ensure_tainted(
|
||||
tainted_list_el, # $ tainted
|
||||
tainted_list_el[0], # $ tainted
|
||||
)
|
||||
|
||||
via_append = MS_append_to_list([SOURCE], NONSOURCE)
|
||||
SINK(via_append[0]) # $ flow="SOURCE, l:-1 -> via_append[0]"
|
||||
|
||||
tainted_list_implicit = MS_append_to_list(TAINTED_LIST, NONSOURCE)
|
||||
ensure_tainted(
|
||||
tainted_list, # $ tainted
|
||||
tainted_list[0], # $ tainted
|
||||
)
|
||||
|
||||
# Modeled flow-summary is not value preserving
|
||||
from json import MS_loads as json_loads
|
||||
|
||||
# so no data-flow
|
||||
SINK_F(json_loads(SOURCE))
|
||||
SINK_F(json_loads(SOURCE)[0])
|
||||
|
||||
# but has taint-flow
|
||||
tainted_resultlist = json_loads(TAINTED_STRING)
|
||||
ensure_tainted(
|
||||
tainted_resultlist, # $ tainted
|
||||
tainted_resultlist[0], # $ tainted
|
||||
)
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -4,12 +4,10 @@ import experimental.dataflow.TestUtil.FlowTest
|
||||
private import semmle.python.dataflow.new.internal.PrintNode
|
||||
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DP
|
||||
|
||||
class ImportTimeLocalFlowTest extends FlowTest {
|
||||
ImportTimeLocalFlowTest() { this = "ImportTimeLocalFlowTest" }
|
||||
module ImportTimeLocalFlowTest implements FlowTestSig {
|
||||
string flowTag() { result = "importTimeFlow" }
|
||||
|
||||
override string flowTag() { result = "importTimeFlow" }
|
||||
|
||||
override predicate relevantFlow(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
predicate relevantFlow(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
nodeFrom.getLocation().getFile().getBaseName() = "multiphase.py" and
|
||||
// results are displayed next to `nodeTo`, so we need a line to write on
|
||||
nodeTo.getLocation().getStartLine() > 0 and
|
||||
@@ -18,12 +16,10 @@ class ImportTimeLocalFlowTest extends FlowTest {
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeLocalFlowTest extends FlowTest {
|
||||
RuntimeLocalFlowTest() { this = "RuntimeLocalFlowTest" }
|
||||
module RuntimeLocalFlowTest implements FlowTestSig {
|
||||
string flowTag() { result = "runtimeFlow" }
|
||||
|
||||
override string flowTag() { result = "runtimeFlow" }
|
||||
|
||||
override predicate relevantFlow(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
predicate relevantFlow(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
nodeFrom.getLocation().getFile().getBaseName() = "multiphase.py" and
|
||||
// results are displayed next to `nodeTo`, so we need a line to write on
|
||||
nodeTo.getLocation().getStartLine() > 0 and
|
||||
@@ -34,3 +30,5 @@ class RuntimeLocalFlowTest extends FlowTest {
|
||||
DP::runtimeJumpStep(nodeFrom, nodeTo)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeFlowTest2<ImportTimeLocalFlowTest, RuntimeLocalFlowTest>
|
||||
|
||||
@@ -9,5 +9,5 @@ import python
|
||||
import experimental.dataflow.testConfig
|
||||
|
||||
from DataFlow::Node source, DataFlow::Node sink
|
||||
where exists(TestConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
where TestFlow::flow(source, sink)
|
||||
select source, sink
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.new.FlowSummary
|
||||
import DataFlow::PathGraph
|
||||
import TestFlow::PathGraph
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import semmle.python.dataflow.new.internal.FlowSummaryImpl
|
||||
import semmle.python.ApiGraphs
|
||||
@@ -16,6 +16,6 @@ query predicate invalidSpecComponent(SummarizedCallable sc, string s, string c)
|
||||
Private::External::invalidSpecComponent(s, c)
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, TestConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from TestFlow::PathNode source, TestFlow::PathNode sink
|
||||
where TestFlow::flowPath(source, sink)
|
||||
select sink, source, sink, "$@", source, source.toString()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import semmle.python.dataflow.new.BarrierGuards
|
||||
|
||||
class CustomSanitizerOverrides extends TestTaintTrackingConfiguration {
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof StringConstCompareBarrier }
|
||||
module CustomSanitizerOverridesConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource = TestTaintTrackingConfig::isSource/1;
|
||||
|
||||
predicate isSink = TestTaintTrackingConfig::isSink/1;
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof StringConstCompareBarrier }
|
||||
}
|
||||
|
||||
import MakeInlineTaintTest<CustomSanitizerOverridesConfig>
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
isSanitizer
|
||||
| TestTaintTrackingConfiguration | test.py:21:39:21:39 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test.py:34:39:34:39 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test.py:52:28:52:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test.py:66:10:66:29 | ControlFlowNode for emulated_escaping() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:33:28:33:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:40:28:40:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:48:28:48:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:53:28:53:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:92:28:92:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:103:28:103:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:111:28:111:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:130:28:130:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:137:28:137:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:148:28:148:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:151:28:151:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:158:28:158:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:167:24:167:24 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:176:24:176:24 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:185:24:185:24 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:193:24:193:24 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_reference.py:31:28:31:28 | ControlFlowNode for s |
|
||||
| test.py:21:39:21:39 | ControlFlowNode for s |
|
||||
| test.py:34:39:34:39 | ControlFlowNode for s |
|
||||
| test.py:52:28:52:28 | ControlFlowNode for s |
|
||||
| test.py:66:10:66:29 | ControlFlowNode for emulated_escaping() |
|
||||
| test_logical.py:33:28:33:28 | ControlFlowNode for s |
|
||||
| test_logical.py:40:28:40:28 | ControlFlowNode for s |
|
||||
| test_logical.py:48:28:48:28 | ControlFlowNode for s |
|
||||
| test_logical.py:53:28:53:28 | ControlFlowNode for s |
|
||||
| test_logical.py:92:28:92:28 | ControlFlowNode for s |
|
||||
| test_logical.py:103:28:103:28 | ControlFlowNode for s |
|
||||
| test_logical.py:111:28:111:28 | ControlFlowNode for s |
|
||||
| test_logical.py:130:28:130:28 | ControlFlowNode for s |
|
||||
| test_logical.py:137:28:137:28 | ControlFlowNode for s |
|
||||
| test_logical.py:148:28:148:28 | ControlFlowNode for s |
|
||||
| test_logical.py:151:28:151:28 | ControlFlowNode for s |
|
||||
| test_logical.py:158:28:158:28 | ControlFlowNode for s |
|
||||
| test_logical.py:167:24:167:24 | ControlFlowNode for s |
|
||||
| test_logical.py:176:24:176:24 | ControlFlowNode for s |
|
||||
| test_logical.py:185:24:185:24 | ControlFlowNode for s |
|
||||
| test_logical.py:193:24:193:24 | ControlFlowNode for s |
|
||||
| test_reference.py:31:28:31:28 | ControlFlowNode for s |
|
||||
|
||||
@@ -12,8 +12,12 @@ predicate isUnsafeCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean bra
|
||||
branch = false
|
||||
}
|
||||
|
||||
class CustomSanitizerOverrides extends TestTaintTrackingConfiguration {
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
module CustomSanitizerOverridesConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource = TestTaintTrackingConfig::isSource/1;
|
||||
|
||||
predicate isSink = TestTaintTrackingConfig::isSink/1;
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(Call call |
|
||||
call.getFunc().(Name).getId() = "emulated_authentication_check" and
|
||||
call.getArg(0) = node.asExpr()
|
||||
@@ -27,7 +31,9 @@ class CustomSanitizerOverrides extends TestTaintTrackingConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
query predicate isSanitizer(TestTaintTrackingConfiguration conf, DataFlow::Node node) {
|
||||
import MakeInlineTaintTest<CustomSanitizerOverridesConfig>
|
||||
|
||||
query predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(node.getLocation().getFile().getRelativePath()) and
|
||||
conf.isSanitizer(node)
|
||||
CustomSanitizerOverridesConfig::isBarrier(node)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
|
||||
@@ -23,10 +23,8 @@
|
||||
private import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
|
||||
class TestConfiguration extends DataFlow::Configuration {
|
||||
TestConfiguration() { this = "TestConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) {
|
||||
module TestConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE"
|
||||
or
|
||||
node.(DataFlow::CfgNode).getNode().getNode().(StrConst).getS() = "source"
|
||||
@@ -37,7 +35,7 @@ class TestConfiguration extends DataFlow::Configuration {
|
||||
// No support for complex numbers
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node node) {
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(DataFlow::CallCfgNode call |
|
||||
call.getFunction().asCfgNode().(NameNode).getId() in ["SINK", "SINK_F"] and
|
||||
(node = call.getArg(_) or node = call.getArgByName(_)) and
|
||||
@@ -45,5 +43,7 @@ class TestConfiguration extends DataFlow::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) { this.isSource(node) }
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||
}
|
||||
|
||||
module TestFlow = DataFlow::Global<TestConfig>;
|
||||
|
||||
@@ -24,10 +24,8 @@ private import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
|
||||
class TestConfiguration extends TaintTracking::Configuration {
|
||||
TestConfiguration() { this = "TestConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) {
|
||||
module TestConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE"
|
||||
or
|
||||
node.(DataFlow::CfgNode).getNode().getNode().(StrConst).getS() = "source"
|
||||
@@ -38,12 +36,14 @@ class TestConfiguration extends TaintTracking::Configuration {
|
||||
// No support for complex numbers
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node node) {
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(CallNode call |
|
||||
call.getFunction().(NameNode).getId() in ["SINK", "SINK_F"] and
|
||||
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizerIn(DataFlow::Node node) { this.isSource(node) }
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||
}
|
||||
|
||||
module TestFlow = TaintTracking::Global<TestConfig>;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -14,12 +14,10 @@ private DataFlow::TypeTrackingNode tracked(TypeTracker t) {
|
||||
exists(TypeTracker t2 | result = tracked(t2).track(t2, t))
|
||||
}
|
||||
|
||||
class TrackedTest extends InlineExpectationsTest {
|
||||
TrackedTest() { this = "TrackedTest" }
|
||||
module TrackedTest implements TestSig {
|
||||
string getARelevantTag() { result = "tracked" }
|
||||
|
||||
override string getARelevantTag() { result = "tracked" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node e, TypeTracker t |
|
||||
tracked(t).flowsTo(e) and
|
||||
// Module variables have no sensible location, and hence can't be annotated.
|
||||
@@ -54,12 +52,10 @@ private DataFlow::TypeTrackingNode string_type(TypeTracker t) {
|
||||
exists(TypeTracker t2 | result = string_type(t2).track(t2, t))
|
||||
}
|
||||
|
||||
class TrackedIntTest extends InlineExpectationsTest {
|
||||
TrackedIntTest() { this = "TrackedIntTest" }
|
||||
module TrackedIntTest implements TestSig {
|
||||
string getARelevantTag() { result = "int" }
|
||||
|
||||
override string getARelevantTag() { result = "int" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node e, TypeTracker t |
|
||||
int_type(t).flowsTo(e) and
|
||||
tag = "int" and
|
||||
@@ -70,12 +66,10 @@ class TrackedIntTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class TrackedStringTest extends InlineExpectationsTest {
|
||||
TrackedStringTest() { this = "TrackedStringTest" }
|
||||
module TrackedStringTest implements TestSig {
|
||||
string getARelevantTag() { result = "str" }
|
||||
|
||||
override string getARelevantTag() { result = "str" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node e, TypeTracker t |
|
||||
string_type(t).flowsTo(e) and
|
||||
tag = "str" and
|
||||
@@ -100,12 +94,10 @@ private DataFlow::TypeTrackingNode tracked_self(TypeTracker t) {
|
||||
exists(TypeTracker t2 | result = tracked_self(t2).track(t2, t))
|
||||
}
|
||||
|
||||
class TrackedSelfTest extends InlineExpectationsTest {
|
||||
TrackedSelfTest() { this = "TrackedSelfTest" }
|
||||
module TrackedSelfTest implements TestSig {
|
||||
string getARelevantTag() { result = "tracked_self" }
|
||||
|
||||
override string getARelevantTag() { result = "tracked_self" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node e, TypeTracker t |
|
||||
tracked_self(t).flowsTo(e) and
|
||||
// Module variables have no sensible location, and hence can't be annotated.
|
||||
@@ -161,12 +153,10 @@ private DataFlow::TypeTrackingNode foo_bar_baz(DataFlow::TypeTracker t) {
|
||||
/** Gets a reference to `foo.bar.baz` (fictive attribute on `foo.bar` module). */
|
||||
DataFlow::Node foo_bar_baz() { foo_bar_baz(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
class TrackedFooBarBaz extends InlineExpectationsTest {
|
||||
TrackedFooBarBaz() { this = "TrackedFooBarBaz" }
|
||||
module TrackedFooBarBaz implements TestSig {
|
||||
string getARelevantTag() { result = "tracked_foo_bar_baz" }
|
||||
|
||||
override string getARelevantTag() { result = "tracked_foo_bar_baz" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node e |
|
||||
e = foo_bar_baz() and
|
||||
// Module variables have no sensible location, and hence can't be annotated.
|
||||
@@ -178,3 +168,5 @@ class TrackedFooBarBaz extends InlineExpectationsTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests5<TrackedTest, TrackedIntTest, TrackedStringTest, TrackedSelfTest, TrackedFooBarBaz>>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -7,7 +7,7 @@ module CaptureTest implements TestSig {
|
||||
string getARelevantTag() { result = "captured" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node sink | exists(TestConfiguration cfg | cfg.hasFlowTo(sink)) |
|
||||
exists(DataFlow::Node sink | TestFlow::flowTo(sink) |
|
||||
location = sink.getLocation() and
|
||||
tag = "captured" and
|
||||
value = "" and
|
||||
|
||||
@@ -4,12 +4,10 @@ import semmle.python.Concepts
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
private import semmle.python.dataflow.new.internal.PrintNode
|
||||
|
||||
class SystemCommandExecutionTest extends InlineExpectationsTest {
|
||||
SystemCommandExecutionTest() { this = "SystemCommandExecutionTest" }
|
||||
module SystemCommandExecutionTest implements TestSig {
|
||||
string getARelevantTag() { result = "getCommand" }
|
||||
|
||||
override string getARelevantTag() { result = "getCommand" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(SystemCommandExecution sce, DataFlow::Node command |
|
||||
command = sce.getCommand() and
|
||||
@@ -21,14 +19,12 @@ class SystemCommandExecutionTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class DecodingTest extends InlineExpectationsTest {
|
||||
DecodingTest() { this = "DecodingTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
module DecodingTest implements TestSig {
|
||||
string getARelevantTag() {
|
||||
result in ["decodeInput", "decodeOutput", "decodeFormat", "decodeMayExecuteInput"]
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Decoding d |
|
||||
exists(DataFlow::Node data |
|
||||
@@ -61,12 +57,10 @@ class DecodingTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class EncodingTest extends InlineExpectationsTest {
|
||||
EncodingTest() { this = "EncodingTest" }
|
||||
module EncodingTest implements TestSig {
|
||||
string getARelevantTag() { result in ["encodeInput", "encodeOutput", "encodeFormat"] }
|
||||
|
||||
override string getARelevantTag() { result in ["encodeInput", "encodeOutput", "encodeFormat"] }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Encoding e |
|
||||
exists(DataFlow::Node data |
|
||||
@@ -93,12 +87,10 @@ class EncodingTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class LoggingTest extends InlineExpectationsTest {
|
||||
LoggingTest() { this = "LoggingTest" }
|
||||
module LoggingTest implements TestSig {
|
||||
string getARelevantTag() { result = "loggingInput" }
|
||||
|
||||
override string getARelevantTag() { result = "loggingInput" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Logging logging, DataFlow::Node data |
|
||||
location = data.getLocation() and
|
||||
@@ -110,12 +102,10 @@ class LoggingTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class CodeExecutionTest extends InlineExpectationsTest {
|
||||
CodeExecutionTest() { this = "CodeExecutionTest" }
|
||||
module CodeExecutionTest implements TestSig {
|
||||
string getARelevantTag() { result = "getCode" }
|
||||
|
||||
override string getARelevantTag() { result = "getCode" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(CodeExecution ce, DataFlow::Node code |
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
@@ -128,12 +118,10 @@ class CodeExecutionTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class SqlConstructionTest extends InlineExpectationsTest {
|
||||
SqlConstructionTest() { this = "SqlConstructionTest" }
|
||||
module SqlConstructionTest implements TestSig {
|
||||
string getARelevantTag() { result = "constructedSql" }
|
||||
|
||||
override string getARelevantTag() { result = "constructedSql" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(SqlConstruction e, DataFlow::Node sql |
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
@@ -146,12 +134,10 @@ class SqlConstructionTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class SqlExecutionTest extends InlineExpectationsTest {
|
||||
SqlExecutionTest() { this = "SqlExecutionTest" }
|
||||
module SqlExecutionTest implements TestSig {
|
||||
string getARelevantTag() { result = "getSql" }
|
||||
|
||||
override string getARelevantTag() { result = "getSql" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(SqlExecution e, DataFlow::Node sql |
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
@@ -164,12 +150,10 @@ class SqlExecutionTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class XPathConstructionTest extends InlineExpectationsTest {
|
||||
XPathConstructionTest() { this = "XPathConstructionTest" }
|
||||
module XPathConstructionTest implements TestSig {
|
||||
string getARelevantTag() { result = "constructedXPath" }
|
||||
|
||||
override string getARelevantTag() { result = "constructedXPath" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(XML::XPathConstruction e, DataFlow::Node xpath |
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
@@ -182,12 +166,10 @@ class XPathConstructionTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class XPathExecutionTest extends InlineExpectationsTest {
|
||||
XPathExecutionTest() { this = "XPathExecutionTest" }
|
||||
module XPathExecutionTest implements TestSig {
|
||||
string getARelevantTag() { result = "getXPath" }
|
||||
|
||||
override string getARelevantTag() { result = "getXPath" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(XML::XPathExecution e, DataFlow::Node xpath |
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
@@ -200,12 +182,10 @@ class XPathExecutionTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class EscapingTest extends InlineExpectationsTest {
|
||||
EscapingTest() { this = "EscapingTest" }
|
||||
module EscapingTest implements TestSig {
|
||||
string getARelevantTag() { result in ["escapeInput", "escapeOutput", "escapeKind"] }
|
||||
|
||||
override string getARelevantTag() { result in ["escapeInput", "escapeOutput", "escapeKind"] }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Escaping esc |
|
||||
exists(DataFlow::Node data |
|
||||
@@ -232,12 +212,10 @@ class EscapingTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class HttpServerRouteSetupTest extends InlineExpectationsTest {
|
||||
HttpServerRouteSetupTest() { this = "HttpServerRouteSetupTest" }
|
||||
module HttpServerRouteSetupTest implements TestSig {
|
||||
string getARelevantTag() { result = "routeSetup" }
|
||||
|
||||
override string getARelevantTag() { result = "routeSetup" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Http::Server::RouteSetup setup |
|
||||
location = setup.getLocation() and
|
||||
@@ -253,12 +231,10 @@ class HttpServerRouteSetupTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class HttpServerRequestHandlerTest extends InlineExpectationsTest {
|
||||
HttpServerRequestHandlerTest() { this = "HttpServerRequestHandlerTest" }
|
||||
module HttpServerRequestHandlerTest implements TestSig {
|
||||
string getARelevantTag() { result in ["requestHandler", "routedParameter"] }
|
||||
|
||||
override string getARelevantTag() { result in ["requestHandler", "routedParameter"] }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
(
|
||||
exists(Http::Server::RequestHandler handler |
|
||||
@@ -330,12 +306,10 @@ class HttpServerHttpResponseTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class HttpServerHttpRedirectResponseTest extends InlineExpectationsTest {
|
||||
HttpServerHttpRedirectResponseTest() { this = "HttpServerHttpRedirectResponseTest" }
|
||||
module HttpServerHttpRedirectResponseTest implements TestSig {
|
||||
string getARelevantTag() { result in ["HttpRedirectResponse", "redirectLocation"] }
|
||||
|
||||
override string getARelevantTag() { result in ["HttpRedirectResponse", "redirectLocation"] }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
(
|
||||
exists(Http::Server::HttpRedirectResponse redirect |
|
||||
@@ -355,14 +329,12 @@ class HttpServerHttpRedirectResponseTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class HttpServerCookieWriteTest extends InlineExpectationsTest {
|
||||
HttpServerCookieWriteTest() { this = "HttpServerCookieWriteTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
module HttpServerCookieWriteTest implements TestSig {
|
||||
string getARelevantTag() {
|
||||
result in ["CookieWrite", "CookieRawHeader", "CookieName", "CookieValue"]
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Http::Server::CookieWrite cookieWrite |
|
||||
location = cookieWrite.getLocation() and
|
||||
@@ -387,12 +359,10 @@ class HttpServerCookieWriteTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class FileSystemAccessTest extends InlineExpectationsTest {
|
||||
FileSystemAccessTest() { this = "FileSystemAccessTest" }
|
||||
module FileSystemAccessTest implements TestSig {
|
||||
string getARelevantTag() { result = "getAPathArgument" }
|
||||
|
||||
override string getARelevantTag() { result = "getAPathArgument" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(FileSystemAccess a, DataFlow::Node path |
|
||||
path = a.getAPathArgument() and
|
||||
@@ -404,12 +374,10 @@ class FileSystemAccessTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class FileSystemWriteAccessTest extends InlineExpectationsTest {
|
||||
FileSystemWriteAccessTest() { this = "FileSystemWriteAccessTest" }
|
||||
module FileSystemWriteAccessTest implements TestSig {
|
||||
string getARelevantTag() { result = "fileWriteData" }
|
||||
|
||||
override string getARelevantTag() { result = "fileWriteData" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(FileSystemWriteAccess write, DataFlow::Node data |
|
||||
data = write.getADataNode() and
|
||||
@@ -421,12 +389,10 @@ class FileSystemWriteAccessTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class PathNormalizationTest extends InlineExpectationsTest {
|
||||
PathNormalizationTest() { this = "PathNormalizationTest" }
|
||||
module PathNormalizationTest implements TestSig {
|
||||
string getARelevantTag() { result = "pathNormalization" }
|
||||
|
||||
override string getARelevantTag() { result = "pathNormalization" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Path::PathNormalization n |
|
||||
location = n.getLocation() and
|
||||
@@ -437,12 +403,10 @@ class PathNormalizationTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class SafeAccessCheckTest extends InlineExpectationsTest {
|
||||
SafeAccessCheckTest() { this = "SafeAccessCheckTest" }
|
||||
module SafeAccessCheckTest implements TestSig {
|
||||
string getARelevantTag() { result = "SafeAccessCheck" }
|
||||
|
||||
override string getARelevantTag() { result = "SafeAccessCheck" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Path::SafeAccessCheck c |
|
||||
location = c.getLocation() and
|
||||
@@ -453,12 +417,10 @@ class SafeAccessCheckTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class PublicKeyGenerationTest extends InlineExpectationsTest {
|
||||
PublicKeyGenerationTest() { this = "PublicKeyGenerationTest" }
|
||||
module PublicKeyGenerationTest implements TestSig {
|
||||
string getARelevantTag() { result in ["PublicKeyGeneration", "keySize"] }
|
||||
|
||||
override string getARelevantTag() { result in ["PublicKeyGeneration", "keySize"] }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Cryptography::PublicKey::KeyGeneration keyGen |
|
||||
location = keyGen.getLocation() and
|
||||
@@ -475,17 +437,15 @@ class PublicKeyGenerationTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class CryptographicOperationTest extends InlineExpectationsTest {
|
||||
CryptographicOperationTest() { this = "CryptographicOperationTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
module CryptographicOperationTest implements TestSig {
|
||||
string getARelevantTag() {
|
||||
result in [
|
||||
"CryptographicOperation", "CryptographicOperationInput", "CryptographicOperationAlgorithm",
|
||||
"CryptographicOperationBlockMode"
|
||||
]
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Cryptography::CryptographicOperation cryptoOperation |
|
||||
location = cryptoOperation.getLocation() and
|
||||
@@ -510,14 +470,12 @@ class CryptographicOperationTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class HttpClientRequestTest extends InlineExpectationsTest {
|
||||
HttpClientRequestTest() { this = "HttpClientRequestTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
module HttpClientRequestTest implements TestSig {
|
||||
string getARelevantTag() {
|
||||
result in ["clientRequestUrlPart", "clientRequestCertValidationDisabled"]
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Http::Client::Request req, DataFlow::Node url |
|
||||
url = req.getAUrlPart() and
|
||||
@@ -538,12 +496,10 @@ class HttpClientRequestTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class CsrfProtectionSettingTest extends InlineExpectationsTest {
|
||||
CsrfProtectionSettingTest() { this = "CsrfProtectionSettingTest" }
|
||||
module CsrfProtectionSettingTest implements TestSig {
|
||||
string getARelevantTag() { result = "CsrfProtectionSetting" }
|
||||
|
||||
override string getARelevantTag() { result = "CsrfProtectionSetting" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Http::Server::CsrfProtectionSetting setting |
|
||||
location = setting.getLocation() and
|
||||
@@ -554,12 +510,10 @@ class CsrfProtectionSettingTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class CsrfLocalProtectionSettingTest extends InlineExpectationsTest {
|
||||
CsrfLocalProtectionSettingTest() { this = "CsrfLocalProtectionSettingTest" }
|
||||
module CsrfLocalProtectionSettingTest implements TestSig {
|
||||
string getARelevantTag() { result = "CsrfLocalProtection" + ["Enabled", "Disabled"] }
|
||||
|
||||
override string getARelevantTag() { result = "CsrfLocalProtection" + ["Enabled", "Disabled"] }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Http::Server::CsrfLocalProtectionSetting p |
|
||||
location = p.getLocation() and
|
||||
@@ -572,12 +526,10 @@ class CsrfLocalProtectionSettingTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class XmlParsingTest extends InlineExpectationsTest {
|
||||
XmlParsingTest() { this = "XmlParsingTest" }
|
||||
module XmlParsingTest implements TestSig {
|
||||
string getARelevantTag() { result = "xmlVuln" }
|
||||
|
||||
override string getARelevantTag() { result = "xmlVuln" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(XML::XmlParsing parsing, XML::XmlParsingVulnerabilityKind kind |
|
||||
parsing.vulnerableTo(kind) and
|
||||
@@ -588,3 +540,14 @@ class XmlParsingTest extends InlineExpectationsTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests5<MergeTests5<SystemCommandExecutionTest, DecodingTest, EncodingTest, LoggingTest,
|
||||
CodeExecutionTest>,
|
||||
MergeTests5<SqlConstructionTest, SqlExecutionTest, XPathConstructionTest, XPathExecutionTest,
|
||||
EscapingTest>,
|
||||
MergeTests4<HttpServerRouteSetupTest, HttpServerRequestHandlerTest,
|
||||
HttpServerHttpRedirectResponseTest, HttpServerCookieWriteTest>,
|
||||
MergeTests5<FileSystemAccessTest, FileSystemWriteAccessTest, PathNormalizationTest,
|
||||
SafeAccessCheckTest, PublicKeyGenerationTest>,
|
||||
MergeTests5<CryptographicOperationTest, HttpClientRequestTest, CsrfProtectionSettingTest,
|
||||
CsrfLocalProtectionSettingTest, XmlParsingTest>>>
|
||||
|
||||
@@ -33,10 +33,8 @@ DataFlow::Node shouldNotBeTainted() {
|
||||
// this module allows the configuration to be imported in other `.ql` files without the
|
||||
// top level query predicates of this file coming into scope.
|
||||
module Conf {
|
||||
class TestTaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
TestTaintTrackingConfiguration() { this = "TestTaintTrackingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module TestTaintTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asCfgNode().(NameNode).getId() in [
|
||||
"TAINTED_STRING", "TAINTED_BYTES", "TAINTED_LIST", "TAINTED_DICT"
|
||||
]
|
||||
@@ -50,7 +48,7 @@ module Conf {
|
||||
source instanceof RemoteFlowSource
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = shouldBeTainted()
|
||||
or
|
||||
sink = shouldNotBeTainted()
|
||||
@@ -60,49 +58,53 @@ module Conf {
|
||||
|
||||
import Conf
|
||||
|
||||
class InlineTaintTest extends InlineExpectationsTest {
|
||||
InlineTaintTest() { this = "InlineTaintTest" }
|
||||
module MakeInlineTaintTest<DataFlow::ConfigSig Config> {
|
||||
private module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
override string getARelevantTag() { result = "tainted" }
|
||||
private module InlineTaintTest implements TestSig {
|
||||
string getARelevantTag() { result = "tainted" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(DataFlow::Node sink |
|
||||
Flow::flowTo(sink) and
|
||||
location = sink.getLocation() and
|
||||
element = prettyExpr(sink.asExpr()) and
|
||||
value = "" and
|
||||
tag = "tainted"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<InlineTaintTest>
|
||||
|
||||
query predicate argumentToEnsureNotTaintedNotMarkedAsSpurious(
|
||||
Location location, string error, string element
|
||||
) {
|
||||
error = "ERROR, you should add `SPURIOUS:` to this annotation" and
|
||||
location = shouldNotBeTainted().getLocation() and
|
||||
InlineTaintTest::hasActualResult(location, element, "tainted", _) and
|
||||
exists(GoodTestExpectation good, ActualTestResult actualResult |
|
||||
good.matchesActualResult(actualResult) and
|
||||
actualResult.getLocation() = location and
|
||||
actualResult.toString() = element
|
||||
)
|
||||
}
|
||||
|
||||
query predicate untaintedArgumentToEnsureTaintedNotMarkedAsMissing(
|
||||
Location location, string error, string element
|
||||
) {
|
||||
error = "ERROR, you should add `# $ MISSING: tainted` annotation" and
|
||||
exists(DataFlow::Node sink |
|
||||
any(TestTaintTrackingConfiguration config).hasFlow(_, sink) and
|
||||
location = sink.getLocation() and
|
||||
sink = shouldBeTainted() and
|
||||
element = prettyExpr(sink.asExpr()) and
|
||||
value = "" and
|
||||
tag = "tainted"
|
||||
not Flow::flowTo(sink) and
|
||||
location = sink.getLocation() and
|
||||
not exists(FalseNegativeTestExpectation missingResult |
|
||||
missingResult.getTag() = "tainted" and
|
||||
missingResult.getLocation().getFile() = location.getFile() and
|
||||
missingResult.getLocation().getStartLine() = location.getStartLine()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate argumentToEnsureNotTaintedNotMarkedAsSpurious(
|
||||
Location location, string error, string element
|
||||
) {
|
||||
error = "ERROR, you should add `SPURIOUS:` to this annotation" and
|
||||
location = shouldNotBeTainted().getLocation() and
|
||||
any(InlineTaintTest test).hasActualResult(location, element, "tainted", _) and
|
||||
exists(GoodExpectation good, ActualResult actualResult |
|
||||
good.matchesActualResult(actualResult) and
|
||||
actualResult.getLocation() = location and
|
||||
actualResult.toString() = element
|
||||
)
|
||||
}
|
||||
|
||||
query predicate untaintedArgumentToEnsureTaintedNotMarkedAsMissing(
|
||||
Location location, string error, string element
|
||||
) {
|
||||
error = "ERROR, you should add `# $ MISSING: tainted` annotation" and
|
||||
exists(DataFlow::Node sink |
|
||||
sink = shouldBeTainted() and
|
||||
element = prettyExpr(sink.asExpr()) and
|
||||
not any(TestTaintTrackingConfiguration config).hasFlow(_, sink) and
|
||||
location = sink.getLocation() and
|
||||
not exists(FalseNegativeExpectation missingResult |
|
||||
missingResult.getTag() = "tainted" and
|
||||
missingResult.getLocation().getFile() = location.getFile() and
|
||||
missingResult.getLocation().getStartLine() = location.getStartLine()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,16 +7,14 @@ private import semmle.python.Frameworks
|
||||
// this import needs to be public to get the query predicates propagated to the actual test files
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class MadSinkTest extends InlineExpectationsTest {
|
||||
MadSinkTest() { this = "MadSinkTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
module MadSinkTest implements TestSig {
|
||||
string getARelevantTag() {
|
||||
exists(string kind | exists(ModelOutput::getASinkNode(kind)) |
|
||||
result = "mad-sink[" + kind + "]"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(DataFlow::Node sink, string kind |
|
||||
sink = ModelOutput::getASinkNode(kind).asSink() and
|
||||
@@ -28,14 +26,12 @@ class MadSinkTest extends InlineExpectationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
class MadSourceTest extends InlineExpectationsTest {
|
||||
MadSourceTest() { this = "MadSourceTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
module MadSourceTest implements TestSig {
|
||||
string getARelevantTag() {
|
||||
exists(string kind | exists(ModelOutput::getASourceNode(kind)) | result = "mad-source__" + kind)
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(DataFlow::Node source, string kind |
|
||||
source = ModelOutput::getASourceNode(kind).asSource() and
|
||||
@@ -46,3 +42,5 @@ class MadSourceTest extends InlineExpectationsTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests<MadSinkTest, MadSourceTest>>
|
||||
|
||||
@@ -13,11 +13,9 @@ import semmle.python.dataflow.new.TaintTracking
|
||||
import experimental.meta.InlineTaintTest::Conf
|
||||
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
any(TestTaintTrackingConfiguration c).isSource(source)
|
||||
}
|
||||
predicate isSource(DataFlow::Node source) { TestTaintTrackingConfig::isSource(source) }
|
||||
|
||||
predicate isSink(DataFlow::Node source) { any(TestTaintTrackingConfiguration c).isSink(source) }
|
||||
predicate isSink(DataFlow::Node source) { TestTaintTrackingConfig::isSink(source) }
|
||||
}
|
||||
|
||||
module Flows = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -12,9 +12,9 @@ import semmle.python.dataflow.new.DataFlow
|
||||
import experimental.dataflow.testConfig
|
||||
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { any(TestConfiguration c).isSource(source) }
|
||||
predicate isSource(DataFlow::Node source) { TestConfig::isSource(source) }
|
||||
|
||||
predicate isSink(DataFlow::Node source) { any(TestConfiguration c).isSink(source) }
|
||||
predicate isSink(DataFlow::Node source) { TestConfig::isSink(source) }
|
||||
}
|
||||
|
||||
module Flows = DataFlow::Global<Config>;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
| taint_test.py:48:9:48:29 | taint_test.py:48 | ERROR, you should add `SPURIOUS:` to this annotation | should_not_be_tainted |
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
| taint_test.py:32:9:32:25 | taint_test.py:32 | ERROR, you should add `# $ MISSING: tainted` annotation | should_be_tainted |
|
||||
| taint_test.py:37:24:37:40 | taint_test.py:37 | ERROR, you should add `# $ MISSING: tainted` annotation | should_be_tainted |
|
||||
failures
|
||||
testFailures
|
||||
| taint_test.py:41:20:41:21 | ts | Fixed missing result:tainted= |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user