Skip to content

Commit f8dbfd9

Browse files
authored
Merge pull request #50 from CHERIoT-Platform/hlefeuvre/dns-compartment-for-pr
Isolate the DNS resolver into its own compartment.
2 parents af597ab + d18abd9 commit f8dbfd9

File tree

22 files changed

+1935
-400
lines changed

22 files changed

+1935
-400
lines changed

README.md

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ The new code in this repository is around 3% of the size of the large components
3030
Compartmentalisation
3131
--------------------
3232

33-
The initial implementation has six compartments.
33+
The initial implementation has seven compartments.
3434
Four are mostly existing third-party code with thin wrappers:
3535

3636
- The TCP/IP stack is in a compartment.
@@ -39,11 +39,12 @@ Four are mostly existing third-party code with thin wrappers:
3939
- The TLS stack is, again, mostly unmodified BearSSL code, with just some thin wrappers added around the edges.
4040
- The MQTT compartment, like the SNTP compartment, is just another consumer of the network stack (the TLS layer, specifically) and provides a simple interface for connecting to MQTT servers, publishing messages and receiving notifications of publish events.
4141

42-
These are joined by two new compartments:
42+
These are joined by three new compartments:
4343

4444
- The firewall compartment is the only thing that talks directly to the network device.
4545
It filters inbound and outbound frames.
4646
- The NetAPI compartment provides the control plane.
47+
- The DNS resolver compartment provides DNS lookup services, interfacing directly with the firewall.
4748

4849
The communication is (roughly) summarised below:
4950

@@ -56,11 +57,14 @@ graph TD
5657
TCPIP["TCP/IP"]:::ThirdParty
5758
User["User Code "]
5859
NetAPI["Network API"]
60+
DNS["DNS Resolver"]
5961
SNTP:::ThirdParty
6062
TLS:::ThirdParty
6163
MQTT:::ThirdParty
6264
DeviceDriver <-- "Network traffic" --> Network
6365
TCPIP <-- "Send and receive Ethernet frames" --> Firewall
66+
DNS <-- "Send and receive Ethernet frames" --> Firewall
67+
NetAPI -- "Perform DNS lookups" --> DNS
6468
NetAPI -- "Add and remove rules" --> Firewall
6569
TLS -- "Request network connections" --> NetAPI
6670
TLS -- "Send and receive" --> TCPIP
@@ -82,27 +86,17 @@ We expand on this capability [below](#automatic-restart-of-the-tcpip-stack).
8286
Unlike the TCP/IP stack, the TLS compartment is almost completely stateless.
8387
This makes resetting the compartment trivial, and gives strong flow isolation properties: Even if an attacker compromises the TLS compartment by sending malicious data over one connection that triggers a bug in BearSSL (unlikely), it is extraordinarily difficult for them to interfere with any other TLS connection.
8488

85-
Similarly, the firewall is controlled by the Network API compartment.
86-
The TCP/IP stack has no access to the control-plane interface for the compartment.
87-
A compromise that gets arbitrary-code execution in the network stack cannot open new firewall holes (to join a DDoS botnet such as [Mirai](https://en.wikipedia.org/wiki/Mirai_(malware)), for example).
88-
Note that there are currently some technical limitations to this, see the discussion below.
89-
The worst it can do to rest of the system is provide malicious data, but a system using TLS will have HMACs on received messages and so this is no worse than a malicious packet being injected from the network.
90-
91-
All of this is on top of the spatial and temporal safety properties that the CHERIoT platform provides at a base level.
92-
93-
**Note on the isolation of the firewall control plane.**
94-
95-
In the current implementation, the TCP/IP stack still indirectly controls which endpoints the firewall allows/disables because the Network API compartment operates with domain names, and the firewall with IPs, and the TCP/IP stack controls the translation between the two.
89+
All inbound and outbound data go through the on-device firewall, which is controlled by the Network API compartment.
90+
The TCP/IP stack has no access to the NetAPI control-plane interface.
91+
Thus, a compromise that gets arbitrary-code execution in the network stack cannot open new firewall holes (to join a DDoS botnet such as [Mirai](https://en.wikipedia.org/wiki/Mirai_(malware)), for example).
92+
The worst it can do to the rest of the system is provide malicious data, but a system using TLS will have HMACs on received messages and so this is no worse than a malicious packet being injected from the network.
9693

94+
The DNS resolver comes as a separate compartment to support this design: since the Network API compartment operates with domain names, and the firewall with IPs, the translation between the two must be done by a trusted entity.
9795
For instance, if the application tells the Network API that the only endpoint it will ever communicate with is `example.com`, the Network API will need to translate that domain name into an IP to create a firewall entry.
98-
The TCP/IP compartment is responsible for doing the translation through DNS.
99-
Thus, a compromised TCP/IP stack can spoof the DNS translation and return whichever IP address it wants to connect to, to create a corresponding firewall entry.
100-
101-
This attack scenario comes with the limitation that DNS resolution and firewall updates only happen when establishing a new connection.
102-
However, in many cases the TCP/IP stack can trigger this arbitrarily by closing the sockets opened by the application to force the application to trigger another socket open (and thus to re-establish the connection and re-translate the domain name).
96+
If this translation was done by a potentially compromised TCP/IP stack, it could spoof the DNS translation and return whichever IP address it wants to connect to, to create a corresponding malicious firewall entry.
97+
The isolated DNS resolver is trusted to perform this task independently of the TCP/IP stack.
10398

104-
Looking forward, we are planning to address this limitation by moving the DNS lookup to a separate compartment.
105-
Unfortunately, without DNSSEC, the network stack can still tamper with responses, so this will also require a firewall-layer bypass to send DNS responses to the DNS compartment instead of the network stack.
99+
This compartmentalised design comes on top of the spatial and temporal safety properties that the CHERIoT platform provides at a base level.
106100

107101
Capabilities authorise communication
108102
------------------------------------

examples/01.SNTP/xmake.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ compartment("sntp_example")
2828

2929
firmware("01.sntp_example")
3030
set_policy("build.warning", true)
31-
add_deps("TCPIP", "Firewall", "NetAPI", "SNTP", "sntp_example", "atomic8", "time_helpers", "debug")
31+
add_deps("DNS", "TCPIP", "Firewall", "NetAPI", "SNTP", "sntp_example", "atomic8", "time_helpers", "debug")
3232
-- stdio only needed for debug prints in SNTP, can be removed with --debug-sntp=n
3333
add_deps("stdio")
3434
on_load(function(target)

examples/02.HTTP/xmake.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ compartment("http_example")
2828

2929
firmware("02.http_example")
3030
set_policy("build.warning", true)
31-
add_deps("TCPIP", "Firewall", "NetAPI", "http_example", "atomic8", "debug")
31+
add_deps("DNS", "TCPIP", "Firewall", "NetAPI", "http_example", "atomic8", "debug")
3232
on_load(function(target)
3333
target:values_set("board", "$(board)")
3434
target:values_set("threads", {

examples/03.HTTPS/xmake.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ option("board")
1818

1919
compartment("https_example")
2020
add_includedirs("../../include")
21-
add_deps("freestanding", "TCPIP", "NetAPI", "TLS", "Firewall", "SNTP", "time_helpers", "debug")
21+
add_deps("freestanding", "DNS", "TCPIP", "NetAPI", "TLS", "Firewall", "SNTP", "time_helpers", "debug")
2222
add_files("https.cc")
2323
on_load(function(target)
2424
target:add('options', "IPv6")

examples/04.MQTT/xmake.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ option("board")
1818

1919
compartment("mqtt_example")
2020
add_includedirs("../../include")
21-
add_deps("freestanding", "TCPIP", "NetAPI", "TLS", "Firewall", "SNTP", "MQTT", "time_helpers", "debug")
21+
add_deps("freestanding", "DNS", "TCPIP", "NetAPI", "TLS", "Firewall", "SNTP", "MQTT", "time_helpers", "debug")
2222
-- stdio only needed for debug prints in MQTT, can be removed with --debug-mqtt=n
2323
add_deps("stdio")
2424
add_files("mqtt.cc")

examples/05.HTTP_SERVER/xmake.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ compartment("http_server_example")
2828

2929
firmware("05.http_server_example")
3030
set_policy("build.warning", true)
31-
add_deps("TCPIP", "Firewall", "NetAPI", "http_server_example", "atomic8", "debug")
31+
add_deps("DNS", "TCPIP", "Firewall", "NetAPI", "http_server_example", "atomic8", "debug")
3232
on_load(function(target)
3333
target:values_set("board", "$(board)")
3434
target:values_set("threads", {

0 commit comments

Comments
 (0)