Skip to content

Commit 3d48b23

Browse files
committed
C++: Instantiate model generation library.
1 parent 254789c commit 3d48b23

File tree

1 file changed

+388
-0
lines changed

1 file changed

+388
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,388 @@
1+
/**
2+
* Provides predicates related to capturing summary models of the Standard or a 3rd party library.
3+
*/
4+
5+
private import cpp
6+
private import semmle.code.cpp.dataflow.new.DataFlow
7+
private import semmle.code.cpp.ir.IR
8+
private import semmle.code.cpp.dataflow.ExternalFlow as ExternalFlow
9+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
10+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
11+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as DataFlowPrivate
12+
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
13+
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
14+
private import semmle.code.cpp.dataflow.new.TaintTracking
15+
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
16+
17+
module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFlow> {
18+
class Type = DataFlowPrivate::DataFlowType;
19+
20+
// Note: This also includes `this`
21+
class Parameter = DataFlow::ParameterNode;
22+
23+
class Callable = Declaration;
24+
25+
class NodeExtended extends DataFlow::Node {
26+
Callable getAsExprEnclosingCallable() { result = this.asExpr().getEnclosingDeclaration() }
27+
}
28+
29+
Parameter asParameter(NodeExtended n) { result = n }
30+
31+
Callable getEnclosingCallable(NodeExtended n) {
32+
result = n.getEnclosingCallable().asSourceCallable()
33+
}
34+
35+
Callable getAsExprEnclosingCallable(NodeExtended n) {
36+
result = n.asExpr().getEnclosingDeclaration()
37+
}
38+
39+
private predicate hasManualSummaryModel(Callable api) {
40+
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
41+
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
42+
}
43+
44+
private predicate hasManualSourceModel(Callable api) {
45+
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel())
46+
}
47+
48+
private predicate hasManualSinkModel(Callable api) {
49+
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel())
50+
}
51+
52+
private predicate relevant(Callable api) { api.fromSource() }
53+
54+
class SummaryTargetApi extends Callable {
55+
private Callable lift;
56+
57+
SummaryTargetApi() {
58+
lift = this and
59+
not hasManualSummaryModel(lift)
60+
}
61+
62+
Callable lift() { result = lift }
63+
64+
predicate isRelevant() {
65+
relevant(this) and
66+
not hasManualSummaryModel(this)
67+
}
68+
}
69+
70+
class SourceOrSinkTargetApi extends Callable {
71+
SourceOrSinkTargetApi() { relevant(this) }
72+
}
73+
74+
class SinkTargetApi extends SourceOrSinkTargetApi {
75+
SinkTargetApi() { not hasManualSinkModel(this) }
76+
}
77+
78+
class SourceTargetApi extends SourceOrSinkTargetApi {
79+
SourceTargetApi() { not hasManualSourceModel(this) }
80+
}
81+
82+
class InstanceParameterNode extends DataFlow::ParameterNode {
83+
InstanceParameterNode() {
84+
DataFlowPrivate::nodeHasInstruction(this,
85+
any(InitializeParameterInstruction i | i.hasIndex(-1)), 1)
86+
}
87+
}
88+
89+
/**
90+
* Holds if the summary generated for `c` should also apply to overrides
91+
* of `c`.
92+
*/
93+
private string isExtensible(Callable c) {
94+
if c instanceof MemberFunction then result = "true" else result = "false"
95+
}
96+
97+
/**
98+
* Gets the string representing the list of template parameters declared
99+
* by `template`.
100+
*
101+
* `template` must either be:
102+
* - An uninstantiated template, or
103+
* - A declaration that is not from a template instantiation.
104+
*/
105+
private string templateParams(Declaration template) {
106+
exists(string params |
107+
params =
108+
concat(int i |
109+
|
110+
template.getTemplateArgument(i).(TypeTemplateParameter).getName(), "," order by i
111+
)
112+
|
113+
if params = "" then result = "" else result = "<" + params + ">"
114+
)
115+
}
116+
117+
/**
118+
* Gets the string representing the list of parameters declared
119+
* by `functionTemplate`.
120+
*
121+
* `functionTemplate` must either be:
122+
* - An uninstantiated template, or
123+
* - A declaration that is not from a template instantiation.
124+
*/
125+
private string params(Function functionTemplate) {
126+
exists(string params |
127+
params =
128+
concat(int i |
129+
|
130+
ExternalFlow::getParameterTypeWithoutTemplateArguments(functionTemplate, i, true), ","
131+
order by
132+
i
133+
)
134+
|
135+
if params = "" then result = "()" else result = "(" + params + ")"
136+
)
137+
}
138+
139+
/**
140+
* Holds if the callable `c` is:
141+
* - In the namespace represented by `namespace`, and
142+
* - Has a declaring type represented by `type`, and
143+
* - Has the name `name`, and
144+
* - Has a list of parameters represented by `params`
145+
*
146+
* This is the predicate that computes the columns that it put into the MaD
147+
* row for `callable`.
148+
*/
149+
private predicate qualifiedName(
150+
Callable callable, string namespace, string type, string name, string params
151+
) {
152+
exists(
153+
Function functionTemplate, string typeWithoutTemplateArgs, string nameWithoutTemplateArgs
154+
|
155+
functionTemplate = ExternalFlow::getFullyTemplatedFunction(callable) and
156+
functionTemplate.hasQualifiedName(namespace, typeWithoutTemplateArgs, nameWithoutTemplateArgs) and
157+
nameWithoutTemplateArgs = functionTemplate.getName() and
158+
name = nameWithoutTemplateArgs + templateParams(functionTemplate) and
159+
params = params(functionTemplate)
160+
|
161+
exists(Class classTemplate |
162+
classTemplate = functionTemplate.getDeclaringType() and
163+
type = typeWithoutTemplateArgs + templateParams(classTemplate)
164+
)
165+
or
166+
not exists(functionTemplate.getDeclaringType()) and
167+
type = ""
168+
)
169+
}
170+
171+
predicate isRelevantType(Type t) { any() }
172+
173+
Type getUnderlyingContentType(DataFlow::ContentSet c) {
174+
result = c.(DataFlow::FieldContent).getField().getUnspecifiedType() or
175+
result = c.(DataFlow::UnionContent).getUnion().getUnspecifiedType()
176+
}
177+
178+
string qualifierString() { result = "Argument[-1]" }
179+
180+
private predicate parameterContentAccessImpl(Parameter p, string argument) {
181+
exists(int indirectionIndex, int argumentIndex, DataFlowPrivate::Position pos |
182+
p.isSourceParameterOf(_, pos) and
183+
pos.getArgumentIndex() = argumentIndex and
184+
argumentIndex != -1 and // handled elsewhere
185+
pos.getIndirectionIndex() = indirectionIndex
186+
|
187+
indirectionIndex = 0 and
188+
argument = "Argument[" + argumentIndex + "]"
189+
or
190+
indirectionIndex > 0 and
191+
argument = "Argument[" + DataFlow::repeatStars(indirectionIndex) + argumentIndex + "]"
192+
)
193+
}
194+
195+
string parameterAccess(Parameter p) { parameterContentAccessImpl(p, result) }
196+
197+
string parameterContentAccess(Parameter p) { parameterContentAccessImpl(p, result) }
198+
199+
bindingset[c]
200+
string paramReturnNodeAsOutput(Callable c, DataFlowPrivate::Position pos) {
201+
exists(Parameter p |
202+
p.isSourceParameterOf(c, pos) and
203+
result = parameterAccess(p)
204+
)
205+
or
206+
pos.getArgumentIndex() = -1 and
207+
result = qualifierString() and
208+
pos.getIndirectionIndex() = 1
209+
}
210+
211+
bindingset[c]
212+
string paramReturnNodeAsContentOutput(Callable c, DataFlowPrivate::ParameterPosition pos) {
213+
result = paramReturnNodeAsOutput(c, pos)
214+
}
215+
216+
pragma[nomagic]
217+
Callable returnNodeEnclosingCallable(DataFlow::Node ret) {
218+
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asSourceCallable()
219+
}
220+
221+
/** Holds if this instance access is to an enclosing instance of type `t`. */
222+
pragma[nomagic]
223+
private predicate isEnclosingInstanceAccess(DataFlowPrivate::ReturnNode n, Class t) {
224+
n.getKind().isIndirectReturn(-1) and
225+
t = n.getType().stripType() and
226+
t != n.getEnclosingCallable().asSourceCallable().(Function).getDeclaringType()
227+
}
228+
229+
pragma[nomagic]
230+
predicate isOwnInstanceAccessNode(DataFlowPrivate::ReturnNode node) {
231+
node.getKind().isIndirectReturn(-1) and
232+
not isEnclosingInstanceAccess(node, _)
233+
}
234+
235+
predicate sinkModelSanitizer(DataFlow::Node node) { none() }
236+
237+
predicate apiSource(DataFlow::Node source) {
238+
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1)
239+
or
240+
source instanceof DataFlow::ParameterNode
241+
}
242+
243+
string getInputArgument(DataFlow::Node source) {
244+
exists(DataFlowPrivate::Position pos, int argumentIndex, int indirectionIndex |
245+
source.(DataFlow::ParameterNode).isParameterOf(_, pos) and
246+
argumentIndex = pos.getArgumentIndex() and
247+
indirectionIndex = pos.getIndirectionIndex() and
248+
result = "Argument[" + DataFlow::repeatStars(indirectionIndex) + argumentIndex + "]"
249+
)
250+
or
251+
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1) and
252+
result = qualifierString()
253+
}
254+
255+
string getReturnValueString(DataFlowPrivate::ReturnKind k) {
256+
k.isNormalReturn() and
257+
exists(int indirectionIndex | indirectionIndex = k.getIndirectionIndex() |
258+
indirectionIndex = 0 and
259+
result = "ReturnValue"
260+
or
261+
indirectionIndex > 0 and
262+
result = "ReturnValue[" + DataFlow::repeatStars(indirectionIndex) + "]"
263+
)
264+
}
265+
266+
predicate irrelevantSourceSinkApi(Callable source, SourceTargetApi api) { none() }
267+
268+
bindingset[kind]
269+
predicate isRelevantSourceKind(string kind) { any() }
270+
271+
bindingset[kind]
272+
predicate isRelevantSinkKind(string kind) { any() }
273+
274+
predicate containerContent(DataFlow::ContentSet cs) { cs instanceof DataFlow::ElementContent }
275+
276+
predicate isAdditionalContentFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
277+
TaintTracking::defaultAdditionalTaintStep(node1, node2, _) and
278+
not exists(DataFlow::Content f |
279+
DataFlowPrivate::readStep(node1, f, node2) and containerContent(f)
280+
)
281+
}
282+
283+
predicate isField(DataFlow::ContentSet cs) {
284+
exists(DataFlow::Content c | cs.isSingleton(c) |
285+
c instanceof DataFlow::FieldContent or
286+
c instanceof DataFlow::UnionContent
287+
)
288+
}
289+
290+
predicate isCallback(DataFlow::ContentSet c) { none() }
291+
292+
string getSyntheticName(DataFlow::ContentSet c) {
293+
exists(Field f |
294+
not f.isPublic() and
295+
f = c.(DataFlow::FieldContent).getField() and
296+
result = f.getName()
297+
)
298+
}
299+
300+
string printContent(DataFlow::ContentSet c) {
301+
exists(int indirectionIndex, string name, string kind |
302+
exists(DataFlow::UnionContent uc |
303+
c.isSingleton(uc) and
304+
name = uc.getUnion().getName() and
305+
indirectionIndex = uc.getIndirectionIndex() and
306+
// Note: We don't actually support the union string in MaD, but we should do that eventually
307+
kind = "Union["
308+
)
309+
or
310+
exists(DataFlow::FieldContent fc |
311+
c.isSingleton(fc) and
312+
name = fc.getField().getName() and
313+
indirectionIndex = fc.getIndirectionIndex() and
314+
kind = "Field["
315+
)
316+
|
317+
result = kind + DataFlow::repeatStars(indirectionIndex) + name + "]"
318+
)
319+
or
320+
exists(DataFlow::ElementContent ec |
321+
c.isSingleton(ec) and
322+
result = "Element[" + ec.getIndirectionIndex() + "]"
323+
)
324+
}
325+
326+
/**
327+
* Holds if `f` is a "private" function.
328+
*
329+
* A "private" function does not contribute any models as it is assumed
330+
* to be an implementation detail of some other "public" function for which
331+
* we will generate a summary.
332+
*/
333+
private predicate isPrivate(Function f) {
334+
f.getNamespace().getParentNamespace*().isAnonymous()
335+
or
336+
f.(MemberFunction).isPrivate()
337+
or
338+
f.isStatic()
339+
}
340+
341+
predicate isUninterestingForDataFlowModels(Callable api) {
342+
// Note: This also makes all global/static-local variables
343+
// uninteresting (which is good!)
344+
not api.(Function).hasDefinition()
345+
or
346+
isPrivate(api)
347+
or
348+
api instanceof Destructor
349+
or
350+
api = any(LambdaExpression lambda).getLambdaFunction()
351+
or
352+
api.isFromUninstantiatedTemplate(_)
353+
}
354+
355+
predicate isUninterestingForHeuristicDataFlowModels(Callable api) {
356+
isUninterestingForDataFlowModels(api)
357+
}
358+
359+
string partialModelRow(Callable api, int i) {
360+
i = 0 and qualifiedName(api, result, _, _, _) // namespace
361+
or
362+
i = 1 and qualifiedName(api, _, result, _, _) // type
363+
or
364+
i = 2 and result = isExtensible(api) // extensible
365+
or
366+
i = 3 and qualifiedName(api, _, _, result, _) // name
367+
or
368+
i = 4 and qualifiedName(api, _, _, _, result) // parameters
369+
or
370+
i = 5 and result = "" and exists(api) // ext
371+
}
372+
373+
string partialNeutralModelRow(Callable api, int i) {
374+
i = 0 and qualifiedName(api, result, _, _, _) // namespace
375+
or
376+
i = 1 and qualifiedName(api, _, result, _, _) // type
377+
or
378+
i = 2 and qualifiedName(api, _, _, result, _) // name
379+
or
380+
i = 3 and qualifiedName(api, _, _, _, result) // parameters
381+
}
382+
383+
predicate sourceNode = ExternalFlow::sourceNode/2;
384+
385+
predicate sinkNode = ExternalFlow::sinkNode/2;
386+
}
387+
388+
import MakeModelGenerator<Location, CppDataFlow, CppTaintTracking, ModelGeneratorInput>

0 commit comments

Comments
 (0)