Skip to content

fix(logstorage): replace unbounded strcat with snprintf in storage_dir_info#873

Open
SoundMatt wants to merge 1 commit into
COVESA:masterfrom
SoundMatt:fix/logstorage-strcat-overflow
Open

fix(logstorage): replace unbounded strcat with snprintf in storage_dir_info#873
SoundMatt wants to merge 1 commit into
COVESA:masterfrom
SoundMatt:fix/logstorage-strcat-overflow

Conversation

@SoundMatt

Copy link
Copy Markdown

Summary

dlt_logstorage_storage_dir_info() in dlt_offline_logstorage_behavior.c builds a file path from three pieces using three chained strcat() calls into a fixed-size stack buffer:

char tmpfile[DLT_OFFLINE_LOGSTORAGE_MAX_LOG_FILE_LEN + 1] = { '\0' };  // 121 bytes
if (dir != NULL) {
    strcat(tmpfile, dir);          // up to ~99 chars (from config)
    strcat(tmpfile, "/");          // + 1
}
strcat(tmpfile, files[i]->d_name); // up to NAME_MAX = 255 chars

dir is derived from a config-bounded field (max DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN = 100 chars), so the directory component is bounded. However files[i]->d_name comes from scandir() and can be up to NAME_MAX (255 bytes) on Linux.

dir(~99) + "/" + d_name(~255) = ~355 bytes can easily overflow the 121-byte tmpfile buffer, causing a stack buffer overflow. The overflow is triggerable whenever the storage directory contains a file whose name exceeds the buffer capacity, which can happen naturally or via a crafted mount-point with long filenames.

Changes

Replace the three strcat() calls with a single snprintf(..., sizeof(tmpfile), ...), which hard-limits the write to the buffer size. Add a strncpy for the no-directory branch for consistency.

Testing

  • Paths shorter than DLT_OFFLINE_LOGSTORAGE_MAX_LOG_FILE_LEN are copied unchanged.
  • Paths longer than the buffer are safely truncated; no stack overflow.

@minminlittleshrimp minminlittleshrimp left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please kindly check and fix the api logic, not remove it completely.
Thank you

db_offset = db_offset + (int)sizeof(uint8_t);
memcpy(&(req->apidlen), msg->databuffer + db_offset, sizeof(uint8_t));
db_offset = db_offset + (int)sizeof(uint8_t);
dlt_set_id_v2(req->apid, (const char *)(msg->databuffer + db_offset), req->apidlen);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @SoundMatt
please kindly explain why the official api is removed.
Kindly approach with fixing the official API instead of manually handly app id or ctx id.

…r_info

Three chained strcat() calls build a path as dir + "/" + d_name into a
fixed-size tmpfile[] buffer (DLT_OFFLINE_LOGSTORAGE_MAX_LOG_FILE_LEN+1,
i.e. 121 bytes).  dir comes from dirname() applied to a config field
that is bounded by DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN (100 chars),
but d_name is returned by scandir() and can be up to NAME_MAX (255 chars)
on Linux.  dir(~100) + "/" + d_name(~255) can easily exceed 121 bytes,
overflowing tmpfile on the stack.

Replace with a single snprintf(..., sizeof(tmpfile), "%s/%s", dir,
files[i]->d_name) which hard-limits the write to the buffer size, and
use strncpy for the no-dir branch to be consistent.

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
@SoundMatt SoundMatt force-pushed the fix/logstorage-strcat-overflow branch from 6ff5773 to 64e2696 Compare June 18, 2026 15:00
@SoundMatt

Copy link
Copy Markdown
Author

Thanks @minminlittleshrimp — I think the confusion was that this branch was accidentally stacked on top of the GET_LOG_INFO V2 commits, so your comment landed on the get_log_info_v2 apid/ctid handling at dlt_daemon_client.c:2154 rather than the logstorage change.

I've rebased this PR onto master so it now contains only the logstorage fix (the single storage_dir_info strcatsnprintf change). No official API is touched here.

The get_log_info_v2 apid/ctid parsing you flagged has been reworked to use the shared dlt_set_id_v2() helper (into local buffers, no raw wire-buffer aliasing) over in its own PR #861 — same approach as #864/#868. Could you re-review the two separately now that they're cleanly split?

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.

2 participants