Boost _ Firedancer v0.1 33669 - [Blockchain_DLT - Medium] fd_quic_process_packet out of bounds read
Submitted on Fri Jul 26 2024 00:53:15 GMT-0400 (Atlantic Standard Time) by @gln for Boost | Firedancer v0.1
Report ID: #33669
Report type: Blockchain/DLT
Report severity: Medium
Target: https://github.com/firedancer-io/firedancer/tree/e60d9a6206efaceac65a5a2c3a9e387a79d1d096
Impacts:
Process to process RCE between sandboxed tiles
Description
Brief/Intro
QUIC tile fails to validate data received from Net tile.
If udp packet length is too short, out of bounds read might be triggered.
Vulnerability Details
Lets look at the code https://github.com/firedancer-io/firedancer/blob/main/src/waltz/quic/fd_quic.c#L2782
void
fd_quic_process_packet( fd_quic_t * quic,
uchar * data,
ulong data_sz ) {
fd_quic_state_t * state = fd_quic_get_state( quic );
ulong rc = 0;
/* holds the remainder of the packet*/
uchar * cur_ptr = data;
ulong cur_sz = data_sz;
if( FD_UNLIKELY( data_sz > 0xffffu ) ) {
/* sanity check */
return;
}
fd_quic_pkt_t pkt = { .datagram_sz = (uint)data_sz };
pkt.rcv_time = state->now;
rc = fd_quic_decode_eth( pkt.eth, cur_ptr, cur_sz );
if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
/* TODO count failure, log-debug failure */
return;
}
if( FD_UNLIKELY( pkt.eth->net_type != FD_ETH_HDR_TYPE_IP ) ) {
FD_DEBUG( FD_LOG_DEBUG(( "Invalid ethertype: %4.4x", pkt.eth->net_type )) );
return;
}
cur_ptr += rc;
cur_sz -= rc;
rc = fd_quic_decode_ip4( pkt.ip4, cur_ptr, cur_sz );
if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
/* TODO count failure, log-debug failure */
return;
}
if( FD_UNLIKELY( pkt.ip4->protocol != FD_IP4_HDR_PROTOCOL_UDP ) ) {
return;
}
if( FD_UNLIKELY( pkt.ip4->net_tot_len > cur_sz ) ) {
return;
}
cur_ptr += rc;
cur_sz -= rc;
1. rc = fd_quic_decode_udp( pkt.udp, cur_ptr, cur_sz );
if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
return;
}
if( FD_UNLIKELY( pkt.udp->net_len > cur_sz ) ) {
return;
}
cur_ptr += rc;
2. cur_sz = pkt.udp->net_len - rc;
...
int long_pkt = !!( (uint)cur_ptr[0] & 0x80u );
uint version = 0;
if( long_pkt ) {
version = DECODE_UINT32( cur_ptr + 1 );
...
3. while(1) {
if( FD_UNLIKELY( cur_sz < FD_QUIC_SHORTEST_PKT ) ) return;
int short_pkt = !( (uint)cur_ptr[0] & 0x80u );
if( FD_UNLIKELY( short_pkt ) ) break;
uint cur_version = DECODE_UINT32( cur_ptr + 1 );
...
...Note that fd_quic_decode_udp() returns 8 (size of udp header)
If pkt.udp->net_len is less than 8, cur_sz will be set to a negative value (large positive)
while loop will go out of bounds when trying to read quic packets
Impact Details
Might be possible to leak parts of memory from QUIC tile.
Denial of service is possible as well.
Proof of concept
Proof of Concept
Most simple way to reproduce this issue is to use fuzz_quic_wire fuzzer with memory sanitizer.
How to reproduce:
build fuzz tests with memory sanitizer, edit config/extra/with-asan.mk and change variables to:
build with command:
get proof of concept by using provided gist link
unpack and decode it:
run fuzz_quic_wire test:
Last updated
Was this helpful?