Skip to content

Commit 189c160

Browse files
committed
Data flow: Add FeatureEscapesSourceCallContext(OrEqualSourceSinkCallContext) flow feature
1 parent 600f585 commit 189c160

File tree

3 files changed

+182
-39
lines changed

3 files changed

+182
-39
lines changed

shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll

Lines changed: 144 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
567567
) {
568568
sourceNode(node) and
569569
(if hasSourceCallCtx() then cc = ccSomeCall() else cc = ccNone()) and
570-
summaryCtx = TSummaryCtxNone() and
570+
summaryCtx.isSourceCtx() and
571571
t = getNodeTyp(node) and
572572
ap instanceof ApNil and
573573
apa = getApprox(ap) and
@@ -602,18 +602,19 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
602602
apa = getApprox(ap)
603603
or
604604
// flow into a callable without summary context
605-
fwdFlowInNoFlowThrough(node, cc, t, ap, stored) and
605+
fwdFlowInNoFlowThrough(node, cc, summaryCtx, t, ap, stored) and
606606
apa = getApprox(ap) and
607-
summaryCtx = TSummaryCtxNone() and
608607
// When the call contexts of source and sink needs to match then there's
609608
// never any reason to enter a callable except to find a summary. See also
610609
// the comment in `PathNodeMid::isAtSink`.
611610
not Config::getAFeature() instanceof FeatureEqualSourceSinkCallContext
612611
or
613612
// flow into a callable with summary context (non-linear recursion)
614-
fwdFlowInFlowThrough(node, cc, t, ap, stored) and
615-
apa = getApprox(ap) and
616-
summaryCtx = TSummaryCtxSome(node, t, ap, stored)
613+
exists(boolean mustReturn |
614+
fwdFlowInFlowThrough(node, cc, t, ap, stored, mustReturn) and
615+
apa = getApprox(ap) and
616+
summaryCtx = TSummaryCtxSome(node, t, ap, stored, mustReturn)
617+
)
617618
or
618619
// flow out of a callable
619620
fwdFlowOut(_, _, node, cc, summaryCtx, t, ap, stored) and
@@ -630,9 +631,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
630631

631632
private newtype TSummaryCtx =
632633
TSummaryCtxNone() or
633-
TSummaryCtxSome(ParamNd p, Typ t, Ap ap, TypOption stored) {
634-
fwdFlowInFlowThrough(p, _, t, ap, stored)
635-
}
634+
TSummaryCtxSome(ParamNd p, Typ t, Ap ap, TypOption stored, Boolean mustReturn) {
635+
fwdFlowInFlowThrough(p, _, t, ap, stored, mustReturn)
636+
} or
637+
TSummaryCtxSource(Boolean mustEscape)
636638

637639
/**
638640
* A context for generating flow summaries. This represents flow entry through
@@ -644,6 +646,69 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
644646
abstract string toString();
645647

646648
abstract Location getLocation();
649+
650+
/**
651+
* Holds if this context is the unique context used at flow sources.
652+
*/
653+
predicate isSourceCtx() {
654+
exists(boolean strict |
655+
Stage1::hasFeatureEscapesSourceCallContext(strict) and
656+
this = TSummaryCtxSource(strict)
657+
)
658+
or
659+
not Stage1::hasFeatureEscapesSourceCallContext(_) and
660+
this = TSummaryCtxNone()
661+
}
662+
663+
pragma[nomagic]
664+
private predicate isSome(boolean mustReturn) {
665+
this = TSummaryCtxSome(_, _, _, _, mustReturn)
666+
}
667+
668+
/**
669+
* Holds if this context is valid as a flow-in context when no flow-through is possible,
670+
* in which case `innerSummaryCtx` is the summary context to be used when entering the
671+
* callable.
672+
*/
673+
pragma[nomagic]
674+
predicate isValidForFlowInNoThrough(SummaryCtx innerSummaryCtx) {
675+
this = TSummaryCtxNone() and
676+
innerSummaryCtx = TSummaryCtxNone()
677+
or
678+
this.isSome(false) and
679+
innerSummaryCtx = TSummaryCtxNone()
680+
or
681+
// Even if we must escape the source call context, we can still allow for flow-in
682+
// without flow-through, as long as the inner context is escaped (which must then
683+
// necessarily be via a jump-step -- possibly after even more flow-in
684+
// without-flow-through steps).
685+
this = TSummaryCtxSource(_) and
686+
innerSummaryCtx = TSummaryCtxSource(true)
687+
}
688+
689+
/**
690+
* Holds if this context is valid as a flow-in context when flow-through is possible.
691+
*
692+
* The boolean `mustReturn` indicates whether flow must return.
693+
*/
694+
predicate isValidForFlowThrough(boolean mustReturn) {
695+
this = TSummaryCtxSource(_) and
696+
mustReturn = true
697+
or
698+
this = TSummaryCtxNone() and
699+
mustReturn = false
700+
or
701+
this.isSome(mustReturn)
702+
}
703+
704+
/** Holds if this context is valid as a sink context. */
705+
predicate isASinkCtx() {
706+
this = TSummaryCtxNone()
707+
or
708+
this.isSome(false)
709+
or
710+
this = TSummaryCtxSource(false)
711+
}
647712
}
648713

649714
/** A summary context from which no flow summary can be generated. */
@@ -659,20 +724,43 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
659724
private Typ t;
660725
private Ap ap;
661726
private TypOption stored;
727+
private boolean mustReturn;
662728

663-
SummaryCtxSome() { this = TSummaryCtxSome(p, t, ap, stored) }
729+
SummaryCtxSome() { this = TSummaryCtxSome(p, t, ap, stored, mustReturn) }
664730

665731
ParamNd getParamNode() { result = p }
666732

667733
private string ppTyp() { result = t.toString() and result != "" }
668734

735+
private string ppMustReturn() {
736+
if mustReturn = true then result = " <mustReturn>" else result = ""
737+
}
738+
669739
override string toString() {
670-
result = p + concat(" : " + this.ppTyp()) + " " + ap + ppStored(stored)
740+
result =
741+
p + concat(" : " + this.ppTyp()) + " " + ap + ppStored(stored) + this.ppMustReturn()
671742
}
672743

673744
override Location getLocation() { result = p.getLocation() }
674745
}
675746

747+
/**
748+
* A special summary context that is used when the flow feature
749+
* `FeatureEscapesSourceCallContext(OrEqualSourceSinkCallContext)`
750+
* is enabled.
751+
*/
752+
private class SummaryCtxSource extends SummaryCtx, TSummaryCtxSource {
753+
private boolean mustEscape;
754+
755+
SummaryCtxSource() { this = TSummaryCtxSource(mustEscape) }
756+
757+
override string toString() {
758+
if mustEscape = true then result = "<source-must-escape>" else result = "<source>"
759+
}
760+
761+
override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) }
762+
}
763+
676764
private predicate fwdFlowJump(Nd node, Typ t, Ap ap, TypOption stored) {
677765
exists(Nd mid |
678766
fwdFlow(mid, _, _, t, ap, stored) and
@@ -915,9 +1003,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
9151003

9161004
pragma[nomagic]
9171005
private predicate fwdFlowInNoFlowThrough(
918-
ParamNd p, CcCall innercc, Typ t, Ap ap, TypOption stored
1006+
ParamNd p, CcCall innercc, SummaryCtx innerSummaryCtx, Typ t, Ap ap, TypOption stored
9191007
) {
920-
FwdFlowInNoThrough::fwdFlowIn(_, _, _, p, _, innercc, _, t, ap, stored, _)
1008+
exists(SummaryCtx summaryCtx |
1009+
FwdFlowInNoThrough::fwdFlowIn(_, _, _, p, _, innercc, summaryCtx, t, ap, stored, _) and
1010+
summaryCtx.isValidForFlowInNoThrough(innerSummaryCtx)
1011+
)
9211012
}
9221013

9231014
private predicate top() { any() }
@@ -926,9 +1017,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
9261017

9271018
pragma[nomagic]
9281019
private predicate fwdFlowInFlowThrough(
929-
ParamNd p, CcCall innercc, Typ t, Ap ap, TypOption stored
1020+
ParamNd p, CcCall innercc, Typ t, Ap ap, TypOption stored, boolean mustReturn
9301021
) {
931-
FwdFlowInThrough::fwdFlowIn(_, _, _, p, _, innercc, _, t, ap, stored, _)
1022+
exists(SummaryCtx outerSummaryCtx |
1023+
FwdFlowInThrough::fwdFlowIn(_, _, _, p, _, innercc, outerSummaryCtx, t, ap, stored, _) and
1024+
outerSummaryCtx.isValidForFlowThrough(mustReturn)
1025+
)
9321026
}
9331027

9341028
pragma[nomagic]
@@ -999,7 +1093,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
9991093
TypOption stored
10001094
) {
10011095
exists(RetNd ret, CcNoCall innercc, boolean allowsFieldFlow |
1002-
fwdFlowIntoRet(ret, innercc, summaryCtx, t, ap, stored) and
1096+
fwdFlowIntoRet(ret, innercc, _, t, ap, stored) and
1097+
summaryCtx = TSummaryCtxNone() and
10031098
fwdFlowOutValidEdge(call, ret, innercc, inner, out, outercc, allowsFieldFlow) and
10041099
if allowsFieldFlow = false then ap instanceof ApNil else any()
10051100
)
@@ -1090,7 +1185,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
10901185
instanceofCcCall(ccc) and
10911186
fwdFlow(pragma[only_bind_into](ret), ccc, summaryCtx, t, ap, stored) and
10921187
summaryCtx =
1093-
TSummaryCtxSome(pragma[only_bind_into](p), _, pragma[only_bind_into](argAp), _) and
1188+
TSummaryCtxSome(pragma[only_bind_into](p), _, pragma[only_bind_into](argAp), _, _) and
10941189
kind = ret.getKind() and
10951190
Stage1::parameterFlowThroughAllowed(p, kind) and
10961191
PrevStage::returnMayFlowThrough(ret, kind)
@@ -1116,9 +1211,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
11161211
pragma[nomagic]
11171212
private predicate fwdFlowIsEntered0(
11181213
Call call, ArgNd arg, Cc cc, CcCall innerCc, SummaryCtx summaryCtx, ParamNd p, Typ t,
1119-
Ap ap, TypOption stored
1214+
Ap ap, TypOption stored, boolean mustReturn
11201215
) {
1121-
FwdFlowInThrough::fwdFlowIn(call, arg, _, p, cc, innerCc, summaryCtx, t, ap, stored, _)
1216+
FwdFlowInThrough::fwdFlowIn(call, arg, _, p, cc, innerCc, summaryCtx, t, ap, stored, _) and
1217+
summaryCtx.isValidForFlowThrough(mustReturn)
11221218
}
11231219

11241220
/**
@@ -1130,9 +1226,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
11301226
Call call, ArgNd arg, Cc cc, CcCall innerCc, SummaryCtx summaryCtx,
11311227
SummaryCtxSome innerSummaryCtx
11321228
) {
1133-
exists(ParamNd p, Typ t, Ap ap, TypOption stored |
1134-
fwdFlowIsEntered0(call, arg, cc, innerCc, summaryCtx, p, t, ap, stored) and
1135-
innerSummaryCtx = TSummaryCtxSome(p, t, ap, stored)
1229+
exists(ParamNd p, Typ t, Ap ap, TypOption stored, boolean mustReturn |
1230+
fwdFlowIsEntered0(call, arg, cc, innerCc, summaryCtx, p, t, ap, stored, mustReturn) and
1231+
innerSummaryCtx = TSummaryCtxSome(p, t, ap, stored, mustReturn)
11361232
)
11371233
}
11381234

@@ -1160,7 +1256,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
11601256
TypOption argStored, Ap ap
11611257
) {
11621258
exists(Call call, boolean allowsFieldFlow |
1163-
returnFlowsThrough0(call, ccc, ap, ret, TSummaryCtxSome(p, argT, argAp, argStored)) and
1259+
returnFlowsThrough0(call, ccc, ap, ret, TSummaryCtxSome(p, argT, argAp, argStored, _)) and
11641260
flowThroughOutOfCall(call, ret, _, allowsFieldFlow) and
11651261
pos = ret.getReturnPosition() and
11661262
if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1216,7 +1312,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
12161312

12171313
pragma[nomagic]
12181314
private predicate revFlow0(Nd node, ReturnCtx returnCtx, ApOption returnAp, Ap ap) {
1219-
fwdFlow(node, _, _, _, ap, _) and
1315+
fwdFlow(node, _, any(SummaryCtx sinkCtx | sinkCtx.isASinkCtx()), _, ap, _) and
12201316
sinkNode(node) and
12211317
(
12221318
if hasSinkCallCtx()
@@ -1490,7 +1586,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
14901586
exists(Ap ap0 |
14911587
parameterMayFlowThrough(p, _) and
14921588
revFlow(n, TReturnCtxMaybeFlowThrough(_), _, ap0) and
1493-
fwdFlow(n, any(CcCall ccc), TSummaryCtxSome(p, _, ap, _), _, ap0, _)
1589+
fwdFlow(n, any(CcCall ccc), TSummaryCtxSome(p, _, ap, _, _), _, ap0, _)
14941590
)
14951591
}
14961592

@@ -1962,6 +2058,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
19622058
private string ppSummaryCtx() {
19632059
summaryCtx instanceof SummaryCtxNone and result = ""
19642060
or
2061+
result = " " + summaryCtx.(SummaryCtxSource)
2062+
or
19652063
summaryCtx instanceof SummaryCtxSome and
19662064
result = " <" + summaryCtx + ">"
19672065
}
@@ -1983,14 +2081,15 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
19832081
override predicate isSource() {
19842082
sourceNode(node) and
19852083
(if hasSourceCallCtx() then cc = ccSomeCall() else cc = ccNone()) and
1986-
summaryCtx = TSummaryCtxNone() and
2084+
summaryCtx.isSourceCtx() and
19872085
t = getNodeTyp(node) and
19882086
ap instanceof ApNil
19892087
}
19902088

19912089
predicate isAtSink() {
19922090
sinkNode(node) and
19932091
ap instanceof ApNil and
2092+
summaryCtx.isASinkCtx() and
19942093
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
19952094
// is exactly what we need to check.
19962095
// For `FeatureEqualSourceSinkCallContext` the initial call
@@ -2042,10 +2141,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
20422141
override predicate isSource() { sourceNode(node) }
20432142
}
20442143

2045-
bindingset[p, t, ap, stored]
2144+
bindingset[p, t, ap, stored, mustReturn]
20462145
pragma[inline_late]
2047-
private SummaryCtxSome mkSummaryCtxSome(ParamNd p, Typ t, Ap ap, TypOption stored) {
2048-
result = TSummaryCtxSome(p, t, ap, stored)
2146+
private SummaryCtxSome mkSummaryCtxSome(
2147+
ParamNd p, Typ t, Ap ap, TypOption stored, boolean mustReturn
2148+
) {
2149+
result = TSummaryCtxSome(p, t, ap, stored, mustReturn)
20492150
}
20502151

20512152
pragma[nomagic]
@@ -2055,11 +2156,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
20552156
) {
20562157
FwdFlowInNoThrough::fwdFlowIn(_, arg, _, p, outercc, innercc, outerSummaryCtx, t, ap,
20572158
stored, _) and
2058-
innerSummaryCtx = TSummaryCtxNone()
2159+
outerSummaryCtx.isValidForFlowInNoThrough(innerSummaryCtx)
20592160
or
2060-
FwdFlowInThrough::fwdFlowIn(_, arg, _, p, outercc, innercc, outerSummaryCtx, t, ap,
2061-
stored, _) and
2062-
innerSummaryCtx = mkSummaryCtxSome(p, t, ap, stored)
2161+
exists(boolean mustReturn |
2162+
FwdFlowInThrough::fwdFlowIn(_, arg, _, p, outercc, innercc, outerSummaryCtx, t, ap,
2163+
stored, _) and
2164+
outerSummaryCtx.isValidForFlowThrough(mustReturn) and
2165+
innerSummaryCtx = mkSummaryCtxSome(p, t, ap, stored, mustReturn)
2166+
)
20632167
}
20642168

20652169
pragma[nomagic]
@@ -2098,7 +2202,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
20982202
|
20992203
fwdFlowThroughStep0(call, arg, cc, ccc, summaryCtx, t, ap, stored, ret,
21002204
innerSummaryCtx) and
2101-
innerSummaryCtx = TSummaryCtxSome(p, innerArgT, innerArgAp, innerArgStored) and
2205+
innerSummaryCtx = TSummaryCtxSome(p, innerArgT, innerArgAp, innerArgStored, _) and
21022206
pn1 = mkPathNode(arg, cc, summaryCtx, innerArgT, innerArgAp, innerArgStored) and
21032207
pn2 =
21042208
typeStrengthenToPathNode(p, ccc, innerSummaryCtx, innerArgT, innerArgAp,
@@ -2212,11 +2316,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
22122316
)
22132317
or
22142318
// flow out of a callable
2215-
exists(RetNd ret, CcNoCall innercc, boolean allowsFieldFlow |
2216-
pn1 = TPathNodeMid(ret, innercc, summaryCtx, t, ap, stored) and
2217-
fwdFlowIntoRet(ret, innercc, summaryCtx, t, ap, stored) and
2319+
exists(
2320+
RetNd ret, CcNoCall innercc, SummaryCtx innerSummaryCtx, boolean allowsFieldFlow
2321+
|
2322+
pn1 = TPathNodeMid(ret, innercc, innerSummaryCtx, t, ap, stored) and
2323+
fwdFlowIntoRet(ret, innercc, innerSummaryCtx, t, ap, stored) and
22182324
fwdFlowOutValidEdge(_, ret, innercc, _, node, cc, allowsFieldFlow) and
22192325
label = "" and
2326+
summaryCtx = TSummaryCtxNone() and
22202327
if allowsFieldFlow = false then ap instanceof ApNil else any()
22212328
)
22222329
}

0 commit comments

Comments
 (0)