Skip to content

Commit 00e5441

Browse files
committed
Data flow: Add consistency queries
1 parent ad54f2e commit 00e5441

3 files changed

Lines changed: 186 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import codeql_ruby.dataflow.internal.DataFlowImplConsistency::Consistency
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/**
2+
* Provides consistency queries for checking invariants in the language-specific
3+
* data-flow classes and predicates.
4+
*/
5+
6+
private import DataFlowImplSpecific::Private
7+
private import DataFlowImplSpecific::Public
8+
private import tainttracking1.TaintTrackingParameter::Private
9+
private import tainttracking1.TaintTrackingParameter::Public
10+
11+
module Consistency {
12+
private class RelevantNode extends Node {
13+
RelevantNode() {
14+
this instanceof ArgumentNode or
15+
this instanceof ParameterNode or
16+
this instanceof ReturnNode or
17+
this = getAnOutNode(_, _) or
18+
simpleLocalFlowStep(this, _) or
19+
simpleLocalFlowStep(_, this) or
20+
jumpStep(this, _) or
21+
jumpStep(_, this) or
22+
storeStep(this, _, _) or
23+
storeStep(_, _, this) or
24+
readStep(this, _, _) or
25+
readStep(_, _, this) or
26+
defaultAdditionalTaintStep(this, _) or
27+
defaultAdditionalTaintStep(_, this)
28+
}
29+
}
30+
31+
query predicate uniqueEnclosingCallable(Node n, string msg) {
32+
exists(int c |
33+
n instanceof RelevantNode and
34+
c = count(n.getEnclosingCallable()) and
35+
c != 1 and
36+
msg = "Node should have one enclosing callable but has " + c + "."
37+
)
38+
}
39+
40+
query predicate uniqueType(Node n, string msg) {
41+
exists(int c |
42+
n instanceof RelevantNode and
43+
c = count(getNodeType(n)) and
44+
c != 1 and
45+
msg = "Node should have one type but has " + c + "."
46+
)
47+
}
48+
49+
query predicate uniqueNodeLocation(Node n, string msg) {
50+
exists(int c |
51+
c =
52+
count(string filepath, int startline, int startcolumn, int endline, int endcolumn |
53+
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
54+
) and
55+
c != 1 and
56+
msg = "Node should have one location but has " + c + "."
57+
)
58+
}
59+
60+
query predicate missingLocation(string msg) {
61+
exists(int c |
62+
c =
63+
strictcount(Node n |
64+
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
65+
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
66+
)
67+
) and
68+
msg = "Nodes without location: " + c
69+
)
70+
}
71+
72+
query predicate uniqueNodeToString(Node n, string msg) {
73+
exists(int c |
74+
c = count(n.toString()) and
75+
c != 1 and
76+
msg = "Node should have one toString but has " + c + "."
77+
)
78+
}
79+
80+
query predicate missingToString(string msg) {
81+
exists(int c |
82+
c = strictcount(Node n | not exists(n.toString())) and
83+
msg = "Nodes without toString: " + c
84+
)
85+
}
86+
87+
query predicate parameterCallable(ParameterNode p, string msg) {
88+
exists(DataFlowCallable c | p.isParameterOf(c, _) and c != p.getEnclosingCallable()) and
89+
msg = "Callable mismatch for parameter."
90+
}
91+
92+
query predicate localFlowIsLocal(Node n1, Node n2, string msg) {
93+
simpleLocalFlowStep(n1, n2) and
94+
n1.getEnclosingCallable() != n2.getEnclosingCallable() and
95+
msg = "Local flow step does not preserve enclosing callable."
96+
}
97+
98+
private DataFlowType typeRepr() { result = getNodeType(_) }
99+
100+
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {
101+
t = typeRepr() and
102+
not compatibleTypes(t, t) and
103+
msg = "Type compatibility predicate is not reflexive."
104+
}
105+
106+
query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) {
107+
isUnreachableInCall(n, call) and
108+
exists(DataFlowCallable c |
109+
c = n.getEnclosingCallable() and
110+
not viableCallable(call) = c
111+
) and
112+
msg = "Call context for isUnreachableInCall is inconsistent with call graph."
113+
}
114+
115+
query predicate localCallNodes(DataFlowCall call, Node n, string msg) {
116+
(
117+
n = getAnOutNode(call, _) and
118+
msg = "OutNode and call does not share enclosing callable."
119+
or
120+
n.(ArgumentNode).argumentOf(call, _) and
121+
msg = "ArgumentNode and call does not share enclosing callable."
122+
) and
123+
n.getEnclosingCallable() != call.getEnclosingCallable()
124+
}
125+
126+
// This predicate helps the compiler forget that in some languages
127+
// it is impossible for a result of `getPreUpdateNode` to be an
128+
// instance of `PostUpdateNode`.
129+
private Node getPre(PostUpdateNode n) {
130+
result = n.getPreUpdateNode()
131+
or
132+
none()
133+
}
134+
135+
query predicate postIsNotPre(PostUpdateNode n, string msg) {
136+
getPre(n) = n and
137+
msg = "PostUpdateNode should not equal its pre-update node."
138+
}
139+
140+
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
141+
exists(int c |
142+
c = count(n.getPreUpdateNode()) and
143+
c != 1 and
144+
msg = "PostUpdateNode should have one pre-update node but has " + c + "."
145+
)
146+
}
147+
148+
query predicate uniquePostUpdate(Node n, string msg) {
149+
1 < strictcount(PostUpdateNode post | post.getPreUpdateNode() = n) and
150+
msg = "Node has multiple PostUpdateNodes."
151+
}
152+
153+
query predicate postIsInSameCallable(PostUpdateNode n, string msg) {
154+
n.getEnclosingCallable() != n.getPreUpdateNode().getEnclosingCallable() and
155+
msg = "PostUpdateNode does not share callable with its pre-update node."
156+
}
157+
158+
private predicate hasPost(Node n) { exists(PostUpdateNode post | post.getPreUpdateNode() = n) }
159+
160+
query predicate reverseRead(Node n, string msg) {
161+
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
162+
msg = "Origin of readStep is missing a PostUpdateNode."
163+
}
164+
165+
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
166+
not hasPost(n) and
167+
not isImmutableOrUnobservable(n) and
168+
msg = "ArgumentNode is missing PostUpdateNode."
169+
}
170+
171+
// This predicate helps the compiler forget that in some languages
172+
// it is impossible for a `PostUpdateNode` to be the target of
173+
// `simpleLocalFlowStep`.
174+
private predicate isPostUpdateNode(Node n) { n instanceof PostUpdateNode or none() }
175+
176+
query predicate postWithInFlow(Node n, string msg) {
177+
isPostUpdateNode(n) and
178+
simpleLocalFlowStep(_, n) and
179+
msg = "PostUpdateNode should not be the target of local flow."
180+
}
181+
}

scripts/identical-files.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
"codeql/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll",
1212
"ql/src/codeql_ruby/dataflow/internal/DataFlowImpl.qll"
1313
],
14+
"DataFlow Consistency": [
15+
"codeql/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
16+
"ql/src/codeql_ruby/dataflow/internal/DataFlowImplConsistency.qll"
17+
],
1418
"TaintTracking": [
1519
"codeql/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
1620
"ql/src/codeql_ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"

0 commit comments

Comments
 (0)