Skip to content

Commit bffa8fa

Browse files
authored
Merge pull request #8641 from hvitved/dataflow/interpret-read-store
Data flow: Introduce `ContentSet`
2 parents ba2a884 + 2466288 commit bffa8fa

File tree

89 files changed

+2871
-1172
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+2871
-1172
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: breaking
3+
---
4+
The signature of `allowImplicitRead` on `DataFlow::Configuration` and `TaintTracking::Configuration` has changed from `allowImplicitRead(DataFlow::Node node, DataFlow::Content c)` to `allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c)`.

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll

Lines changed: 77 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
116116
* Holds if an arbitrary number of implicit read steps of content `c` may be
117117
* taken at `node`.
118118
*/
119-
predicate allowImplicitRead(Node node, Content c) { none() }
119+
predicate allowImplicitRead(Node node, ContentSet c) { none() }
120120

121121
/**
122122
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
485485
)
486486
}
487487

488-
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
489-
read(node1.asNode(), c, node2.asNode()) and
488+
pragma[nomagic]
489+
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
490+
readSet(node1.asNode(), c, node2.asNode()) and
490491
stepFilter(node1, node2, config)
491492
or
492493
exists(Node n |
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
496497
)
497498
}
498499

500+
// inline to reduce fan-out via `getAReadContent`
501+
pragma[inline]
502+
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
503+
exists(ContentSet cs |
504+
readSet(node1, cs, node2, config) and
505+
c = cs.getAReadContent()
506+
)
507+
}
508+
509+
// inline to reduce fan-out via `getAReadContent`
510+
pragma[inline]
511+
private predicate clearsContentEx(NodeEx n, Content c) {
512+
exists(ContentSet cs |
513+
clearsContentCached(n.asNode(), cs) and
514+
c = cs.getAReadContent()
515+
)
516+
}
517+
518+
pragma[nomagic]
499519
private predicate store(
500520
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
501521
) {
@@ -573,9 +593,9 @@ private module Stage1 {
573593
)
574594
or
575595
// read
576-
exists(Content c |
577-
fwdFlowRead(c, node, cc, config) and
578-
fwdFlowConsCand(c, config)
596+
exists(ContentSet c |
597+
fwdFlowReadSet(c, node, cc, config) and
598+
fwdFlowConsCandSet(c, _, config)
579599
)
580600
or
581601
// flow into a callable
@@ -599,10 +619,10 @@ private module Stage1 {
599619
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
600620

601621
pragma[nomagic]
602-
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
622+
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
603623
exists(NodeEx mid |
604624
fwdFlow(mid, cc, config) and
605-
read(mid, c, node, config)
625+
readSet(mid, c, node, config)
606626
)
607627
}
608628

@@ -620,6 +640,16 @@ private module Stage1 {
620640
)
621641
}
622642

643+
/**
644+
* Holds if `cs` may be interpreted in a read as the target of some store
645+
* into `c`, in the flow covered by `fwdFlow`.
646+
*/
647+
pragma[nomagic]
648+
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
649+
fwdFlowConsCand(c, config) and
650+
c = cs.getAReadContent()
651+
}
652+
623653
pragma[nomagic]
624654
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
625655
exists(RetNodeEx ret |
@@ -712,9 +742,9 @@ private module Stage1 {
712742
)
713743
or
714744
// read
715-
exists(NodeEx mid, Content c |
716-
read(node, c, mid, config) and
717-
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
745+
exists(NodeEx mid, ContentSet c |
746+
readSet(node, c, mid, config) and
747+
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
718748
revFlow(mid, toReturn, pragma[only_bind_into](config))
719749
)
720750
or
@@ -740,10 +770,10 @@ private module Stage1 {
740770
*/
741771
pragma[nomagic]
742772
private predicate revFlowConsCand(Content c, Configuration config) {
743-
exists(NodeEx mid, NodeEx node |
773+
exists(NodeEx mid, NodeEx node, ContentSet cs |
744774
fwdFlow(node, pragma[only_bind_into](config)) and
745-
read(node, c, mid, config) and
746-
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
775+
readSet(node, cs, mid, config) and
776+
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
747777
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
748778
)
749779
}
@@ -762,6 +792,7 @@ private module Stage1 {
762792
* Holds if `c` is the target of both a read and a store in the flow covered
763793
* by `revFlow`.
764794
*/
795+
pragma[nomagic]
765796
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
766797
revFlowConsCand(c, conf) and
767798
revFlowStore(c, _, _, conf)
@@ -860,9 +891,9 @@ private module Stage1 {
860891

861892
pragma[nomagic]
862893
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
863-
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
864-
revFlow(n2, pragma[only_bind_into](config)) and
865-
read(n1, c, n2, pragma[only_bind_into](config))
894+
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
895+
read(n1, c, n2, pragma[only_bind_into](config)) and
896+
revFlow(n2, pragma[only_bind_into](config))
866897
}
867898

868899
pragma[nomagic]
@@ -1574,7 +1605,7 @@ private module Stage2 {
15741605
Configuration config
15751606
) {
15761607
exists(Ap ap2, Content c |
1577-
store(node1, tc, node2, contentType, config) and
1608+
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
15781609
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
15791610
revFlowConsCand(ap2, c, ap1, config)
15801611
)
@@ -1729,9 +1760,9 @@ private module LocalFlowBigStep {
17291760
or
17301761
node.asNode() instanceof OutNodeExt
17311762
or
1732-
store(_, _, node, _, config)
1763+
Stage2::storeStepCand(_, _, _, node, _, config)
17331764
or
1734-
read(_, _, node, config)
1765+
Stage2::readStepCand(_, _, node, config)
17351766
or
17361767
node instanceof FlowCheckNode
17371768
or
@@ -1752,8 +1783,8 @@ private module LocalFlowBigStep {
17521783
additionalJumpStep(node, next, config) or
17531784
flowIntoCallNodeCand1(_, node, next, config) or
17541785
flowOutOfCallNodeCand1(_, node, next, config) or
1755-
store(node, _, next, _, config) or
1756-
read(node, _, next, config)
1786+
Stage2::storeStepCand(node, _, _, next, _, config) or
1787+
Stage2::readStepCand(node, _, next, config)
17571788
)
17581789
or
17591790
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1926,7 +1957,24 @@ private module Stage3 {
19261957
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
19271958

19281959
pragma[nomagic]
1929-
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
1960+
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
1961+
PrevStage::revFlow(node, config) and
1962+
clearsContentCached(node.asNode(), c)
1963+
}
1964+
1965+
pragma[nomagic]
1966+
private predicate clearContent(NodeEx node, Content c, Configuration config) {
1967+
exists(ContentSet cs |
1968+
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
1969+
c = cs.getAReadContent() and
1970+
clearSet(node, cs, pragma[only_bind_into](config))
1971+
)
1972+
}
1973+
1974+
pragma[nomagic]
1975+
private predicate clear(NodeEx node, Ap ap, Configuration config) {
1976+
clearContent(node, ap.getHead().getContent(), config)
1977+
}
19301978

19311979
pragma[nomagic]
19321980
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1935,7 +1983,7 @@ private module Stage3 {
19351983
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
19361984
exists(state) and
19371985
exists(config) and
1938-
not clear(node, ap) and
1986+
not clear(node, ap, config) and
19391987
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
19401988
}
19411989

@@ -2363,7 +2411,7 @@ private module Stage3 {
23632411
Configuration config
23642412
) {
23652413
exists(Ap ap2, Content c |
2366-
store(node1, tc, node2, contentType, config) and
2414+
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
23672415
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
23682416
revFlowConsCand(ap2, c, ap1, config)
23692417
)
@@ -3190,7 +3238,7 @@ private module Stage4 {
31903238
Configuration config
31913239
) {
31923240
exists(Ap ap2, Content c |
3193-
store(node1, tc, node2, contentType, config) and
3241+
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
31943242
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
31953243
revFlowConsCand(ap2, c, ap1, config)
31963244
)
@@ -4202,7 +4250,7 @@ private module Subpaths {
42024250
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
42034251
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
42044252
store(n1, _, n2, _, _) or
4205-
read(n1, _, n2, _)
4253+
readSet(n1, _, n2, _)
42064254
)
42074255
}
42084256

@@ -4557,7 +4605,7 @@ private module FlowExploration {
45574605
or
45584606
exists(PartialPathNodeRev mid |
45594607
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
4560-
not clearsContentCached(node.asNode(), ap.getHead()) and
4608+
not clearsContentEx(node, ap.getHead()) and
45614609
not fullBarrier(node, config) and
45624610
not stateBarrier(node, state, config) and
45634611
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4573,7 +4621,7 @@ private module FlowExploration {
45734621
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
45744622
not fullBarrier(node, config) and
45754623
not stateBarrier(node, state, config) and
4576-
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
4624+
not clearsContentEx(node, ap.getHead().getContent()) and
45774625
if node.asNode() instanceof CastingNode
45784626
then compatibleTypes(node.getDataFlowType(), ap.getType())
45794627
else any()

0 commit comments

Comments
 (0)