COVESA / COVESA/dlt-daemon

Heap Buffer Overflow in dlt_buffer_get()

Open
#899 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
459
Forks
340
Avg merge
4d 21h
Merged PRs (30d)
2

Description

## Summary
A heap buffer overflow exists in dlt_buffer_get(). The function's "third check" that validates head.size against the caller's max_size buffer only emits LOG_WARNING and does not abort execution. An attacker who can write to the DLT shared memory (SHM) ring buffer can craft a DltBufferBlockHead with head.size > max_size, causing dlt_buffer_read_block() to copy attacker-controlled data beyond the bounds of the destination heap buffer (recv_buf_shm). This vulnerability causes heap corruption, primarily resulting in denial of service (DoS) due to heap metadata corruption. In some cases, it may also be leveraged for local privilege escalation.

## Root Cause Analysis

src/shared/dlt_common.c:4162-4279:
```
/* third check size */
if (max_size && (head.size > max_size))
dlt_vlog(LOG_WARNING,
"%s: Buffer: Max size is smaller than read header size. Max size: %d\n",
__func__, max_size);

/* nothing to do but data does not fit provided buffer */

if ((data != NULL) && max_size) {
/* read data */
dlt_buffer_read_block(buf, &read, data, (unsigned int)head.size);
```

- Third check is non-binding (line 4246-4249)
When head.size > max_size, only a warning is logged. Execution continues to dlt_buffer_read_block() which copies head.size bytes into the caller's max_size-byte buffer.

- Signed→unsigned cast enables massive copy (line 4255)
head.size is declared as signed int. Setting head.size = -1 bypasses the third check entirely (-1 > max_size is false in signed comparison). The cast (unsigned int)head.size then yields 0xFFFFFFFF, causing dlt_buffer_read_block() to attempt a ~4GB copy.

- Second check validates ring data, not caller buffer (line 4237)
if (used_size < ((int)sizeof(DltBufferBlockHead) + head.size))
This checks only whether the ring buffer contains enough data for the claimed size. Since the attacker controls both used_size (via SHM write/read pointers) and head.size, this provides no protection against overflowing the caller's data buffer.

src/shared/dlt_common.c:3893-3917:
```
void dlt_buffer_read_block(DltBuffer *buf, int *read,
unsigned char *data, unsigned int size)
{
if (((unsigned int)(*read) + size) <= buf->size) {
memcpy(data, buf->mem + *read, size);
*read += (int)size;
} else {
if ((unsigned int)(*read) <= buf->size) {
memcpy(data, buf->mem + *read,
buf->size - (unsigned int)(*read));
memcpy(data + buf->size - *read, buf->mem,
size - buf->size + (unsigned int)(*read));
*read += (int)(size - buf->size);
}
}
}
```
No bounds check against size exists. The caller's data buffer size is unknown to this function.

Log:

```
$ ./exploit 1
[*] mode=1 head.size=10200(0x27d8) write=10212 read=0 count=1
[*] Trigger sent.

Write DltBufferBlockHead with size > 10000 (or -1) into SHM data area, set DltBufferHead.write = read + sizeof(header) + head.size, count = 1, then send DltUserHeader to daemon's FIFO. The daemon's dlt_buffer_get() warns but copies oversized block into 10000-byte heap buffer overflow.

$ dlt-daemon
Cannot open configuration file: etc/dlt.conf
[1024492.686391]~DLT~39655~NOTICE ~Starting DLT Daemon; DLT Package Version: 3.0.1 STABLE, Package Revision: v3.0.0_20_gb84dbc0, build on Jul 14 2026 14:04:25
-SYSTEMD -SYSTEMD_WATCHDOG -TEST +SHM

[1024492.686497]~DLT~39655~INFO ~DLT protocol version: 1 (DLTv1)
[1024492.686865]~DLT~39655~INFO ~Activate connection type: 4
[1024492.686911]~DLT~39655~INFO ~dlt_daemon_socket_open: Socket created
[1024492.686935]~DLT~39655~INFO ~dlt_daemon_socket_open: Listening on ip 0.0.0.0 and port: 3490
[1024492.686958]~DLT~39655~INFO ~dlt_daemon_socket_open: Socket send queue size: 16384
[1024492.687022]~DLT~39655~INFO ~Activate connection type: 1
[1024492.687140]~DLT~39655~INFO ~Activate connection type: 9
[1024492.687194]~DLT~39655~INFO ~Cannot open configuration file: /tmp/dlt-runtime.cfg
[1024492.687206]~DLT~39655~INFO ~Ringbuffer configuration: 500000/10000000/500000
[1024492.688048]~DLT~39655~NOTICE ~Failed to open ECU Software version file.
[1024492.688152]~DLT~39655~WARNING ~Unable to set send timeout Socket operation on non-socket.
[1024492.688169]~DLT~39655~INFO ~Activate connection type: 6
[1024492.688175]~DLT~39655~INFO ~Switched to buffer state for socket connections.
[1024492.688277]~DLT~39655~WARNING ~dlt_daemon_applications_load: cannot open file /tmp/dlt-runtime-application.cfg: No such file or directory
[1024494.754968]~DLT~39655~INFO ~Activate connection type: 5
[1024494.755071]~DLT~39655~WARNING ~dlt_buffer_get: Buffer: Max size is smaller than read header size. Max size: 10000
=================================================================
==39655==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x52600000b810 at pc 0x77bb6a1f9303 bp 0x7ffe0540ef20 sp 0x7ffe0540e6c8
WRITE of size 10200 at 0x52600000b810 thread T0
#0 0x77bb6a1f9302 in memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115
#1 0x5a11178c9e12 in dlt_buffer_read_block /root/dlt-daemon/src/shared/dlt_common.c:3899
#2 0x5a11178cc105 in dlt_buffer_get /root/dlt-daemon/src/shared/dlt_common.c:4255
#3 0x5a11178cc5e4 in dlt_buffer_pull /root/dlt-daemon/src/shared/dlt_common.c:4284
#4 0x5a11178f88d9 in dlt_shm_pull /root/dlt-daemon/src/shared/dlt_shm.c:355
#5 0x5a111784f0cc in dlt_daemon_process_user_message_log /root/dlt-daemon/src/daemon/dlt-daemon.c:5113
#6 0x5a111784576a in dlt_daemon_process_user_messages /root/dlt-daemon/src/daemon/dlt-daemon.c:3838
#7 0x5a11178871c4 in dlt_daemon_handle_event /root/dlt-daemon/src/daemon/dlt_daemon_event_handler.c:264
#8 0x5a111783930a in main /root/dlt-daemon/src/daemon/dlt-daemon.c:1684
#9 0x77bb69f161c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#10 0x77bb69f1628a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#11 0x5a1117834564 in _start (/root/dlt-daemon/build_asan/src/daemon/dlt-daemon+0x23564) (BuildId: 774c6e8df918994896ed6133e1a185e4c7000b20)

0x52600000b810 is located 0 bytes after 10000-byte region [0x526000009100,0x52600000b810)
allocated by thread T0 here:
#0 0x77bb6a1fb340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x5a1117839fc9 in dlt_daemon_local_init_p2 /root/dlt-daemon/src/daemon/dlt-daemon.c:1863
#2 0x5a1117838d4f in main /root/dlt-daemon/src/daemon/dlt-daemon.c:1569
#3 0x77bb69f161c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#4 0x77bb69f1628a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#5 0x5a1117834564 in _start (/root/dlt-daemon/build_asan/src/daemon/dlt-daemon+0x23564) (BuildId: 774c6e8df918994896ed6133e1a185e4c7000b20)

SUMMARY: AddressSanitizer: heap-buffer-overflow ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115 in memcpy
Shadow bytes around the buggy address:
0x52600000b580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x52600000b600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x52600000b680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x52600000b700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x52600000b780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x52600000b800: 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x52600000b880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x52600000b900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x52600000b980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x52600000ba00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x52600000ba80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==39655==ABORTING
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in src/shared/dlt_common.c at dlt_buffer_get() and dlt_buffer_read_block(), then follow the reported call path through src/shared/dlt_shm.c and src/daemon/dlt-daemon.c. Run the reported ./exploit reproduction under AddressSanitizer and verify that oversized and negative header sizes no longer cause a heap-buffer-overflow.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.