-
Notifications
You must be signed in to change notification settings - Fork 334
fix: prevent stack overflow and /tmp race in dlt-convert workspace (#793) #833
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+362
to
+365
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /* 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); | |
| /* Directory exists — verify it is a directory and usable, then | |
| * clear any pre-existing contents (including attacker-planted | |
| * files) before we use it as a workspace. */ | |
| if (stat(DLT_CONVERT_WS, &st) != 0) { | |
| fprintf(stderr,"ERROR: Cannot stat existing temp path %s!\n", DLT_CONVERT_WS); | |
| if (ovalue) { | |
| close(ohandle); | |
| ohandle = -1; | |
| } | |
| return -1; | |
| } | |
| if (!S_ISDIR(st.st_mode)) { | |
| fprintf(stderr,"ERROR: Temp path %s exists but is not a directory!\n", DLT_CONVERT_WS); | |
| if (ovalue) { | |
| close(ohandle); | |
| ohandle = -1; | |
| } | |
| return -1; | |
| } | |
| empty_dir(DLT_CONVERT_WS); |
Copilot
AI
Apr 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clamping argc to original_argc prevents the overflow but also changes behavior: archives that expand into more than (original_argc - optind) files will have the extra extracted files silently ignored. Instead of mutating/clamping argc, consider iterating over the scandir() results directly or allocating a new argv-like array on the heap sized to the discovered file count.
| /* 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; | |
| /* do not include ./ and ../ in the files; n includes "." and ".." */ | |
| if (n > 2) { | |
| int new_argc = optind + (n - 2); | |
| if (new_argc > original_argc) { | |
| char **new_argv; | |
| int i; | |
| new_argv = (char **)malloc((size_t)new_argc * sizeof(char *)); | |
| if (new_argv == NULL) { | |
| fprintf(stderr, | |
| "ERROR: Out of memory while expanding argument list for %s!\n", | |
| DLT_CONVERT_WS); | |
| if (ovalue) { | |
| close(ohandle); | |
| ohandle = -1; | |
| } | |
| return -1; | |
| } | |
| /* Preserve existing arguments. */ | |
| for (i = 0; i < original_argc; i++) { | |
| new_argv[i] = argv[i]; | |
| } | |
| /* Initialize any newly added slots. They will be populated as needed. */ | |
| for (i = original_argc; i < new_argc; i++) { | |
| new_argv[i] = NULL; | |
| } | |
| argv = new_argv; | |
| argc = new_argc; | |
| } else { | |
| argc = new_argc; | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new EEXIST handling uses stat() and then calls empty_dir() when S_ISDIR is true. Because stat() follows symlinks, an attacker can pre-create /tmp/dlt_convert_workspace as a symlink to another directory; running dlt-convert could then delete files outside of /tmp. Use lstat() and explicitly reject symlinks (and ideally verify ownership/permissions) before cleaning or using the workspace path.