From a1ee3f275c6ee024d4c557d2f1eef92d0c95f31a Mon Sep 17 00:00:00 2001 From: Akihiko Komada Date: Thu, 2 Apr 2026 12:51:01 +0900 Subject: [PATCH] fix: prevent stack overflow and /tmp race in dlt-convert workspace (#793) Two related bugs in the -t (compressed file) path of dlt-convert: 1. Workspace not cleared when directory already exists (CWE-377): mkdir() failing with EEXIST did not call empty_dir(). The struct stat was zero-initialised but never populated via stat(), so S_ISDIR() was always false and empty_dir() was never reached. An attacker who pre-creates /tmp/dlt_convert_workspace/ and fills it with files controls the workspace contents before dlt-convert runs. Fix: call stat() before S_ISDIR() in the EEXIST path so the check is meaningful; always call empty_dir() in the fresh-mkdir path (removing the now-dead fprintf branch). 2. argc inflated past original argv bounds (CWE-121, stack overflow): argc = optind + (n - 2) can exceed the original argc when n is large (e.g. attacker planted many files). The subsequent loop assigns argv[index] = tmp_filename for indices beyond the original argv allocation, writing past the stack-allocated argument vector. Fix: save original_argc before the tflag block and cap the inflated argc at that value. CWE-377 (Insecure Temporary File), CWE-121 (Stack-based Buffer Overflow), CWE-20 (Improper Input Validation). Signed-off-by: Akihiko Komada --- src/console/dlt-convert.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/console/dlt-convert.c b/src/console/dlt-convert.c index a4c6dc122..d986bdb1e 100644 --- a/src/console/dlt-convert.c +++ b/src/console/dlt-convert.c @@ -229,6 +229,7 @@ int main(int argc, char *argv[]) memset(&st, 0, sizeof(struct stat)); struct dirent **files = { 0 }; int n = 0; + int original_argc = argc; struct iovec iov[2]; int bytes_written = 0; @@ -358,12 +359,13 @@ int main(int argc, char *argv[]) } return -1; } + /* Directory exists — clear any pre-existing contents (including + * attacker-planted files) before we use it as a workspace. */ + if (stat(DLT_CONVERT_WS, &st) == 0 && S_ISDIR(st.st_mode)) + empty_dir(DLT_CONVERT_WS); } else { - if (S_ISDIR(st.st_mode)) - empty_dir(DLT_CONVERT_WS); - else - fprintf(stderr, "ERROR: %s is not a directory", DLT_CONVERT_WS); + empty_dir(DLT_CONVERT_WS); } for (index = optind; index < argc; index++) { @@ -398,6 +400,9 @@ int main(int argc, char *argv[]) /* do not include ./ and ../ in the files */ argc = optind + (n - 2); + /* Guard: never exceed the original argv bounds. */ + if (argc > original_argc) + argc = original_argc; } for (index = optind; index < argc; index++) {