mirror of
https://github.com/github/codeql.git
synced 2026-02-20 00:43:44 +01:00
We noticed that when - a function has more than one summary (with different charpred) - one summary is subsumed by a subpath (or something happens around the function being extracted) - the function is called multiple times(we needed at least three) one of the summaries would no longer lead to flow.
244 lines
7.6 KiB
Plaintext
244 lines
7.6 KiB
Plaintext
private import python
|
|
private import semmle.python.dataflow.new.FlowSummary
|
|
private import semmle.python.ApiGraphs
|
|
|
|
/**
|
|
* This module ensures that the `callStep` predicate in
|
|
* our type tracker implelemtation does not refer to the
|
|
* `getACall` predicate on `SummarizedCallable`.
|
|
*/
|
|
module RecursionGuard {
|
|
private import semmle.python.dataflow.new.internal.TypeTrackingImpl::TypeTrackingInput as TT
|
|
|
|
private class RecursionGuard extends SummarizedCallable {
|
|
RecursionGuard() { this = "RecursionGuard" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result.getFunction().asCfgNode().(NameNode).getId() = this and
|
|
(TT::callStep(_, _) implies any())
|
|
}
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
none()
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
|
|
}
|
|
}
|
|
|
|
private class SummarizedCallableIdentity extends SummarizedCallable {
|
|
SummarizedCallableIdentity() { this = "identity" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result.getFunction().asCfgNode().(NameNode).getId() = this
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
|
|
|
|
override predicate propagatesFlow(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 DataFlow::CallCfgNode getACall() {
|
|
result.getFunction().asCfgNode().(NameNode).getId() = this
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
input = "Argument[1]" and
|
|
output = "Argument[0].Parameter[0]" and
|
|
preservesValue = true
|
|
or
|
|
input = "Argument[0].ReturnValue" and
|
|
output = "ReturnValue" and
|
|
preservesValue = true
|
|
}
|
|
}
|
|
|
|
private class SummarizedCallableReversed extends SummarizedCallable {
|
|
SummarizedCallableReversed() { this = "list_reversed" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result.getFunction().asCfgNode().(NameNode).getId() = this
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
input = "Argument[0].ListElement" and
|
|
output = "ReturnValue.ListElement" and
|
|
preservesValue = true
|
|
}
|
|
}
|
|
|
|
private class SummarizedCallableMap extends SummarizedCallable {
|
|
SummarizedCallableMap() { this = "list_map" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result.getFunction().asCfgNode().(NameNode).getId() = this
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
input = "Argument[1].ListElement" and
|
|
output = "Argument[0].Parameter[0]" and
|
|
preservesValue = true
|
|
or
|
|
input = "Argument[0].ReturnValue" and
|
|
output = "ReturnValue.ListElement" and
|
|
preservesValue = true
|
|
}
|
|
}
|
|
|
|
private class SummarizedCallableAppend extends SummarizedCallable {
|
|
SummarizedCallableAppend() { this = "append_to_list" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result.getFunction().asCfgNode().(NameNode).getId() = this
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
input = "Argument[0]" and
|
|
output = "ReturnValue" and
|
|
preservesValue = false
|
|
or
|
|
input = "Argument[1]" and
|
|
output = "ReturnValue.ListElement" and
|
|
preservesValue = true
|
|
}
|
|
}
|
|
|
|
private class SummarizedCallableJsonLoads extends SummarizedCallable {
|
|
SummarizedCallableJsonLoads() { this = "json.loads" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result = API::moduleImport("json").getMember("loads").getACall()
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() {
|
|
result = API::moduleImport("json").getMember("loads").getAValueReachableFromSource()
|
|
}
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
input = "Argument[0]" and
|
|
output = "ReturnValue.ListElement" and
|
|
preservesValue = true
|
|
}
|
|
}
|
|
|
|
// Repeated summaries
|
|
private class SummarizedCallableWithSubpath extends SummarizedCallable {
|
|
SummarizedCallableWithSubpath() { this = "extracted_package.functions.with_subpath" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result =
|
|
API::moduleImport("extracted_package")
|
|
.getMember("functions")
|
|
.getMember("with_subpath")
|
|
.getACall()
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() {
|
|
result =
|
|
API::moduleImport("extracted_package")
|
|
.getMember("functions")
|
|
.getMember("with_subpath")
|
|
.getAValueReachableFromSource()
|
|
}
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
input = "Argument[0]" and
|
|
output = "ReturnValue" and
|
|
preservesValue = false
|
|
}
|
|
}
|
|
|
|
private class SummarizedCallableWithSubpathAgain extends SummarizedCallable {
|
|
SummarizedCallableWithSubpathAgain() { this = "extracted_package.functions.with_subpathII" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result =
|
|
API::moduleImport("extracted_package")
|
|
.getMember("functions")
|
|
.getMember("with_subpath")
|
|
.getACall()
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() {
|
|
result =
|
|
API::moduleImport("extracted_package")
|
|
.getMember("functions")
|
|
.getMember("with_subpath")
|
|
.getAValueReachableFromSource()
|
|
}
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
input = "Argument[0]" and
|
|
output = "ReturnValue.Attribute[pattern]" and
|
|
preservesValue = true
|
|
}
|
|
}
|
|
|
|
private class SummarizedCallableWithoutSubpath extends SummarizedCallable {
|
|
SummarizedCallableWithoutSubpath() { this = "extracted_package.functions.without_subpath" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result =
|
|
API::moduleImport("extracted_package")
|
|
.getMember("functions")
|
|
.getMember("without_subpath")
|
|
.getACall()
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() {
|
|
result =
|
|
API::moduleImport("extracted_package")
|
|
.getMember("functions")
|
|
.getMember("without_subpath")
|
|
.getAValueReachableFromSource()
|
|
}
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
input = "Argument[0]" and
|
|
output = "ReturnValue" and
|
|
preservesValue = false
|
|
}
|
|
}
|
|
|
|
private class SummarizedCallableWithoutSubpathAgain extends SummarizedCallable {
|
|
SummarizedCallableWithoutSubpathAgain() { this = "extracted_package.functions.without_subpathII" }
|
|
|
|
override DataFlow::CallCfgNode getACall() {
|
|
result =
|
|
API::moduleImport("extracted_package")
|
|
.getMember("functions")
|
|
.getMember("without_subpath")
|
|
.getACall()
|
|
}
|
|
|
|
override DataFlow::ArgumentNode getACallback() {
|
|
result =
|
|
API::moduleImport("extracted_package")
|
|
.getMember("functions")
|
|
.getMember("without_subpath")
|
|
.getAValueReachableFromSource()
|
|
}
|
|
|
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
|
input = "Argument[0]" and
|
|
output = "ReturnValue.Attribute[pattern]" and
|
|
preservesValue = true
|
|
}
|
|
}
|