Skip to content

Commit f7844cd

Browse files
authored
Merge pull request #24 from CHERIoT-Platform/hlefeuvre/tcpip-crash-return-values-in-netapi
Better handle TCP/IP stack crashes in the NETAPI compartment.
2 parents ef3fe19 + 515e006 commit f7844cd

File tree

3 files changed

+86
-37
lines changed

3 files changed

+86
-37
lines changed

lib/netapi/NetAPI.cc

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,37 @@ SObj network_socket_connect_tcp(Timeout *timeout,
5555
Debug::log("Host capability does not authorise a TCP connection");
5656
return nullptr;
5757
}
58+
59+
NetworkAddress address{NetworkAddress::AddressKindInvalid};
60+
CHERI::Capability addressPtr = &address;
61+
addressPtr.permissions() &= {CHERI::Permission::Store};
5862
firewall_permit_dns();
59-
NetworkAddress address = network_host_resolve(host->hostname, UseIPv6);
63+
int ret = network_host_resolve(host->hostname, UseIPv6, addressPtr);
6064
firewall_permit_dns(false);
61-
if (address.kind == NetworkAddress::AddressKindInvalid)
65+
if ((ret < 0) || (address.kind == NetworkAddress::AddressKindInvalid))
6266
{
6367
Debug::log("Failed to resolve host");
6468
return nullptr;
6569
}
66-
bool isIPv6 = address.kind == NetworkAddress::AddressKindIPv6;
67-
auto sealedSocket = network_socket_create_and_bind(
70+
bool isIPv6 = address.kind == NetworkAddress::AddressKindIPv6;
71+
72+
CHERI::Capability sealedSocket = network_socket_create_and_bind(
6873
timeout, mallocCapability, isIPv6, ConnectionTypeTCP);
69-
auto kind = network_socket_kind(sealedSocket);
74+
if (!sealedSocket.is_valid())
75+
{
76+
Debug::log("Failed to create socket");
77+
return nullptr;
78+
}
79+
80+
SocketKind kind;
81+
CHERI::Capability kindPtr = &kind;
82+
kindPtr.permissions() &= {CHERI::Permission::Store};
83+
if (network_socket_kind(sealedSocket, kindPtr) < 0)
84+
{
85+
Debug::log("Failed to retrieve socket kind");
86+
return nullptr;
87+
}
88+
7089
// FIXME: IPv6
7190
if (isIPv6)
7291
{
@@ -78,10 +97,13 @@ SObj network_socket_connect_tcp(Timeout *timeout,
7897
firewall_add_tcpipv4_endpoint(
7998
address.ipv4, kind.localPort, ntohs(host->port));
8099
}
100+
81101
if (network_socket_connect_tcp_internal(
82102
timeout, sealedSocket, address, host->port) != 0)
83103
{
84104
Timeout t{UnlimitedTimeout};
105+
// We pass an unlimited timeout, so this cannot fail in any
106+
// actionable manner. Don't check the return value.
85107
network_socket_close(&t, mallocCapability, sealedSocket);
86108
timeout->elapse(t.elapsed);
87109
if (isIPv6)
@@ -118,7 +140,14 @@ NetworkAddress network_socket_udp_authorise_host(Timeout *timeout,
118140
Debug::log("Host capability does not authorise a UDP connection");
119141
return address;
120142
}
121-
auto kind = network_socket_kind(socket);
143+
144+
SocketKind kind;
145+
CHERI::Capability kindPtr = &kind;
146+
kindPtr.permissions() &= {CHERI::Permission::Store};
147+
// No need to check the return value here, potential errors will be
148+
// detected in the switch.
149+
network_socket_kind(socket, kindPtr);
150+
122151
bool isIPv6 = false;
123152
switch (kind.protocol)
124153
{
@@ -133,10 +162,13 @@ NetworkAddress network_socket_udp_authorise_host(Timeout *timeout,
133162
isIPv6 = true;
134163
break;
135164
}
165+
166+
CHERI::Capability addressPtr = &address;
167+
addressPtr.permissions() &= {CHERI::Permission::Store};
136168
firewall_permit_dns();
137-
address = network_host_resolve(host->hostname, UseIPv6);
169+
int ret = network_host_resolve(host->hostname, UseIPv6, addressPtr);
138170
firewall_permit_dns(false);
139-
if (address.kind == NetworkAddress::AddressKindInvalid)
171+
if ((ret < 0) || (address.kind == NetworkAddress::AddressKindInvalid))
140172
{
141173
Debug::log("Failed to resolve host");
142174
return address;
@@ -146,6 +178,7 @@ NetworkAddress network_socket_udp_authorise_host(Timeout *timeout,
146178
Debug::log("Host address does not match socket type");
147179
return address;
148180
}
181+
149182
if (isIPv6)
150183
{
151184
firewall_add_udpipv6_endpoint(
@@ -161,6 +194,7 @@ NetworkAddress network_socket_udp_authorise_host(Timeout *timeout,
161194
firewall_add_udpipv4_endpoint(
162195
address.ipv4, kind.localPort, ntohs(host->port));
163196
}
197+
164198
return address;
165199
}
166200

lib/tcpip/network-internal.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@
1717
* Resolve a host name to an IPv4 or IPv6 address. If `useIPv6` is true, then
1818
* this will first attempt to find a IPv6 address and fall back to IPv4 if none
1919
* is found.
20+
*
21+
* The result of the resolve is stored in `outAddress`.
22+
*
23+
* This returns zero for success, or a negative value on error.
2024
*/
21-
NetworkAddress __cheri_compartment("TCPIP")
22-
network_host_resolve(const char *hostname, bool useIPv6);
25+
__cheri_compartment("TCPIP") int network_host_resolve(
26+
const char *hostname,
27+
bool useIPv6,
28+
NetworkAddress *outAddress);
2329

2430
/**
2531
* Create a socket and bind it to the given address. The socket will be
@@ -72,6 +78,9 @@ struct SocketKind
7278
};
7379

7480
/**
75-
* Returns information about the given socket.
81+
* Returns information about the given socket in `kind`.
82+
*
83+
* This returns zero for success, or a negative value on error.
7684
*/
77-
SocketKind __cheri_compartment("TCPIP") network_socket_kind(SObj socket);
85+
int __cheri_compartment("TCPIP")
86+
network_socket_kind(SObj socket, SocketKind *kind);

lib/tcpip/network_wrapper.cc

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,8 @@ namespace
214214
* will favour IPv6 addresses, but can still return IPv4 addresses if no
215215
* IPv6 address is available.
216216
*/
217-
NetworkAddress host_resolve(const char *hostname, bool useIPv6 = UseIPv6)
217+
int
218+
host_resolve(const char *hostname, bool useIPv6, NetworkAddress *address)
218219
{
219220
struct AddrinfoHints hints;
220221
hints.family = useIPv6 ? FREERTOS_AF_INET6 : FREERTOS_AF_INET;
@@ -229,31 +230,31 @@ namespace
229230
// Try with IPv4 if the lookup failed with IPv6
230231
if (useIPv6)
231232
{
232-
return host_resolve(hostname, false);
233+
return host_resolve(hostname, false, address);
233234
}
234235
Debug::log("DNS request returned: {}", ret);
235-
return {0, NetworkAddress::AddressKindInvalid};
236+
address->kind = NetworkAddress::AddressKindInvalid;
237+
address->ipv4 = 0;
238+
return ret;
236239
}
237240

238-
NetworkAddress address;
239-
bool isIPv6 = false;
241+
bool isIPv6 = false;
240242
for (freertos_addrinfo *r = results; r != nullptr; r = r->ai_next)
241243
{
242244
Debug::log("Canonical name: {}", r->ai_canonname);
243245
if (r->ai_family == FREERTOS_AF_INET6)
244246
{
245247
memcpy(
246-
address.ipv6, r->ai_addr->sin_address.xIP_IPv6.ucBytes, 16);
247-
address.kind = NetworkAddress::AddressKindIPv6;
248+
address->ipv6, r->ai_addr->sin_address.xIP_IPv6.ucBytes, 16);
249+
address->kind = NetworkAddress::AddressKindIPv6;
248250
Debug::log("Got IPv6 address");
249251
}
250252
else
251253
{
252-
address.ipv4 = r->ai_addr->sin_address.ulIP_IPv4;
253-
address.kind = NetworkAddress::AddressKindIPv4;
254-
Debug::log("Got IPv4 address");
254+
address->ipv4 = r->ai_addr->sin_address.ulIP_IPv4;
255+
address->kind = NetworkAddress::AddressKindIPv4;
255256
Debug::log(
256-
"Got address: {}.{}.{}.{}",
257+
"Got IPv4 address: {}.{}.{}.{}",
257258
static_cast<int>(r->ai_addr->sin_address.ulIP_IPv4) & 0xff,
258259
static_cast<int>(r->ai_addr->sin_address.ulIP_IPv4) >> 8 &
259260
0xff,
@@ -265,7 +266,7 @@ namespace
265266
}
266267

267268
FreeRTOS_freeaddrinfo(results);
268-
return address;
269+
return 0;
269270
}
270271

271272
/**
@@ -422,9 +423,11 @@ namespace
422423
}
423424
} // namespace
424425

425-
NetworkAddress network_host_resolve(const char *hostname, bool useIPv6)
426+
int network_host_resolve(const char *hostname,
427+
bool useIPv6,
428+
NetworkAddress *address)
426429
{
427-
return host_resolve(hostname, useIPv6);
430+
return host_resolve(hostname, useIPv6, address);
428431
}
429432

430433
SObj network_socket_create_and_bind(Timeout *timeout,
@@ -959,27 +962,30 @@ ssize_t network_socket_send_to(Timeout *timeout,
959962
socket);
960963
}
961964

962-
SocketKind network_socket_kind(SObj socket)
965+
int network_socket_kind(SObj socket, SocketKind *kind)
963966
{
964-
SocketKind kind = {SocketKind::Invalid, 0};
965-
with_sealed_socket(
967+
kind->protocol = SocketKind::Invalid;
968+
kind->localPort = 0;
969+
970+
int ret = with_sealed_socket(
966971
[&](SealedSocket *socket) {
967972
if (socket->socket->ucProtocol == FREERTOS_IPPROTO_TCP)
968973
{
969-
kind.protocol = socket->socket->bits.bIsIPv6
970-
? SocketKind::TCPIPv6
971-
: SocketKind::TCPIPv4;
974+
kind->protocol = socket->socket->bits.bIsIPv6
975+
? SocketKind::TCPIPv6
976+
: SocketKind::TCPIPv4;
972977
}
973978
else
974979
{
975-
kind.protocol = socket->socket->bits.bIsIPv6
976-
? SocketKind::UDPIPv6
977-
: SocketKind::UDPIPv4;
980+
kind->protocol = socket->socket->bits.bIsIPv6
981+
? SocketKind::UDPIPv6
982+
: SocketKind::UDPIPv4;
978983
}
979-
kind.localPort = listGET_LIST_ITEM_VALUE(
984+
kind->localPort = listGET_LIST_ITEM_VALUE(
980985
(&((socket->socket)->xBoundSocketListItem)));
981986
return 0;
982987
},
983988
socket);
984-
return kind;
989+
990+
return ret;
985991
}

0 commit comments

Comments
 (0)