Tor · Report #3709605
Conflux-queued zero-length RELAY_END triggers heap out-of-bounds read
How it was found
Summary
A zero-length RELAY_END cell can trigger a heap out-of-bounds read when the cell is copied through Conflux out-of-order delivery and then processed on a non-open AP stream.
Tor explicitly allows zero-length RELAY_END cells by treating them as END_STREAM_REASON_MISC, but connection_ap_process_end_not_open() reads msg->body[0] before checking msg->length.
This is normally masked by relay-cell backing storage. Conflux out-of-order queuing copies messages into exact-size heap allocations using relay_msg_copy(). For msg->length == 0, the copied msg->body points immediately after the allocation, and the unguarded get_uint8(msg->body) becomes a true heap OOB read.
Affected Code
src/core/or/relay.c:846
int reason = get_uint8(msg->body);
The length check occurs later:
if (msg->length == 0) {
reason = END_STREAM_REASON_MISC;
}
src/core/or/conflux.c:923
c_msg->msg = relay_msg_copy(msg);
src/core/or/relay_msg.c:71
void *alloc = tor_malloc_zero(sizeof(relay_msg_t) + msg->length);
Proof of Concept
I added a local ASan regression PoC as a patch to this checkout. The relevant patched files are:
src/test/test_relaycell.c- Test name:
relaycell/end_cell_conflux_copy_oob
{F5843197} contains the test_relaycell_end_cell_conflux_copy_oob() test and its copy_msg_through_conflux_ooo() helper.
The PoC:
- Builds a zero-length
RELAY_ENDmessage for a non-open AP stream. - Sends it through Tor's actual
conflux_process_relay_msg()out-of-order queue. - Dequeues the exact heap-backed
relay_msg_tproduced byrelay_msg_copy(). - Simulates Conflux ordered delivery into
connection_edge_process_relay_cell(). - ASan reports a heap-buffer-overflow at
connection_ap_process_end_not_open().
Reproduction
From a clean Tor checkout with this PoC patch applied:
./autogen.sh
CC=clang \
CFLAGS='-O0 -g -fsanitize=address -fno-omit-frame-pointer' \
LDFLAGS='-fsanitize=address' \
./configure --disable-asciidoc --disable-manpage --disable-html-manual
make micro-revision.i
make -j"$(nproc)" src/test/test
ASAN_OPTIONS='abort_on_error=1:halt_on_error=1:detect_leaks=0:symbolize=1' \
./src/test/test relaycell/end_cell_conflux_copy_oob
In my environment I also needed to point configure at Homebrew OpenSSL:
PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig \
CPPFLAGS='-I/home/linuxbrew/.linuxbrew/include' \
LDFLAGS='-fsanitize=address -L/home/linuxbrew/.linuxbrew/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/lib' \
./configure --with-openssl-dir=/home/linuxbrew/.linuxbrew \
--disable-asciidoc --disable-manpage --disable-html-manual
ASan Evidence
The PoC crashes with:
ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 1
#0 get_uint8 src/lib/arch/bytes.h:25
#1 connection_ap_process_end_not_open src/core/or/relay.c:846
#2 connection_edge_process_relay_cell_not_open src/core/or/relay.c:1402
#3 connection_edge_process_ordered_relay_cell src/core/or/relay.c:2168
#4 connection_edge_process_relay_cell src/core/or/relay.c:2099
#5 test_relaycell_end_cell_conflux_copy_oob src/test/test_relaycell.c:1136
allocated by thread T0 here:
#3 relay_msg_copy src/core/or/relay_msg.c:71
#4 conflux_process_relay_msg src/core/or/conflux.c:923
#5 copy_msg_through_conflux_ooo src/test/test_relaycell.c:214
0 bytes after 16-byte region
Suggested Fix
Read the reason byte only when one is present:
int reason = msg->length > 0 ? get_uint8(msg->body)
: END_STREAM_REASON_MISC;
Impact
An attacker who can cause a zero-length RELAY_END to be queued out-of-order on a Conflux circuit can trigger a remote heap OOB read in Tor's relay-cell handling path. In ASan or hardened builds this is a reliable process crash. In non-ASan builds, this remains memory-unsafe behavior and reads from heap-adjacent memory.
The strongest reachable case is a non-open AP stream, such as a stream still in AP_CONN_STATE_CONNECT_WAIT, receiving an empty RELAY_END from the exit side after Conflux has copied the cell through the out-of-order queue.
Vector: CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
Justification:
AV:N: the malformed relay cell can be delivered over the Tor network.AC:H: exploitation requires a linked Conflux pair, an out-of-order sequence gap, and a non-open AP stream state such asAP_CONN_STATE_CONNECT_WAIT.PR:N: the attacker does not need privileges on the target client; they act as a relay/exit capable of sending relay cells on the circuit.UI:N: after the circuit and stream exist, no additional user interaction is required to send the malformedRELAY_END.S:U: the impact is within the vulnerable Tor process.C:N: no direct information disclosure primitive is demonstrated.I:N: the OOB byte is overwritten withEND_STREAM_REASON_MISCfor zero-length messages before meaningful reason handling.A:H: ASan/hardened builds reliably abort the Tor process on the heap OOB read.