python: variaous fixes

- sync summary files
- format files
- fix compilation
This commit is contained in:
yoff
2022-04-29 10:20:33 +00:00
committed by GitHub
parent f14ee0e794
commit da3634188d
7 changed files with 61 additions and 40 deletions

View File

@@ -94,10 +94,10 @@ abstract class SummarizedCallable extends LibraryCallable {
/** /**
* Holds if values stored inside `content` are cleared on objects passed as * Holds if values stored inside `content` are cleared on objects passed as
* the `i`th argument to this callable. * arguments at position `pos` to this callable.
*/ */
pragma[nomagic] pragma[nomagic]
predicate clearsContent(int i, DataFlow::Content content) { none() } predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) { none() }
} }
private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable { private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable {
@@ -111,7 +111,7 @@ private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable
sc.propagatesFlow(input, output, preservesValue) sc.propagatesFlow(input, output, preservesValue)
} }
final override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) { final override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) {
sc.clearsContent(pos, content) sc.clearsContent(pos, content)
} }
} }

View File

@@ -42,9 +42,7 @@ module AccessPath {
* Parses a lower-bounded interval `n..` and gets the lower bound. * Parses a lower-bounded interval `n..` and gets the lower bound.
*/ */
bindingset[arg] bindingset[arg]
private int parseLowerBound(string arg) { int parseLowerBound(string arg) { result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt() }
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
}
/** /**
* Parses an integer constant or interval (bounded or unbounded) that explicitly * Parses an integer constant or interval (bounded or unbounded) that explicitly
@@ -151,7 +149,7 @@ class AccessPath extends string instanceof AccessPath::Range {
* An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths. * An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths.
*/ */
class AccessPathToken extends string { class AccessPathToken extends string {
AccessPathToken() { this = getRawToken(any(AccessPath path), _) } AccessPathToken() { this = getRawToken(_, _) }
private string getPart(int part) { private string getPart(int part) {
result = this.regexpCapture("([^\\[]+)(?:\\[([^\\]]*)\\])?", part) result = this.regexpCapture("([^\\[]+)(?:\\[([^\\]]*)\\])?", part)

View File

@@ -24,7 +24,7 @@ module Public {
class SummaryComponent extends TSummaryComponent { class SummaryComponent extends TSummaryComponent {
/** Gets a textual representation of this summary component. */ /** Gets a textual representation of this summary component. */
string toString() { string toString() {
exists(Content c | this = TContentSummaryComponent(c) and result = c.toString()) exists(ContentSet c | this = TContentSummaryComponent(c) and result = c.toString())
or or
exists(ArgumentPosition pos | exists(ArgumentPosition pos |
this = TParameterSummaryComponent(pos) and result = "parameter " + pos this = TParameterSummaryComponent(pos) and result = "parameter " + pos
@@ -41,7 +41,7 @@ module Public {
/** Provides predicates for constructing summary components. */ /** Provides predicates for constructing summary components. */
module SummaryComponent { module SummaryComponent {
/** Gets a summary component for content `c`. */ /** Gets a summary component for content `c`. */
SummaryComponent content(Content c) { result = TContentSummaryComponent(c) } SummaryComponent content(ContentSet c) { result = TContentSummaryComponent(c) }
/** Gets a summary component for a parameter at position `pos`. */ /** Gets a summary component for a parameter at position `pos`. */
SummaryComponent parameter(ArgumentPosition pos) { result = TParameterSummaryComponent(pos) } SummaryComponent parameter(ArgumentPosition pos) { result = TParameterSummaryComponent(pos) }
@@ -218,7 +218,7 @@ module Public {
* arguments at position `pos` to this callable. * arguments at position `pos` to this callable.
*/ */
pragma[nomagic] pragma[nomagic]
predicate clearsContent(ParameterPosition pos, Content content) { none() } predicate clearsContent(ParameterPosition pos, ContentSet content) { none() }
} }
} }
@@ -231,7 +231,7 @@ module Private {
import AccessPathSyntax import AccessPathSyntax
newtype TSummaryComponent = newtype TSummaryComponent =
TContentSummaryComponent(Content c) or TContentSummaryComponent(ContentSet c) or
TParameterSummaryComponent(ArgumentPosition pos) or TParameterSummaryComponent(ArgumentPosition pos) or
TArgumentSummaryComponent(ParameterPosition pos) or TArgumentSummaryComponent(ParameterPosition pos) or
TReturnSummaryComponent(ReturnKind rk) TReturnSummaryComponent(ReturnKind rk)
@@ -540,7 +540,7 @@ module Private {
exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | head = s.head() | exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | head = s.head() |
n = summaryNodeInputState(c, s) and n = summaryNodeInputState(c, s) and
( (
exists(Content cont | exists(ContentSet cont |
head = TContentSummaryComponent(cont) and result = getContentType(cont) head = TContentSummaryComponent(cont) and result = getContentType(cont)
) )
or or
@@ -554,7 +554,7 @@ module Private {
or or
n = summaryNodeOutputState(c, s) and n = summaryNodeOutputState(c, s) and
( (
exists(Content cont | exists(ContentSet cont |
head = TContentSummaryComponent(cont) and result = getContentType(cont) head = TContentSummaryComponent(cont) and result = getContentType(cont)
) )
or or
@@ -669,7 +669,7 @@ module Private {
* Holds if there is a read step of content `c` from `pred` to `succ`, which * Holds if there is a read step of content `c` from `pred` to `succ`, which
* is synthesized from a flow summary. * is synthesized from a flow summary.
*/ */
predicate summaryReadStep(Node pred, Content c, Node succ) { predicate summaryReadStep(Node pred, ContentSet c, Node succ) {
exists(SummarizedCallable sc, SummaryComponentStack s | exists(SummarizedCallable sc, SummaryComponentStack s |
pred = summaryNodeInputState(sc, s.drop(1)) and pred = summaryNodeInputState(sc, s.drop(1)) and
succ = summaryNodeInputState(sc, s) and succ = summaryNodeInputState(sc, s) and
@@ -681,7 +681,7 @@ module Private {
* Holds if there is a store step of content `c` from `pred` to `succ`, which * Holds if there is a store step of content `c` from `pred` to `succ`, which
* is synthesized from a flow summary. * is synthesized from a flow summary.
*/ */
predicate summaryStoreStep(Node pred, Content c, Node succ) { predicate summaryStoreStep(Node pred, ContentSet c, Node succ) {
exists(SummarizedCallable sc, SummaryComponentStack s | exists(SummarizedCallable sc, SummaryComponentStack s |
pred = summaryNodeOutputState(sc, s) and pred = summaryNodeOutputState(sc, s) and
succ = summaryNodeOutputState(sc, s.drop(1)) and succ = summaryNodeOutputState(sc, s.drop(1)) and
@@ -708,7 +708,7 @@ module Private {
* `a` on line 2 to the post-update node for `a` on that line (via an intermediate * `a` on line 2 to the post-update node for `a` on that line (via an intermediate
* node where field `b` is cleared). * node where field `b` is cleared).
*/ */
predicate summaryClearsContent(Node n, Content c) { predicate summaryClearsContent(Node n, ContentSet c) {
exists(SummarizedCallable sc, ParameterPosition pos | exists(SummarizedCallable sc, ParameterPosition pos |
n = summaryNode(sc, TSummaryNodeClearsContentState(pos, true)) and n = summaryNode(sc, TSummaryNodeClearsContentState(pos, true)) and
sc.clearsContent(pos, c) sc.clearsContent(pos, c)
@@ -730,7 +730,8 @@ module Private {
* In such cases, it is important to prevent use-use flow out of * In such cases, it is important to prevent use-use flow out of
* `arg` (see comment for `summaryClearsContent`). * `arg` (see comment for `summaryClearsContent`).
*/ */
predicate summaryClearsContentArg(ArgNode arg, Content c) { pragma[nomagic]
predicate summaryClearsContentArg(ArgNode arg, ContentSet c) {
exists(DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos | exists(DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos |
argumentPositionMatch(call, arg, ppos) and argumentPositionMatch(call, arg, ppos) and
viableParam(call, sc, ppos, _) and viableParam(call, sc, ppos, _) and
@@ -775,7 +776,7 @@ module Private {
* NOTE: This step should not be used in global data-flow/taint-tracking, but may * NOTE: This step should not be used in global data-flow/taint-tracking, but may
* be useful to include in the exposed local data-flow/taint-tracking relations. * be useful to include in the exposed local data-flow/taint-tracking relations.
*/ */
predicate summaryGetterStep(ArgNode arg, Content c, Node out) { predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out) {
exists(ReturnKindExt rk, Node mid, ReturnNodeExt ret | exists(ReturnKindExt rk, Node mid, ReturnNodeExt ret |
summaryReadStep(summaryArgParam(arg, rk, out), c, mid) and summaryReadStep(summaryArgParam(arg, rk, out), c, mid) and
summaryLocalStep(mid, ret, _) and summaryLocalStep(mid, ret, _) and
@@ -790,7 +791,7 @@ module Private {
* NOTE: This step should not be used in global data-flow/taint-tracking, but may * NOTE: This step should not be used in global data-flow/taint-tracking, but may
* be useful to include in the exposed local data-flow/taint-tracking relations. * be useful to include in the exposed local data-flow/taint-tracking relations.
*/ */
predicate summarySetterStep(ArgNode arg, Content c, Node out) { predicate summarySetterStep(ArgNode arg, ContentSet c, Node out) {
exists(ReturnKindExt rk, Node mid, ReturnNodeExt ret | exists(ReturnKindExt rk, Node mid, ReturnNodeExt ret |
summaryLocalStep(summaryArgParam(arg, rk, out), mid, _) and summaryLocalStep(summaryArgParam(arg, rk, out), mid, _) and
summaryStoreStep(mid, c, ret) and summaryStoreStep(mid, c, ret) and
@@ -806,10 +807,10 @@ module Private {
module External { module External {
/** Holds if `spec` is a relevant external specification. */ /** Holds if `spec` is a relevant external specification. */
private predicate relevantSpec(string spec) { private predicate relevantSpec(string spec) {
summaryElement(_, spec, _, _) or summaryElement(_, spec, _, _, _) or
summaryElement(_, _, spec, _) or summaryElement(_, _, spec, _, _) or
sourceElement(_, spec, _) or sourceElement(_, spec, _, _) or
sinkElement(_, spec, _) sinkElement(_, spec, _, _)
} }
private class AccessPathRange extends AccessPath::Range { private class AccessPathRange extends AccessPath::Range {
@@ -875,13 +876,20 @@ module Private {
} }
private class SummarizedCallableExternal extends SummarizedCallable { private class SummarizedCallableExternal extends SummarizedCallable {
SummarizedCallableExternal() { summaryElement(this, _, _, _) } SummarizedCallableExternal() { summaryElement(this, _, _, _, _) }
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
summaryElement(this, inSpec, outSpec, kind, false)
or
summaryElement(this, inSpec, outSpec, kind, true) and
not summaryElement(this, _, _, _, false)
}
override predicate propagatesFlow( override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) { ) {
exists(AccessPath inSpec, AccessPath outSpec, string kind | exists(AccessPath inSpec, AccessPath outSpec, string kind |
summaryElement(this, inSpec, outSpec, kind) and this.relevantSummaryElement(inSpec, outSpec, kind) and
interpretSpec(inSpec, input) and interpretSpec(inSpec, input) and
interpretSpec(outSpec, output) interpretSpec(outSpec, output)
| |
@@ -910,7 +918,7 @@ module Private {
private predicate sourceElementRef(InterpretNode ref, AccessPath output, string kind) { private predicate sourceElementRef(InterpretNode ref, AccessPath output, string kind) {
exists(SourceOrSinkElement e | exists(SourceOrSinkElement e |
sourceElement(e, output, kind) and sourceElement(e, output, kind, _) and
if outputNeedsReference(output.getToken(0)) if outputNeedsReference(output.getToken(0))
then e = ref.getCallTarget() then e = ref.getCallTarget()
else e = ref.asElement() else e = ref.asElement()
@@ -919,7 +927,7 @@ module Private {
private predicate sinkElementRef(InterpretNode ref, AccessPath input, string kind) { private predicate sinkElementRef(InterpretNode ref, AccessPath input, string kind) {
exists(SourceOrSinkElement e | exists(SourceOrSinkElement e |
sinkElement(e, input, kind) and sinkElement(e, input, kind, _) and
if inputNeedsReference(input.getToken(0)) if inputNeedsReference(input.getToken(0))
then e = ref.getCallTarget() then e = ref.getCallTarget()
else e = ref.asElement() else e = ref.asElement()
@@ -1056,8 +1064,8 @@ module Private {
| |
c.relevantSummary(input, output, preservesValue) and c.relevantSummary(input, output, preservesValue) and
csv = csv =
c.getCallableCsv() + ";" + getComponentStackCsv(input) + ";" + c.getCallableCsv() + getComponentStackCsv(input) + ";" + getComponentStackCsv(output) +
getComponentStackCsv(output) + ";" + renderKind(preservesValue) ";" + renderKind(preservesValue)
) )
} }
} }
@@ -1123,7 +1131,7 @@ module Private {
if preservesValue = true then value = "value" else value = "taint" if preservesValue = true then value = "value" else value = "taint"
) )
or or
exists(Content c | exists(ContentSet c |
Private::Steps::summaryReadStep(a.asNode(), c, b.asNode()) and Private::Steps::summaryReadStep(a.asNode(), c, b.asNode()) and
value = "read (" + c + ")" value = "read (" + c + ")"
or or

View File

@@ -41,13 +41,17 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) { any() }
/** /**
* Holds if an external flow summary exists for `c` with input specification * Holds if an external flow summary exists for `c` with input specification
* `input`, output specification `output`, and kind `kind`. * `input`, output specification `output`, kind `kind`, and a flag `generated`
* stating whether the summary is autogenerated.
*/ */
predicate summaryElement(DataFlowCallable c, string input, string output, string kind) { predicate summaryElement(
DataFlowCallable c, string input, string output, string kind, boolean generated
) {
exists(FlowSummary::SummarizedCallable sc, boolean preservesValue | exists(FlowSummary::SummarizedCallable sc, boolean preservesValue |
sc.propagatesFlowExt(input, output, preservesValue) and sc.propagatesFlowExt(input, output, preservesValue) and
c.asLibraryCallable() = sc and c.asLibraryCallable() = sc and
if preservesValue = true then kind = "value" else kind = "taint" (if preservesValue = true then kind = "value" else kind = "taint") and
generated = false
) )
} }
@@ -92,16 +96,18 @@ ReturnKind getReturnValueKind() { any() }
*/ */
private module UnusedSourceSinkInterpretation { private module UnusedSourceSinkInterpretation {
/** /**
* Holds if an external source specification exists for `e` with output specification * Holds if an external source specification exists for `n` with output specification
* `output` and kind `kind`. * `output`, kind `kind`, and a flag `generated` stating whether the source specification is
* autogenerated.
*/ */
predicate sourceElement(AstNode n, string output, string kind) { none() } predicate sourceElement(AstNode n, string output, string kind, boolean generated) { none() }
/** /**
* Holds if an external sink specification exists for `n` with input specification * Holds if an external sink specification exists for `n` with input specification
* `input` and kind `kind`. * `input`, kind `kind` and a flag `generated` stating whether the sink specification is
* autogenerated.
*/ */
predicate sinkElement(AstNode n, string input, string kind) { none() } predicate sinkElement(AstNode n, string input, string kind, boolean generated) { none() }
class SourceOrSinkElement = AstNode; class SourceOrSinkElement = AstNode;

View File

@@ -11,6 +11,6 @@
import python import python
import semmle.python.dataflow.new.internal.DataFlowPrivate import semmle.python.dataflow.new.internal.DataFlowPrivate
from DataFlowCall c, DataFlowCallableValue f from DataFlowSourceCall c, DataFlowCallableValue f
where c.getCallable() = f where c.getCallable() = f
select c, "Call to $@", f.getScope(), f.toString() select c, "Call to $@", f.getScope(), f.toString()

View File

@@ -49,6 +49,12 @@ abstract class RoutingTest extends InlineExpectationsTest {
pragma[inline] pragma[inline]
private string toFunc(DataFlow::Node toNode) { private string toFunc(DataFlow::Node toNode) {
result = toNode.getEnclosingCallable().(DataFlowPrivate::NonLibraryDataFlowCallable).getCallableValue().getScope().getQualifiedName() // TODO: More robust pretty printing? result =
toNode
.getEnclosingCallable()
.(DataFlowPrivate::NonLibraryDataFlowCallable)
.getCallableValue()
.getScope()
.getQualifiedName() // TODO: More robust pretty printing?
} }
} }

View File

@@ -58,13 +58,16 @@ private class SummarizedCallableMap extends SummarizedCallable {
preservesValue = true preservesValue = true
} }
} }
// Typetracking needs to use a local flow step not including summaries // Typetracking needs to use a local flow step not including summaries
// Typetracking needs to use a call graph not including summaries // Typetracking needs to use a call graph not including summaries
private class SummarizedCallableJsonLoads extends SummarizedCallable { private class SummarizedCallableJsonLoads extends SummarizedCallable {
SummarizedCallableJsonLoads() { this = "json.loads" } SummarizedCallableJsonLoads() { this = "json.loads" }
override Call getACall() { override Call getACall() {
result = API::moduleImport("json").getMember("loads").getACall().asExpr() result = API::moduleImport("json").getMember("loads").getACall().asExpr()
} }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0]" and input = "Argument[0]" and
output = "ReturnValue.ListElement" and output = "ReturnValue.ListElement" and