-
Notifications
You must be signed in to change notification settings - Fork 249
/
Copy pathcallback_tracking.qll
137 lines (127 loc) · 4.02 KB
/
callback_tracking.qll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import cpp
import common
import bindings
import field
import callbacks
/**
* Dataflow library for tracking unretained or retained types in a callback.
*/
/**
* An assignment to a callback field.
*/
predicate isCallbackFieldSink(DataFlow::Node sink) {
exists(Field f | sink.asExpr() = generalAssignValue(f))
}
/**
* Running of a callback.
*/
predicate runCallbackSink(DataFlow::Node sink) {
exists(RunCallback cb | cb.getCallback() = sink.asExpr())
}
/**
* An expression that posts a callback to a task runner.
*/
predicate postTaskSink(DataFlow::Node sink) {
exists(FunctionCall postTask | postTask.getTarget().getName().matches("PostTask%") or
postTask.getTarget().getName() = "PostDelayedTask" |
postTask.getAnArgument() = sink.asExpr()
)
}
/**
* Callback gets passed inside an interface pointer function. The idea is that such a
* callback may then be called from the renderer. (A bit like
* https://bugs.chromium.org/p/project-zero/issues/detail?id=1755
* )
*/
predicate interfacePtrCallSink(DataFlow::Node sink) {
exists(FunctionCall mojom, InterfacePtr iPtr, Function interfaceFunc |
overrides*(mojom.getTarget(), interfaceFunc) and
interfaceFunc.getDeclaringType() = iPtr.getInterfaceType() and
sink.asExpr() = mojom.getAnArgument()
) or
exists(BindCall bc, InterfacePtr iPtr, Function interfaceFunc |
overrides*(bc.getFunction(), interfaceFunc) and interfaceFunc.getDeclaringType() = iPtr.getInterfaceType() and
sink.asExpr() = bc.getAnArgument() and
sink.asExpr() != bc.getArgument(0)
)
}
/**
* Callback that then binds to another callback as an argument.
*/
predicate callbackArgSink(DataFlow::Node sink) {
exists(GeneralCallback cb | cb.getACallbackArg() = sink.asExpr())
}
class CallbackConfig extends DataFlow::Configuration {
CallbackConfig() {
this = "callbackconfig"
}
override predicate isSource(DataFlow::Node source) {
(
exists(GeneralCallback fc |
source.asExpr() = fc
)
or
exists(CallbackField f | source.asExpr() = f.getAnAccess())
)
and
not source.asExpr().getFile().getBaseName() = "bind.h" and
not source.asExpr().getFile().getBaseName() = "callback_helpers.h"// and
}
override predicate isSink(DataFlow::Node sink) {
(
isCallbackFieldSink(sink)
or
runCallbackSink(sink)
or
postTaskSink(sink)
or
interfacePtrCallSink(sink)
or
callbackArgSink(sink)
) and
(
//Exclude sinks that are in uninteresting files.
not sink.asExpr().getFile().getBaseName() = "bind_internal.h" and
not sink.asExpr().getFile().getBaseName() = "tuple" and
not sink.asExpr().getFile().getBaseName() = "memory" and
not sink.asExpr().getFile().getAbsolutePath().matches("%/libc++/%") and
not sink.asExpr().getFile().getBaseName() = "bind.h" and
not sink.asExpr().getFile().getBaseName() = "binding_state.h" and
not sink.asExpr().getFile().getBaseName() = "interface_endpoint_client.h" and
not sink.asExpr().getFile().getBaseName() = "associated_interface_registry.h" and
not sink.asExpr().getFile().getBaseName() = "callback_helpers.h" and
not sink.asExpr().getFile().getBaseName() = "callback_list.h" and
sink.asExpr().fromSource()
)
}
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
callbackStep(node1, node2) or
collectionsEdge(node1, node2) or
getEdge(node1, node2) or
generalAssignEdge(node1, node2) or
exists(Parameter p | p = node1.asParameter() and
node2.asExpr() = p.getAnAccess()
) or
copyConstructorEdge(node1, node2)
or
pointerTransferEdge(node1, node2)
or
adaptCallbackEdge(node1, node2)
or
callbackWrapperEdge(node1, node2)
or
callbackToBindEdge(node1, node2)
or
polymorphicCallEdge(node1, node2)
or
passEdge(node1, node2)
or
ownedEdge(node1, node2)
or
retainedRefEdge(node1, node2)
or
unretainedEdge(node1, node2)
or
forRangeEdge(node1, node2)
}
}