Skip to content

Commit bb2ec12

Browse files
committed
Shared: Support "reverse flow" summaries. That is, summaries starting from the return value of a call.
1 parent 03c3ef9 commit bb2ec12

1 file changed

Lines changed: 114 additions & 8 deletions

File tree

shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,24 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> Lang> {
5454
none()
5555
}
5656

57+
/**
58+
* A base class of calls that are candidates for flow summary modeling.
59+
*/
60+
class FlowSummaryCallBase {
61+
string toString();
62+
}
63+
64+
/** Gets a call that targets summarized callable `sc`. */
65+
default FlowSummaryCallBase getASourceCall(SummarizedCallableBase sc) { none() }
66+
67+
/** Gets the callable corresponding to summarized callable `c`. */
68+
default Lang::DataFlowCallable getSummarizedCallableAsDataFlowCallable(SummarizedCallableBase c) {
69+
none()
70+
}
71+
72+
/** Gets the enclosing callable of `call`. */
73+
default Lang::DataFlowCallable getSourceCallEnclosingCallable(FlowSummaryCallBase call) { none() }
74+
5775
/** Gets the parameter position representing a callback itself, if any. */
5876
default Lang::ArgumentPosition callbackSelfParameterPosition() { none() }
5977

@@ -74,6 +92,9 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> Lang> {
7492
result = getStandardReturnValueKind()
7593
}
7694

95+
/** Gets the parameter position corresponding to a flow-summary return kind `rk`, if any. */
96+
default Lang::ParameterPosition getFlowSummaryParameterPosition(Lang::ReturnKind rk) { none() }
97+
7798
/** Gets the textual representation of parameter position `pos` used in MaD. */
7899
string encodeParameterPosition(Lang::ParameterPosition pos);
79100

@@ -660,6 +681,10 @@ module Make<
660681
s.length() = 1 and
661682
s.head() instanceof TArgumentSummaryComponent
662683
or
684+
// ReturnValue.*
685+
s.length() = 1 and
686+
s.head() instanceof TReturnSummaryComponent
687+
or
663688
// Argument[n].ReturnValue.*
664689
s.length() = 2 and
665690
s.head() instanceof TReturnSummaryComponent and
@@ -1137,6 +1162,13 @@ module Make<
11371162
outputState(c, s) and s = SummaryComponentStack::argument(_)
11381163
}
11391164

1165+
private predicate relevantFlowSummaryPosition(SummarizedCallable c, ReturnKind rk) {
1166+
exists(SummaryComponentStack input |
1167+
summary(c, input, _, _, _) and
1168+
input = TSingletonSummaryComponentStack(TReturnSummaryComponent(rk))
1169+
)
1170+
}
1171+
11401172
pragma[nomagic]
11411173
private predicate sourceOutputStateEntry(
11421174
SourceElement source, SummaryComponentStack s, string kind, string model
@@ -1272,6 +1304,12 @@ module Make<
12721304
TSummaryParameterNode(SummarizedCallable c, ParameterPosition pos) {
12731305
summaryParameterNodeRange(c, pos)
12741306
} or
1307+
TSummaryReturnArgumentNode(FlowSummaryCallBase call, ReturnKind rk) {
1308+
exists(SummarizedCallable sc |
1309+
call = getASourceCall(sc) and
1310+
relevantFlowSummaryPosition(sc, rk)
1311+
)
1312+
} or
12751313
TSourceOutputNode(SourceElement source, SummaryNodeState state, string kind, string model) {
12761314
state.isSourceOutputState(source, _, kind, model)
12771315
} or
@@ -1321,6 +1359,39 @@ module Make<
13211359
override SinkElement getSinkElement() { none() }
13221360
}
13231361

1362+
private class SummaryReturnArgumentNode extends SummaryNode, TSummaryReturnArgumentNode {
1363+
private FlowSummaryCallBase call;
1364+
private ReturnKind rk;
1365+
1366+
SummaryReturnArgumentNode() { this = TSummaryReturnArgumentNode(call, rk) }
1367+
1368+
override string toString() { result = "[summary] value written to " + rk + " at " + call }
1369+
1370+
override SummarizedCallable getSummarizedCallable() { none() }
1371+
1372+
override SourceElement getSourceElement() { none() }
1373+
1374+
override SinkElement getSinkElement() { none() }
1375+
}
1376+
1377+
/**
1378+
* Gets the summary node that represents the for `call` returning a value
1379+
* with kind `rk`.
1380+
*/
1381+
SummaryNode summaryArgumentNode(FlowSummaryCallBase call, ReturnKind rk) {
1382+
result = TSummaryReturnArgumentNode(call, rk)
1383+
}
1384+
1385+
/** Gets the enclosing callable for summary node `sn`. */
1386+
DataFlowCallable getEnclosingCallable(SummaryNode sn) {
1387+
result = getSummarizedCallableAsDataFlowCallable(sn.getSummarizedCallable())
1388+
or
1389+
exists(FlowSummaryCallBase call |
1390+
sn = TSummaryReturnArgumentNode(call, _) and
1391+
result = getSourceCallEnclosingCallable(call)
1392+
)
1393+
}
1394+
13241395
class SourceOutputNode extends SummaryNode, TSourceOutputNode {
13251396
private SourceElement source_;
13261397
private SummaryNodeState state_;
@@ -1427,6 +1498,12 @@ module Make<
14271498
SummarizedCallable c, SummaryNodeState state, ParameterPosition pos
14281499
) {
14291500
state.isInputState(c, SummaryComponentStack::argument(pos))
1501+
or
1502+
exists(ReturnKind rk |
1503+
relevantFlowSummaryPosition(c, rk) and
1504+
state.isInputState(c, SummaryComponentStack::return(rk)) and
1505+
pos = getFlowSummaryParameterPosition(rk)
1506+
)
14301507
}
14311508

14321509
/**
@@ -1560,6 +1637,9 @@ module Make<
15601637
)
15611638
}
15621639

1640+
/** Holds if return kind `rk` is a relevant return kind for flow summary modeling. */
1641+
predicate relevantFlowSummaryPosition(ReturnKind rk) { relevantFlowSummaryPosition(_, rk) }
1642+
15631643
/**
15641644
* Holds if flow is allowed to pass from the parameter at position `pos` of `c`,
15651645
* to a return node, and back out to the parameter.
@@ -1736,9 +1816,15 @@ module Make<
17361816
}
17371817

17381818
signature module StepsInputSig {
1819+
/** Gets the summary node represented by data-flow node `n`, if any. */
1820+
SummaryNode getSummaryNode(Node n);
1821+
17391822
/** Gets a call that targets summarized callable `sc`. */
17401823
DataFlowCall getACall(SummarizedCallable sc);
17411824

1825+
/** Gets the out node of kind `rk` for `call`, if any. */
1826+
default Node getSourceOutNode(FlowSummaryCallBase call, ReturnKind rk) { none() }
1827+
17421828
/** Gets the enclosing callable of `source`. */
17431829
DataFlowCallable getSourceNodeEnclosingCallable(SourceBase source);
17441830

@@ -1765,7 +1851,7 @@ module Make<
17651851
* Holds if there is a local step from `pred` to `succ`, which is synthesized
17661852
* from a flow summary.
17671853
*/
1768-
predicate summaryLocalStep(
1854+
private predicate summaryLocalStepImpl(
17691855
SummaryNode pred, SummaryNode succ, boolean preservesValue, string model
17701856
) {
17711857
exists(
@@ -1811,9 +1897,27 @@ module Make<
18111897
)
18121898
}
18131899

1900+
/** Holds if there is a local step between data-flow nodes synthesized from a flow summary. */
1901+
predicate summaryLocalStep(Node pred, SummaryNode succ, boolean preservesValue, string model) {
1902+
exists(SummaryNode predSummary |
1903+
predSummary = StepsInput::getSummaryNode(pred) and
1904+
summaryLocalStepImpl(predSummary, succ, preservesValue, model)
1905+
)
1906+
or
1907+
exists(
1908+
FlowSummaryCallBase summaryCall, ReturnKind rk, SummarizedCallable sc,
1909+
SummaryComponentStack output
1910+
|
1911+
pred = StepsInput::getSourceOutNode(summaryCall, rk) and
1912+
summaryCall = getASourceCall(sc) and
1913+
summary(sc, SummaryComponentStack::return(rk), output, preservesValue, model) and
1914+
succ = TSummaryReturnArgumentNode(summaryCall, rk)
1915+
)
1916+
}
1917+
18141918
/** Holds if the value of `succ` is uniquely determined by the value of `pred`. */
18151919
predicate summaryLocalMustFlowStep(SummaryNode pred, SummaryNode succ) {
1816-
pred = unique(SummaryNode n1 | summaryLocalStep(n1, succ, true, _))
1920+
pred = unique(SummaryNode n1 | summaryLocalStepImpl(n1, succ, true, _))
18171921
}
18181922

18191923
/**
@@ -1935,7 +2039,7 @@ module Make<
19352039
or
19362040
exists(SummaryNode mid, boolean clearsOrExpectsMid |
19372041
paramReachesLocal(p, mid, clearsOrExpectsMid) and
1938-
summaryLocalStep(mid, n, true, _) and
2042+
summaryLocalStepImpl(mid, n, true, _) and
19392043
if
19402044
summaryClearsContent(n, _) or
19412045
summaryExpectsContent(n, _)
@@ -1993,7 +2097,7 @@ module Make<
19932097
*/
19942098
predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) {
19952099
exists(SummaryNode ret |
1996-
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, true, _)
2100+
summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), ret, true, _)
19972101
)
19982102
}
19992103

@@ -2006,7 +2110,7 @@ module Make<
20062110
*/
20072111
predicate summaryThroughStepTaint(ArgNode arg, Node out, SummarizedCallable sc) {
20082112
exists(SummaryNode ret |
2009-
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, false, _)
2113+
summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), ret, false, _)
20102114
)
20112115
}
20122116

@@ -2020,7 +2124,7 @@ module Make<
20202124
predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
20212125
exists(SummaryNode mid, SummaryNode ret |
20222126
summaryReadStep(summaryArgParamRetOut(arg, ret, out, sc), c, mid) and
2023-
summaryLocalStep(mid, ret, _, _)
2127+
summaryLocalStepImpl(mid, ret, _, _)
20242128
)
20252129
}
20262130

@@ -2033,7 +2137,7 @@ module Make<
20332137
*/
20342138
predicate summarySetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
20352139
exists(SummaryNode mid, SummaryNode ret |
2036-
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), mid, _, _) and
2140+
summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), mid, _, _) and
20372141
summaryStoreStep(mid, c, ret)
20382142
)
20392143
}
@@ -2749,9 +2853,11 @@ module Make<
27492853
key = "semmle.label" and val = n.toString()
27502854
}
27512855

2856+
private Node getNode(SummaryNode sn) { sn = StepsInput::getSummaryNode(result) }
2857+
27522858
private predicate edgesComponent(NodeOrCall a, NodeOrCall b, string value) {
27532859
exists(boolean preservesValue |
2754-
PrivateSteps::summaryLocalStep(a.asNode(), b.asNode(), preservesValue, _) and
2860+
PrivateSteps::summaryLocalStep(getNode(a.asNode()), b.asNode(), preservesValue, _) and
27552861
if preservesValue = true then value = "value" else value = "taint"
27562862
)
27572863
or

0 commit comments

Comments
 (0)