upgrade query to detect redash CVE too

This commit is contained in:
amammad
2023-06-30 22:14:50 +10:00
parent 7a17b99c17
commit 816799c4ba
436 changed files with 13346 additions and 1089 deletions

View File

@@ -1,3 +1,7 @@
## 0.9.3
No user-facing changes.
## 0.9.2
### Minor Analysis Improvements

View File

@@ -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"

View File

@@ -0,0 +1,3 @@
## 0.9.3
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.9.2
lastReleaseVersion: 0.9.3

View File

@@ -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

View File

@@ -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
)
}
}

View File

@@ -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.

View File

@@ -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.

View 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.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.7.2
lastReleaseVersion: 0.7.3

View File

@@ -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>

View File

@@ -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()
}
}

View File

@@ -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()
}
}

View File

@@ -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']

View File

@@ -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,

View File

@@ -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('/')

View File

@@ -0,0 +1,3 @@
import os
SECRET_KEY = "REDASH_COOKIE_SECRET"

View File

@@ -1,5 +1,5 @@
name: codeql/python-queries
version: 0.7.3-dev
version: 0.7.4-dev
groups:
- python
- queries

View File

@@ -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

View File

@@ -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>>>
}

View File

@@ -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>

View File

@@ -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>;

View File

@@ -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()

View File

@@ -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()

View File

@@ -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>
}

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -1,2 +1,3 @@
missingAnnotationOnSink
failures
testFailures

View File

@@ -1,2 +1,3 @@
missingAnnotationOnSink
failures
testFailures

View File

@@ -1,2 +1,3 @@
missingAnnotationOnSink
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -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>

View File

@@ -1,2 +1,3 @@
missingAnnotationOnSink
failures
testFailures

View File

@@ -0,0 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
testFailures

View File

@@ -0,0 +1,4 @@
import python
private import TestSummaries
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -0,0 +1,3 @@
missingAnnotationOnSink
failures
testFailures

View File

@@ -0,0 +1,3 @@
import python
private import TestSummaries
import experimental.dataflow.TestUtil.NormalDataflowTest

View File

@@ -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"
]
}
}

View File

@@ -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
)

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -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>

View File

@@ -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

View File

@@ -1,2 +1,3 @@
missingAnnotationOnSink
failures
testFailures

View File

@@ -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()

View File

@@ -1,3 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
failures
testFailures

View File

@@ -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>

View File

@@ -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 |

View File

@@ -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)
}

View File

@@ -1,3 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
failures
testFailures

View File

@@ -1 +1,2 @@
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -1,3 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
failures
testFailures

View File

@@ -1 +1,2 @@
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -1,3 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
failures
testFailures

View File

@@ -1 +1,2 @@
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -1,2 +1,3 @@
missingAnnotationOnSink
failures
testFailures

View File

@@ -1,3 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
failures
testFailures

View File

@@ -1 +1,2 @@
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -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>>

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -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

View File

@@ -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>>>

View File

@@ -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()
)
)
}

View File

@@ -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>>

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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= |

View File

@@ -1 +1,2 @@
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -1,2 +1,3 @@
missingAnnotationOnSink
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -1,3 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
failures
testFailures

View File

@@ -1 +1,2 @@
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -1,2 +1,3 @@
missingAnnotationOnSink
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -1,3 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
failures
testFailures

View File

@@ -1 +1,2 @@
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -1,3 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
failures
testFailures

View File

@@ -1 +1,2 @@
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -1,3 +1,4 @@
failures
argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
failures
testFailures

View File

@@ -1 +1,2 @@
import experimental.meta.InlineTaintTest
import MakeInlineTaintTest<TestTaintTrackingConfig>

View File

@@ -0,0 +1,2 @@
failures
testFailures

Some files were not shown because too many files have changed in this diff Show More