Skip to content

Commit 11b5114

Browse files
committed
Create chrome libraries
1 parent 8a48429 commit 11b5114

16 files changed

+1909
-0
lines changed

Diff for: CodeQL_Queries/cpp/Chrome/README.md

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Code QL library for Chrome
2+
3+
This repository contains various [CodeQL](https://codeql.com) libraries for [Chromium](https://chromium.googlesource.com/chromium/src.git). In order to use it, follow the instructions to install the [CodeQL plugin in eclipse](https://help.semmle.com/ql-for-eclipse/Content/WebHelp/installation.html) and then import this repository as an eclipse project.
4+
5+
## Building snapshot
6+
7+
As the Chromium source code is huge. In order to use CodeQL with it, you are likely to need to build your own Chromium snapshot and restrict it to a specific target, instead of building and running CodeQL on the whole of Chromium. This can be achieved by a two stage build. For example, if the directory of interest is `content/browser` (e.g. when researching Chromium IPC), then first build the entire Chromium. Next, remove all the build artifacts (*.o, *.so, *.a) in the `src/out/<target>/obj/content/browser/` directory (including subdirectories) and rebuild with CodeQL, following the instructions [here](https://help.semmle.com/codeql/codeql-cli.html). This should result in a usable size snapshot. Note, however, that building with CodeQL CLI is a memory intensive process and even a restricted snapshot would take up a huge amount of RAM (e.g. `content/browser` requires at least 50-60GB of RAM to build) and I'd recommended building it in a VM in the cloud.
8+
9+
## Overview of various libraries
10+
11+
The libraries in this repository are organized as follows:
12+
13+
### `commons.qll`:
14+
15+
Mostly contain general enchancement to the standard QL library and some Chromium specific, but still general material. For example, because the operators `->` and `=` are often overloaded in Chrome, this somehow upsets the usual `getQualifier` and `Assignment` in QL, so two general methods, `getQualifier` and `GeneralAssignment` are implemented to take these into account. Another useful predicates are `constructionCall` and `polyConstructionCall`, which identify all the constructor calls, as well as constructions via `make_unique` and `MakeRefCounted` (the former works fine in code search, but not the later, but neither will work on vanilla QL (you just ended inside the standard library))
16+
17+
### `collections.qll`:
18+
19+
Generally deals with `std::map`, `std::vector` etc. I use some heuristics there because there are just too many different types of containers and it is likely to miss out some if I add them manually. The library provides methods that get the component types of a container and also function calls that set/reset components in a container. A set/reset method call (e.g. push_back/erase/clear etc.) are useful as they are needed to identify when raw pointers might get remove and when managed pointers may get reset (which will cause the underlying object to be deleted and may cause a UaF somewhere else) Many bugs are actually related to pointers/managed pointers stored in containers.
20+
21+
### `callbacks.qll`:
22+
23+
The is a very useful library. It provides utilities to track the pointer types that are stored inside a callback, both retained and unretained. It uses dataflow in `callback_tracking.qll` to do this and can track through callback fields and multiple callbacks, e.g.
24+
25+
```c
26+
A* a;
27+
...
28+
assignCallback(base::BindOnce(&foo, Unretained(a)));
29+
30+
31+
void assignCallback(Callback callback) {
32+
callback_ = std::move(callback);
33+
}
34+
35+
...
36+
void bar() {
37+
x = base::BindOnce(&foo2, std::move(callback_)); //<-- x unretains type A via the assignCallback call.
38+
}
39+
```
40+
41+
I normally use this as a look up during investigation to see whether a particular callback is dangerous or not.
42+
43+
### `callback_tracking.qll`
44+
45+
Only used by `callbacks.qll` to track the types stored in callbacks.
46+
47+
### `bindings.qll`
48+
49+
Use for modelling mojom interface.
50+
51+
## `pointers`:
52+
53+
QL libraries for managed and raw pointers.
54+
55+
## `object_lifetime`:
56+
57+
### `lifetime_management.qll`:
58+
59+
QL library that models various clean up logic in Chrome. I haven't got round to implement too much code there yet.
60+
61+
`obj_lifetime.qll`:
62+
63+
Mostly contain classes that are long living, e.g. BrowserContext, Singleton and the objects that they manage. Mostly use to exclude raw pointer results as these are not likely to be destroyed.

Diff for: CodeQL_Queries/cpp/Chrome/bindings.qll

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import cpp
2+
import common
3+
4+
/**
5+
* Library for mojo bindings.
6+
*/
7+
8+
class StrongBinding extends ClassTemplateInstantiation {
9+
StrongBinding() {
10+
getName().matches("StrongBinding%")
11+
}
12+
13+
Type getBindingType() {
14+
result = this.getTemplateArgument(0).stripType()
15+
}
16+
}
17+
18+
class Binding extends ClassTemplateInstantiation {
19+
Binding() {
20+
getName().matches("Binding<%")
21+
}
22+
23+
Type getBindingType() {
24+
result = this.getTemplateArgument(0).stripType()
25+
}
26+
}
27+
28+
29+
class MojoReceiver extends ClassTemplateInstantiation {
30+
MojoReceiver() {
31+
getQualifiedName().matches("%mojo::Receiver<%")
32+
}
33+
34+
Type getBindingType() {
35+
result = this.getTemplateArgument(0).stripType()
36+
}
37+
}
38+
39+
class InterfaceBinding extends Class {
40+
FunctionCall addBinding;
41+
42+
InterfaceBinding() {
43+
addBinding.getTarget().hasName("AddBinding") and
44+
this = generalStripType(addBinding.getArgument(0).getAChild*().getType())
45+
}
46+
47+
FunctionCall getABinding() {
48+
result = addBinding
49+
}
50+
}
51+
52+
class InterfacePtr extends ClassTemplateInstantiation {
53+
InterfacePtr() {
54+
stripType().getName().matches("InterfacePtr<%") or
55+
stripType().getName().matches("InterfacePtrInfo<%")
56+
}
57+
58+
Type getInterfaceType() {
59+
result = getTemplateArgument(0)
60+
}
61+
62+
Type getInterfacePtrType() {
63+
exists(string s | s = getInterfaceType().getName() + "Ptr" and
64+
result.getName() = s
65+
)
66+
}
67+
}
68+
69+
class SetConnectionErrorHandler extends Function {
70+
SetConnectionErrorHandler() {
71+
getName() = "set_connection_error_handler" or
72+
getName() = "set_connection_error_with_reason_handler"
73+
}
74+
}
75+
76+
/**
77+
* `StructPtr` usually use for transporting data in IPC.
78+
*/
79+
class StructPtr extends Class {
80+
StructPtr() {
81+
getName().matches("StructPtr<%") or
82+
getName().matches("InlinedStructPtr<%")
83+
}
84+
85+
Type getStructType() {
86+
result = getTemplateArgument(0)
87+
}
88+
}
89+
90+
Type stripStructPtrType(Type c) {
91+
(
92+
c.getName().matches("vector<%") and
93+
result = stripStructPtrType(c.(Class).getTemplateArgument(0))
94+
) or
95+
exists(StructPtr t | t = c.stripType() and
96+
result = t.getStructType().stripType()
97+
) or
98+
result = c.stripType()
99+
}

Diff for: CodeQL_Queries/cpp/Chrome/callback_tracking.qll

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

0 commit comments

Comments
 (0)