mirror of
https://github.com/github/codeql.git
synced 2026-05-04 05:05:12 +02:00
python: some summary flows
This commit is contained in:
committed by
GitHub
parent
8c263b349f
commit
4024ce4777
@@ -0,0 +1,73 @@
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.FlowSummary
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
private class SummarizedCallableIdentity extends SummarizedCallable {
|
||||
SummarizedCallableIdentity() { this = "identity" }
|
||||
|
||||
override Call getACall() { result.getFunc().(Name).getId() = this }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[0]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
// For lambda flow to work, implement lambdaCall and lambdaCreation
|
||||
private class SummarizedCallableApplyLambda extends SummarizedCallable {
|
||||
SummarizedCallableApplyLambda() { this = "apply_lambda" }
|
||||
|
||||
override Call getACall() { result.getFunc().(Name).getId() = this }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[1]" and
|
||||
output = "Parameter[0] of Argument[0]" and
|
||||
preservesValue = true
|
||||
or
|
||||
input = "ReturnValue of Argument[0]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableReversed extends SummarizedCallable {
|
||||
SummarizedCallableReversed() { this = "reversed" }
|
||||
|
||||
override Call getACall() { result.getFunc().(Name).getId() = this }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "ListElement of Argument[0]" and
|
||||
output = "ListElement of ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableMap extends SummarizedCallable {
|
||||
SummarizedCallableMap() { this = "map" }
|
||||
|
||||
override Call getACall() { result.getFunc().(Name).getId() = this }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
input = "ListElement of Argument[1]" and
|
||||
output = "Parameter[0] of Argument[0]" and
|
||||
preservesValue = true
|
||||
or
|
||||
input = "ReturnValue of Argument[0]" and
|
||||
output = "ListElement of ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
// Typetracking needs to use a local flow step not including summaries
|
||||
// Typetracking needs to use a call graph not including summaries
|
||||
// private class SummarizedCallableJsonLoads extends SummarizedCallable {
|
||||
// SummarizedCallableJsonLoads() { this = "json.loads" }
|
||||
// override Call getACall() {
|
||||
// result = API::moduleImport("json").getMember("loads").getACall().asExpr()
|
||||
// }
|
||||
// override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
// input = "Argument[0]" and
|
||||
// output = "ListElement of ReturnValue" and
|
||||
// preservesValue = true
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,19 @@
|
||||
edges
|
||||
| summaries.py:2:12:2:28 | ControlFlowNode for identity() | summaries.py:3:7:3:13 | ControlFlowNode for tainted |
|
||||
| summaries.py:2:12:2:28 | ControlFlowNode for identity() | summaries.py:13:26:13:34 | ControlFlowNode for List |
|
||||
| summaries.py:2:12:2:28 | ControlFlowNode for identity() | summaries.py:34:7:34:27 | ControlFlowNode for Subscript |
|
||||
| summaries.py:2:21:2:27 | ControlFlowNode for Str | summaries.py:2:12:2:28 | ControlFlowNode for identity() |
|
||||
| summaries.py:13:26:13:34 | ControlFlowNode for List | summaries.py:14:7:14:21 | ControlFlowNode for Subscript |
|
||||
nodes
|
||||
| summaries.py:2:12:2:28 | ControlFlowNode for identity() | semmle.label | ControlFlowNode for identity() |
|
||||
| summaries.py:2:21:2:27 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str |
|
||||
| summaries.py:3:7:3:13 | ControlFlowNode for tainted | semmle.label | ControlFlowNode for tainted |
|
||||
| summaries.py:13:26:13:34 | ControlFlowNode for List | semmle.label | ControlFlowNode for List |
|
||||
| summaries.py:14:7:14:21 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| summaries.py:34:7:34:27 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
subpaths
|
||||
invalidSpecComponent
|
||||
#select
|
||||
| summaries.py:3:7:3:13 | ControlFlowNode for tainted | summaries.py:2:21:2:27 | ControlFlowNode for Str | summaries.py:3:7:3:13 | ControlFlowNode for tainted | $@ | summaries.py:2:21:2:27 | ControlFlowNode for Str | ControlFlowNode for Str |
|
||||
| summaries.py:14:7:14:21 | ControlFlowNode for Subscript | summaries.py:2:21:2:27 | ControlFlowNode for Str | summaries.py:14:7:14:21 | ControlFlowNode for Subscript | $@ | summaries.py:2:21:2:27 | ControlFlowNode for Str | ControlFlowNode for Str |
|
||||
| summaries.py:34:7:34:27 | ControlFlowNode for Subscript | summaries.py:2:21:2:27 | ControlFlowNode for Str | summaries.py:34:7:34:27 | ControlFlowNode for Subscript | $@ | summaries.py:2:21:2:27 | ControlFlowNode for Str | ControlFlowNode for Str |
|
||||
34
python/ql/test/experimental/dataflow/summaries/summaries.py
Normal file
34
python/ql/test/experimental/dataflow/summaries/summaries.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# Simple summary
|
||||
tainted = identity("taint")
|
||||
sink(tainted)
|
||||
|
||||
# Lambda summary
|
||||
tainted_lambda = apply_lambda(lambda x: x + 1, tainted)
|
||||
sink(tainted_lambda)
|
||||
|
||||
untainted_lambda = apply_lambda(lambda x: 1, tainted)
|
||||
sink(tainted_lambda) # should not see flow
|
||||
|
||||
# Collection summaries
|
||||
tainted_list = reversed([tainted])
|
||||
sink(tainted_list[0])
|
||||
|
||||
# Complex summaries
|
||||
def add_colon(x):
|
||||
return x + ":"
|
||||
|
||||
tainted_mapped = map(add_colon, [tainted])
|
||||
sink(tainted_mapped[0])
|
||||
|
||||
def explicit_identity(x):
|
||||
return x
|
||||
|
||||
tainted_mapped_explicit = map(explicit_identity, [tainted])
|
||||
sink(tainted_mapped_explicit[0])
|
||||
|
||||
tainted_mapped_summary = map(identity, [tainted])
|
||||
sink(tainted_mapped_summary[0])
|
||||
|
||||
from json import loads as json_loads
|
||||
tainted_resultlist = json_loads(tainted)
|
||||
sink(tainted_resultlist[0])
|
||||
33
python/ql/test/experimental/dataflow/summaries/summaries.ql
Normal file
33
python/ql/test/experimental/dataflow/summaries/summaries.ql
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.new.FlowSummary
|
||||
import DataFlow::PathGraph
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import semmle.python.dataflow.new.internal.FlowSummaryImpl
|
||||
import semmle.python.ApiGraphs
|
||||
private import TestSummaries
|
||||
|
||||
query predicate invalidSpecComponent(SummarizedCallable sc, string s, string c) {
|
||||
(sc.propagatesFlowExt(s, _, _) or sc.propagatesFlowExt(_, s, _)) and
|
||||
Private::External::invalidSpecComponent(s, c)
|
||||
}
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "FlowSummaries" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src.asExpr().(StrConst).getS() = "taint" }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(Call mc |
|
||||
mc.getFunc().(Name).getId() = "sink" and
|
||||
mc.getAnArg() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink, source, sink, "$@", source, source.toString()
|
||||
Reference in New Issue
Block a user