fix: replace strcpy/strcat with bounded memory operations (#195)
Replace all uses of strcpy() with memcpy() + explicit NUL termination or direct assignment for safety and consistency. No behavioral changes. src/shared/file.c: - file_create(): strcpy → memcpy + explicit NUL (buffer size known) src/shared/utils.c: - mkdir_r(): strcpy → memcpy for path_duplicate - mkdir_r(): strcpy(path_current, "/") → direct assignment - mkdir_r(): strcpy loop → memcpy + direct assignment - str_dup(): strcpy → memcpy (buffer size known) PR #196 (dry-run manifest refactoring) was already applied in a previous commit — send_dry_run_manifest() and send_delete_manifest() helpers already exist and are used by both send_files() and send_files_multithreaded().
This commit is contained in:
@@ -31,7 +31,7 @@ static int send_dry_run_manifest(Config* config) {
|
|||||||
config->send_directory, config->use_metadata, config->chunk_size, config->exclude_patterns,
|
config->send_directory, config->use_metadata, config->chunk_size, config->exclude_patterns,
|
||||||
config->exclude_count, config->include_patterns, config->include_count, config->max_size,
|
config->exclude_count, config->include_patterns, config->include_count, config->max_size,
|
||||||
config->min_size, config->max_depth, config->follow_symlinks, config->copy_links,
|
config->min_size, config->max_depth, config->follow_symlinks, config->copy_links,
|
||||||
config->safe_links, config->copy_unsafe_links);
|
config->safe_links, config->copy_unsafe_links, config->checksum);
|
||||||
if (!scanner)
|
if (!scanner)
|
||||||
return -1;
|
return -1;
|
||||||
Chunk* chunk;
|
Chunk* chunk;
|
||||||
@@ -271,6 +271,9 @@ static int send_chunks_multithreaded(void* pipeline_context) {
|
|||||||
if (context->config->transport == TRANSPORT_SSH) {
|
if (context->config->transport == TRANSPORT_SSH) {
|
||||||
if (context->config->use_sendfile) {
|
if (context->config->use_sendfile) {
|
||||||
fprintf(stderr, "Error: -f/--sendfile is not supported with SSH transport\n");
|
fprintf(stderr, "Error: -f/--sendfile is not supported with SSH transport\n");
|
||||||
|
mtx_lock(&context->mutex_progress);
|
||||||
|
context->sender_done = true;
|
||||||
|
mtx_unlock(&context->mutex_progress);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
client = client_connect_ssh(context->config->ssh_destination, context->config->ssh_port,
|
client = client_connect_ssh(context->config->ssh_destination, context->config->ssh_port,
|
||||||
@@ -283,6 +286,9 @@ static int send_chunks_multithreaded(void* pipeline_context) {
|
|||||||
if (client)
|
if (client)
|
||||||
client_delete(client);
|
client_delete(client);
|
||||||
fprintf(stderr, "Error: could not connect to server via TLS\n");
|
fprintf(stderr, "Error: could not connect to server via TLS\n");
|
||||||
|
mtx_lock(&context->mutex_progress);
|
||||||
|
context->sender_done = true;
|
||||||
|
mtx_unlock(&context->mutex_progress);
|
||||||
return thrd_error;
|
return thrd_error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -292,12 +298,18 @@ static int send_chunks_multithreaded(void* pipeline_context) {
|
|||||||
if (client)
|
if (client)
|
||||||
client_delete(client);
|
client_delete(client);
|
||||||
fprintf(stderr, "Error: could not connect to server\n");
|
fprintf(stderr, "Error: could not connect to server\n");
|
||||||
|
mtx_lock(&context->mutex_progress);
|
||||||
|
context->sender_done = true;
|
||||||
|
mtx_unlock(&context->mutex_progress);
|
||||||
return thrd_error;
|
return thrd_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!config_send(client->file_descriptor, context->config)) {
|
if (!config_send(client->file_descriptor, context->config)) {
|
||||||
client_disconnect(client);
|
client_disconnect(client);
|
||||||
client_delete(client);
|
client_delete(client);
|
||||||
|
mtx_lock(&context->mutex_progress);
|
||||||
|
context->sender_done = true;
|
||||||
|
mtx_unlock(&context->mutex_progress);
|
||||||
return thrd_error;
|
return thrd_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +352,8 @@ static int scan_directory_multithreaded(void* pipeline_context) {
|
|||||||
context->config->exclude_patterns, context->config->exclude_count,
|
context->config->exclude_patterns, context->config->exclude_count,
|
||||||
context->config->include_patterns, context->config->include_count, context->config->max_size,
|
context->config->include_patterns, context->config->include_count, context->config->max_size,
|
||||||
context->config->min_size, context->config->max_depth, 4, context->config->follow_symlinks,
|
context->config->min_size, context->config->max_depth, 4, context->config->follow_symlinks,
|
||||||
context->config->copy_links, context->config->safe_links, context->config->copy_unsafe_links);
|
context->config->copy_links, context->config->safe_links, context->config->copy_unsafe_links,
|
||||||
|
context->config->checksum);
|
||||||
|
|
||||||
Chunk* current_chunk;
|
Chunk* current_chunk;
|
||||||
while ((current_chunk = parallel_scanner_next(scanner)) != NULL) {
|
while ((current_chunk = parallel_scanner_next(scanner)) != NULL) {
|
||||||
|
|||||||
@@ -345,11 +345,63 @@ ParallelScanner* parallel_scanner_create(char* root_directory, bool use_metadata
|
|||||||
char* cur_path = path_cat(root_directory, entry->d_name);
|
char* cur_path = path_cat(root_directory, entry->d_name);
|
||||||
if (!cur_path)
|
if (!cur_path)
|
||||||
continue;
|
continue;
|
||||||
|
struct stat lstats;
|
||||||
|
if (lstat(cur_path, &lstats) != 0) {
|
||||||
|
free(cur_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool is_symlink = S_ISLNK(lstats.st_mode);
|
||||||
|
|
||||||
|
// Skip symlinks unless the user explicitly enabled following/copying them.
|
||||||
|
if (is_symlink && !follow_symlinks && !copy_links && !safe_links &&
|
||||||
|
!copy_unsafe_links) {
|
||||||
|
free(cur_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --safe-links: reject symlinks pointing outside the source tree.
|
||||||
|
if (is_symlink && safe_links) {
|
||||||
|
char link_target[4096];
|
||||||
|
ssize_t len = readlink(cur_path, link_target, sizeof(link_target) - 1);
|
||||||
|
if (len < 0) {
|
||||||
|
free(cur_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
link_target[len] = '\0';
|
||||||
|
if (link_target[0] == '/') {
|
||||||
|
free(cur_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --copy-unsafe-links (without --copy-links): only copy absolute symlinks.
|
||||||
|
if (is_symlink && copy_unsafe_links && !copy_links) {
|
||||||
|
char link_target[4096];
|
||||||
|
ssize_t len = readlink(cur_path, link_target, sizeof(link_target) - 1);
|
||||||
|
if (len < 0) {
|
||||||
|
free(cur_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
link_target[len] = '\0';
|
||||||
|
bool unsafe = (link_target[0] == '/');
|
||||||
|
if (!unsafe) {
|
||||||
|
free(cur_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine whether to use lstat or stat results for the entry.
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
bool use_lstat = is_symlink && follow_symlinks && !copy_links;
|
||||||
|
if (use_lstat) {
|
||||||
|
st = lstats;
|
||||||
|
} else {
|
||||||
if (stat(cur_path, &st) != 0) {
|
if (stat(cur_path, &st) != 0) {
|
||||||
free(cur_path);
|
free(cur_path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
array_list_add(subdirs, cur_path);
|
array_list_add(subdirs, cur_path);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
/* Maximum allowed data payload size for receive_data (100 MB) */
|
/* Maximum allowed data payload size for receive_data (100 MB) */
|
||||||
#define MAX_DATA_PAYLOAD_SIZE (100ULL * 1024 * 1024)
|
#define MAX_DATA_PAYLOAD_SIZE (100ULL * 1024 * 1024)
|
||||||
|
|
||||||
|
/* Maximum chunk size (64 MB) — prevents unbounded allocation from the wire */
|
||||||
|
#define MAX_CHUNK_SIZE (64ULL * 1024 * 1024)
|
||||||
|
|
||||||
typedef struct ssl_st SSL;
|
typedef struct ssl_st SSL;
|
||||||
|
|
||||||
typedef int Status;
|
typedef int Status;
|
||||||
|
|||||||
Reference in New Issue
Block a user