From a32179878e8e439948a4a6385515a0aea7a61592 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 29 Jan 2016 17:48:46 +0200 Subject: [PATCH] Add system_argv() helper for safer calls to system utilities Often file names contain special characters like hashes or whitespaces and that makes escaping a difficult task when using system(). Thus add a new helper system_argv() that is based on execvp() syscall and doesn't require escaping. Signed-off-by: Dmitry Rozhkov Upstream-Status: Backport [v2.54+] --- include/swupd.h | 1 + src/fullfiles.c | 6 ++---- src/helpers.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/include/swupd.h b/include/swupd.h index 522ac2e..ad4b967 100644 --- a/include/swupd.h +++ b/include/swupd.h @@ -228,6 +228,7 @@ extern FILE * fopen_exclusive(const char *filename); /* no mode, opens for write extern void dump_file_info(struct file *file); extern void string_or_die(char **strp, const char *fmt, ...); extern void print_elapsed_time(struct timeval *previous_time, struct timeval *current_time); +extern int system_argv(char *const argv[]); extern bool signature_initialize(void); extern void signature_terminate(void); diff --git a/src/fullfiles.c b/src/fullfiles.c index 1bb581e..fa78293 100644 --- a/src/fullfiles.c +++ b/src/fullfiles.c @@ -138,12 +138,10 @@ static void create_fullfile(struct file *file) string_or_die(&tempfile, "%s/%s", empty, file->hash); if (link(origin, tempfile) < 0) { LOG(NULL, "hardlink failed", "%s due to %s (%s -> %s)", file->filename, strerror(errno), origin, tempfile); - string_or_die(&tarcommand, "cp -a %s %s", origin, tempfile); - if (system(tarcommand) != 0) { - LOG(NULL, "Failed to run command:", "%s", tarcommand); + char *const argv[] = {"cp", "-a", origin, tempfile, NULL}; + if (system_argv(argv) != 0) { assert(0); } - free(tarcommand); } /* step 2a: tar it with each compression type */ diff --git a/src/helpers.c b/src/helpers.c index 65acffd..5884b51 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -124,3 +125,65 @@ void print_elapsed_time(struct timeval *previous_time, struct timeval *current_t free(elapsed); } + +void concat_str_array(char **output, char *const argv[]) +{ + int size = 0; + + for (int i = 0; argv[i]; i++) { + size += strlen(argv[i]) + 1; + } + + *output = malloc(size + 1); + if (!*output) { + LOG(NULL, "Failed to allocate", "%i bytes", size); + assert(0); + } + strcpy(*output, ""); + for (int i = 0; argv[i]; i++) { + strcat(*output, argv[i]); + strcat(*output, " "); + } +} + +int system_argv(char *const argv[]) +{ + int child_exit_status; + pid_t pid; + int status; + + pid = fork(); + + if (pid == 0) { /* child */ + execvp(*argv, argv); + LOG(NULL, "This line must not be reached", ""); + assert(0); + } else if (pid < 0) { + LOG(NULL, "Failed to fork a child process", ""); + assert(0); + } else { + pid_t ws = waitpid(pid, &child_exit_status, 0); + + if (ws == -1) { + LOG(NULL, "Failed to wait for child process", ""); + assert(0); + } + + if (WIFEXITED(child_exit_status)) { + status = WEXITSTATUS(child_exit_status); + } else { + LOG(NULL, "Child process didn't exit", ""); + assert(0); + } + + if (status != 0) { + char* cmdline = NULL; + + concat_str_array(&cmdline, argv); + LOG(NULL, "Failed to run command:", "%s", cmdline); + free(cmdline); + } + + return status; + } +} -- 2.5.0