Headline
CVE-2023-24818: Null Pointer dereference during fragment forwarding
RIOT-OS, an operating system that supports Internet of Things devices, contains a network stack with the ability to process 6LoWPAN frames. Prior to version 2022.10, an attacker can send a crafted frame to the device resulting in a NULL pointer dereference. During forwarding of a fragment an uninitialized entry in the reassembly buffer is used. The NULL pointer dereference triggers a hard fault exception resulting in denial of service. Version 2022.10 fixes this issue. As a workaround, disable support for fragmented IP datagrams or apply the patches manually.
Impact
RIOT-OS contains a network stack with the ability to process 6LoWPAN frames. An attacker can send a crafted frame to the device resulting in a NULL pointer dereference. During forwarding of a fragment an uninitialized entry in the reassembly buffer is used. The NULL pointer dereference triggers a hard fault exception resulting in denial of service.
Patches
- master #1, #2, #3
- 2022.10 #1, #2, #3
Workarounds
- Disabling support for fragmented IP datagrams, or
- Backport the patches listed above
For more information
If you have any questions or comments about this advisory:
- Open an issue in RIOT
- Email us at RIOT-security
Bug Details****Missing source address leads to NULL pointer dereference
NULL pointer dereference in gnrc_sixlowpan_dispatch_send due to unchecked use of return value from gnrc_netif_get_by_pid (source):
void gnrc_sixlowpan_dispatch_send(gnrc_pktsnip_t *pkt, void *context,
unsigned page)
{
(void)context;
(void)page;
assert(pkt->type == GNRC_NETTYPE_NETIF);
gnrc_netif_hdr_t *hdr = pkt->data;
if (gnrc_netif_send(gnrc_netif_get_by_pid(hdr->if_pid), pkt) < 1) {
The return value is NULL because hdr->if_pid is zero, which is defined as invalid pid.
The function is called in gnrc_sixlowpan_frag_minfwd_forward, where the netif header is build from the vrbe (source):
tmp = _netif_hdr_from_vrbe(vrbe);
...
pkt = gnrc_pkt_prepend(pkt, tmp);
gnrc_sixlowpan_dispatch_send(pkt, NULL, page);
The function is called from _forward_frag, which just passes the vrbe through, which is then called from _rbuf_add.
There the vrb is retrieved via gnrc_sixlowpan_frag_vrb_get (source):
(entry.vrb = gnrc_sixlowpan_frag_vrb_get(src, netif_hdr->src_l2addr_len,
datagram_tag)) != NULL) {
...
if (_forward_frag(pkt, sizeof(sixlowpan_frag_n_t), entry.vrb,
page) < 0) {
The problem here is that the netif_hdr->src_l2addr_len is zero and an empty vrb entry is defined as having super.src_len == 0.
This leads to the situation that gnrc_sixlowpan_frag_vrb_get returns an uninitialized vrb entry.
The same bug can be triggered via another path: gnrc_sixlowpan_frag_sfr_recv -> _forward_rfrag -> _send_frame
Cause of missing address in netif header
The netif_hdr is created by the link layer, in this case the IEEE 802.15.4 netif layer.
In _recv the function _make_netif_hdr is called to set the values in the header (source):
netif_hdr = _make_netif_hdr(mhr);
Here the source and destination addresses are retrieved and written to the netif_hdr (source):
dst_len = ieee802154_get_dst(mhr, dst, &_pan_tmp);
src_len = ieee802154_get_src(mhr, src, &_pan_tmp);
if ((dst_len < 0) || (src_len < 0)) {
DEBUG("_make_netif_hdr: unable to get addresses\n");
return NULL;
}
/* allocate space for header */
snip = gnrc_netif_hdr_build(src, (size_t)src_len, dst, (size_t)dst_len);
These functions decode the Frame Type header and if the Destination/Source Addressing Mode specifies that the address is not present a length of zero is returned.
Thus the addresses are absent from the packet forwarded to the 6LoWPAN layer.