Adds support for nested directories#293
Conversation
There was a problem hiding this comment.
Pull request overview
Adds “mkdir -p” style behavior to Meterpreter’s mettle stdapi filesystem mkdir handler to align directory creation semantics with other session types.
Changes:
- Updates
fs_mkdirto attempt creation of intermediate path components when given a nested directory path. - Switches mkdir handling from a single
eio_mkdircall to manual path splitting + per-component existence checks/creation.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| path_dup = strdup(path); | ||
|
|
||
| eio_mkdir(path, 0777, 0, fs_cb, ctx); | ||
| // take into account null byte at the end of path and the one we add in sprintf | ||
| base_dir = malloc(strlen(path_dup)+2); | ||
| tmp = malloc(strlen(path_dup)+2); | ||
| dir = strtok(path_dup, "/"); | ||
|
|
||
| //address absolute paths — check original path since strtok modifies path_dup | ||
| if (path[0] == '/') | ||
| { | ||
| sprintf(base_dir, "/%s/", dir); | ||
| } | ||
| else | ||
| { | ||
| sprintf(base_dir, "%s/", dir); | ||
| } |
There was a problem hiding this comment.
fs_mkdir doesn’t validate allocation/tokenization results: strdup()/malloc() can return NULL, and strtok() returns NULL for inputs like "" or "/" (or all-slash paths). In those cases the subsequent sprintf(base_dir, ... , dir) dereferences a NULL dir and will crash. Add checks for allocation failures and for dir == NULL before formatting, and return an appropriate error code (e.g., TLV_RESULT_ENOMEM / TLV_RESULT_EINVAL) instead of proceeding.
| while(dir != NULL) | ||
| { | ||
| #ifdef _WIN32 | ||
| if(stat(base_dir, &f_info) != 0) | ||
| #else | ||
| if(lstat(base_dir, &f_info) != 0) | ||
| #endif | ||
| { | ||
| eio_mkdir(base_dir, 0777, 0, NULL, NULL); | ||
| } | ||
| memset(&f_info, 0, sizeof(struct stat)); | ||
| dir = strtok(NULL, "/"); | ||
| if(dir != NULL) | ||
| { | ||
| sprintf(tmp, "%s%s/", base_dir, dir); | ||
| strcpy(base_dir, tmp); | ||
| } | ||
| } | ||
|
|
||
| struct tlv_packet *p = tlv_packet_response_result(ctx,TLV_RESULT_SUCCESS); | ||
|
|
||
| tlv_dispatcher_enqueue_response(ctx->td, p); | ||
| tlv_handler_ctx_free(ctx); |
There was a problem hiding this comment.
fs_mkdir now enqueues a TLV_RESULT_SUCCESS response immediately and frees ctx without waiting for any mkdir operations to complete or checking their results. Additionally, each missing path component is created via eio_mkdir with a NULL callback, which both prevents error reporting and can schedule nested directory creations out-of-order (e.g., "a/b" mkdir can run before "a"), causing intermittent failures while still returning success. Consider moving the whole recursive mkdir logic into a single eio_custom worker (or chaining eio_mkdir calls with a callback) so directory creation is ordered and the response reflects the actual outcome (including EEXIST/ENOTDIR cases).
Fixes mkdir inconsistency. This address the inconsistency between mkdir among Meterpreter and other types of sessions.