Skip to content

[Prior2] fix: handle bufferoverflow and memory issues in v2 protocol - #895

Closed
santhoshsivanhere wants to merge 9 commits into
COVESA:masterfrom
santhoshsivanhere:combine/related-prs
Closed

[Prior2] fix: handle bufferoverflow and memory issues in v2 protocol#895
santhoshsivanhere wants to merge 9 commits into
COVESA:masterfrom
santhoshsivanhere:combine/related-prs

Conversation

@santhoshsivanhere

@santhoshsivanhere santhoshsivanhere commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Combine multiple related PRs #861, #862, #864, #865, #868, #869 #873

Summary

This PR consolidates several interdependent / closely related pull requests into a single, cohesive change set. Combining them reduces merge friction, ensures consistent testing, and simplifies the review process for the team.

The following PRs are squashed / merged into this branch:


Changes included

ℹ️ For detailed rationale, please refer to the individual PR threads linked above.

The fixed-size precheck at the entry of this function validates only the
11-byte minimum GET_LOG_INFO V2 request (apidlen = ctidlen = 0). The
function then reads two attacker-controlled uint8_t length fields
(apidlen, ctidlen) from msg->databuffer and uses them to advance an
offset, before passing pointers into the buffer to dlt_set_id_v2()
(which reads up to apidlen / ctidlen bytes via dlt_strnlen_s) and
finishing with a 4-byte memcpy of the trailing com field. A short
message with non-zero length fields causes the variable-length reads to
walk past the end of msg->databuffer.

Add bounds checks after each length is parsed, freeing the calloc'd
request and returning when the message cannot satisfy the next read.

Note: the existing early-return paths inside this function already leak
the calloc'd req pointer; left untouched here to keep this commit
focused on the security fix.

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
Companion fix to the OOB-read fix in the previous commit. The function
never assigned req->apid or req->ctid: req is calloc'd, so the char *
pointer fields start NULL, and the dlt_set_id_v2(req->apid, ...) call to
populate them was a no-op (dlt_set_id_v2 early-returns when its
destination is NULL). req->apid / req->ctid stayed NULL and were then
passed to dlt_daemon_application_find_v2 and dlt_daemon_context_find_v2
despite req->apidlen / req->ctidlen being non-zero — every non-empty
lookup was silently turned into a zero-length one.

Copy the apid/ctid into local fixed-size buffers through the shared
dlt_set_id_v2() helper and point req->apid / req->ctid at those buffers,
keeping id initialisation inside the helper API rather than aliasing the
receive buffer. The buffers live for the whole function scope and req is
freed (struct only) before return, so the pointers stay valid for every
use. The bounds checks added in the previous commit keep the helper's
reads within msg->databuffer.

Closes COVESA#870.
Related: COVESA#866.

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
mft1cob and others added 7 commits July 13, 2026 14:23
Fix two issues in dlt_daemon_control_get_log_info_v2() when parsing
GET_LOG_INFO V2 requests.

First, validate the variable-length APID and CTID fields before reading
them. The existing fixed-size check only verified the minimum 11-byte
request, allowing attacker-controlled apidlen and ctidlen values to
cause reads beyond the end of msg->databuffer through dlt_set_id_v2()
and the trailing com field memcpy(). Add bounds checks after each length
is parsed and abort processing when the remaining message is too short.

Second, correctly initialize req->apid and req->ctid. The request
structure is allocated with calloc(), leaving these pointers NULL.
Passing them to dlt_set_id_v2() was therefore a no-op, causing all
subsequent APID/CTID lookups to behave as zero-length lookups even when
valid IDs were present. Copy the IDs into local fixed-size buffers using
dlt_set_id_v2() and point req->apid and req->ctid to those buffers for
the lifetime of the function.

The existing early-return paths that leak the allocated request
structure are intentionally left unchanged.

Closes: COVESA#870
Related: COVESA#866

Signed-off-by: Matt Jones
               <47545907+SoundMatt@users.noreply.github.com>
Signed-off-by: Santhosh Sivan Murugan
               <122221363+santhoshsivanhere@users.noreply.github.com>
Validate the variable-length APID and CTID fields when parsing
SET_LOG_LEVEL V2 requests.

The existing fixed-size precheck verifies only the minimum 11-byte
request (apidlen = ctidlen = 0). The function then reads two
attacker-controlled uint8_t length fields and uses them to advance an
offset into msg->databuffer before passing pointers into the buffer to
dlt_set_id_v2(), reading the log_level field, and copying the trailing
com field. A short message with non-zero length fields can therefore
cause reads beyond the end of msg->databuffer.

Add bounds checks after each length field is parsed and return without
further processing when the remaining message is too short. Since the
request structure is allocated on the stack, no cleanup is required on
these error paths.

Related: COVESA#861

Signed-off-by: Matt Jones
               <47545907+SoundMatt@users.noreply.github.com>
Signed-off-by: Santhosh Sivan Murugan
               <122221363+santhoshsivanhere@users.noreply.github.com>
Correct APID and CTID parsing in
dlt_daemon_control_set_log_level_v2().

The request structure stores APID and CTID as char * fields, but these
pointers were never initialized before being passed to dlt_set_id_v2().
Since the helper returns immediately when given a NULL destination, the
IDs were never parsed from the request, leaving req.apid and req.ctid
NULL.

Requests with empty APID/CTID fields silently became no-ops, while
requests containing non-empty IDs could dereference a NULL pointer in
the wildcard and field-only handling paths, crashing the daemon.

Copy the APID and CTID into local fixed-size buffers using
dlt_set_id_v2() and point req.apid and req.ctid at those buffers. This
keeps ID initialization within the shared helper, avoids aliasing the
receive buffer, and ensures the parsed IDs remain valid for the lifetime
of the function.

Also add unit tests covering dlt_set_id_v2() normal operation,
truncation at DLT_V2_ID_SIZE, overflow handling, and NULL/zero-length
inputs.

Closes: COVESA#863
Related: COVESA#862

Signed-off-by: Matt Jones
               <47545907+SoundMatt@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Santhosh Sivan Murugan
               <122221363+santhoshsivanhere@users.noreply.github.com>
dlt_with_filename_and_line_number() stores the filename length in the
uint8_t dlt_user.filenamelen field, but used the truncated value to size
the heap allocation while copying the full filename with strcpy().

When the source filename exceeds UINT8_MAX bytes, the length is
truncated modulo 256, causing the allocated buffer to be smaller than
the source string. The subsequent strcpy() then writes past the end of
the heap buffer.

This can occur with long compile-time __FILE__ paths (for example,
absolute paths in large monorepos) or when applications forward
user-controlled filenames through this API.

Clamp the filename length to UINT8_MAX before storing it, allocate the
buffer using the clamped length, and copy only that many bytes followed
by an explicit null terminator. This preserves the existing V2 protocol
limit while preventing the heap overflow.

Signed-off-by: Matt Jones
               <47545907+SoundMatt@users.noreply.github.com>
Signed-off-by: Santhosh Sivan Murugan
               <122221363+santhoshsivanhere@users.noreply.github.com>
Correct several issues in
dlt_daemon_control_message_unregister_context_v2() when building the
UNREGISTER_CONTEXT V2 response.

The response size calculation accumulated the payload length in a
uint8_t, allowing it to wrap for large APID and CTID values. This could
underallocate the response buffer and lead to a heap buffer overflow
during serialization.

The response structure also failed to initialize and populate its APID
and CTID fields correctly. The structure's apid and ctid members are
char * pointers, but they were passed directly to dlt_set_id_v2() while
still NULL, so the helper copied nothing. The corresponding length
fields were likewise left unset, resulting in incorrect response
payloads and undefined behaviour during serialization.

Zero-initialize the response structure, compute the payload size using a
uint32_t accumulator, copy APID and CTID into local fixed-size buffers
through dlt_set_id_v2(), and point the response structure at those
buffers for serialization. Also initialize the length fields and guard
variable-length copies against NULL pointers.

This preserves ID initialization through the shared helper, avoids
aliasing the caller's buffers, prevents size calculation overflow, and
ensures the response is serialized correctly.

Closes: COVESA#867
Related: COVESA#866

Signed-off-by: Matt Jones
               <47545907+SoundMatt@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Santhosh Sivan Murugan
               <122221363+santhoshsivanhere@users.noreply.github.com>
Rewrite the handler to parse the GET request field-by-field instead of
casting msg->databuffer directly to DltServiceSetLogLevelV2 *.

The struct contains char *apid and char *ctid pointer fields, so the
direct cast caused these pointers to be populated with attacker-controlled
network data and later dereferenced. The previous implementation also
triggered the same NULL-dereference issue identified in COVESA#863.

Add bounds checks for the attacker-controlled APID and CTID length fields
to ensure variable-length reads remain within msg->databuffer.

Copy APID/CTID into local fixed-size buffers using the shared
dlt_set_id_v2() helper and point apid/ctid to those buffers. This keeps ID
initialisation within the helper API instead of aliasing the receive buffer,
consistent with the fixes in COVESA#864, COVESA#868, and COVESA#861.

Related: COVESA#866.

Signed-off-by: Matt Jones
               <47545907+SoundMatt@users.noreply.github.com>
Signed-off-by: Santhosh Sivan Murugan
               <122221363+santhoshsivanhere@users.noreply.github.com>
…r_info

Three chained strcat() calls build a path as dir + "/" + d_name into the
fixed-size tmpfile[] buffer (DLT_OFFLINE_LOGSTORAGE_MAX_LOG_FILE_LEN + 1,
i.e. 121 bytes).

Although dir is derived from dirname() applied to a configuration field
bounded by DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN (100 bytes), d_name is
returned by scandir() and can be up to NAME_MAX (255 bytes) on Linux.
Therefore, dir + "/" + d_name can exceed the tmpfile buffer size and cause
a stack buffer overflow.

Replace the chained strcat() calls with a single snprintf() using
sizeof(tmpfile) to enforce the destination buffer limit. Also replace the
no-directory branch with strncpy() for consistent bounded string handling.

Signed-off-by: Matt Jones
               <47545907+SoundMatt@users.noreply.github.com>
Signed-off-by: Santhosh Sivan Murugan
               <122221363+santhoshsivanhere@users.noreply.github.com>
@santhoshsivanhere
santhoshsivanhere marked this pull request as ready for review July 13, 2026 10:06
@santhoshsivanhere santhoshsivanhere changed the title [DRAFT] fix: handle bufferoverflow and memory issues in v2 protocol fix: handle bufferoverflow and memory issues in v2 protocol Jul 13, 2026
@santhoshsivanhere
santhoshsivanhere force-pushed the combine/related-prs branch 2 times, most recently from 98d5c8e to 379c52b Compare July 13, 2026 10:12
@minminlittleshrimp minminlittleshrimp changed the title fix: handle bufferoverflow and memory issues in v2 protocol [Prior2] fix: handle bufferoverflow and memory issues in v2 protocol Jul 15, 2026
@minminlittleshrimp

Copy link
Copy Markdown
Collaborator

Hi @SoundMatt
I would say this is such an over-engineering where the fix seems another AI-slop to me.
I rework and remove any unrelated comments, dlt has nothing to do with security, but more or less safety, and you know what, security vs. safety is a controversal thing to discuss ✌🏻

@minminlittleshrimp

Copy link
Copy Markdown
Collaborator

Solved here #911

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants