[PATCH 20/31] dutil: Add exec_objcopy() shell-injection-safe helper
Arnaldo Carvalho de Melo <[email protected]> Wed, 29 Jul 2026 16:07:20 -0300
| Newsgroups | org.kernel.vger.dwarves,org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
From: Arnaldo Carvalho de Melo <[email protected]> Add exec_objcopy() that runs objcopy via posix_spawnp() instead of system(), eliminating shell injection risk from filenames containing shell metacharacters. Signal handling follows POSIX system() semantics: SIGINT/SIGQUIT ignored in parent during wait, SIGCHLD blocked, default dispositions restored in child. No callers yet — the next commit converts btf_encoder and libctf. Assisted-by: Claude:claude-sonnet-4-5 Signed-off-by: Arnaldo Carvalho de Melo <[email protected]> --- dutil.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dutil.h | 3 +++ 2 files changed, 75 insertions(+) diff --git a/dutil.c b/dutil.c index 14f134016add1f0c..38101f184faf58ee 100644 --- a/dutil.c +++ b/dutil.c @@ -9,9 +9,15 @@ #include <ctype.h> #include <errno.h> +#include <signal.h> +#include <spawn.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/wait.h> +#include <unistd.h> + +extern char **environ; void *zalloc(size_t size) { @@ -234,3 +240,69 @@ char *strlwr(char *s) return s; } + +int exec_objcopy(const char *objcopy, const char *add_section, + const char *filename) +{ + sigset_t mask, orig; + struct sigaction ign, old_int, old_quit; + posix_spawnattr_t attr; + sigset_t child_default; + pid_t pid; + int rc; + + char *argv[] = { + (char *)objcopy, + "--add-section", (char *)add_section, + "--", (char *)filename, + NULL + }; + + /* Ignore SIGINT/SIGQUIT in parent while waiting, per POSIX system() */ + ign.sa_handler = SIG_IGN; + sigemptyset(&ign.sa_mask); + ign.sa_flags = 0; + sigaction(SIGINT, &ign, &old_int); + sigaction(SIGQUIT, &ign, &old_quit); + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + pthread_sigmask(SIG_BLOCK, &mask, &orig); + + posix_spawnattr_init(&attr); + /* Restore default signal disposition and mask in child */ + sigemptyset(&child_default); + sigaddset(&child_default, SIGINT); + sigaddset(&child_default, SIGQUIT); + posix_spawnattr_setsigdefault(&attr, &child_default); + posix_spawnattr_setsigmask(&attr, &orig); + posix_spawnattr_setflags(&attr, + POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); + + rc = posix_spawnp(&pid, objcopy, NULL, &attr, argv, environ); + posix_spawnattr_destroy(&attr); + + if (rc != 0) { + sigaction(SIGINT, &old_int, NULL); + sigaction(SIGQUIT, &old_quit, NULL); + pthread_sigmask(SIG_SETMASK, &orig, NULL); + return rc == ENOENT ? -ENOENT : -1; + } + + int status; + + while (waitpid(pid, &status, 0) == -1) { + if (errno != EINTR) { + status = -1; + break; + } + } + + sigaction(SIGINT, &old_int, NULL); + sigaction(SIGQUIT, &old_quit, NULL); + pthread_sigmask(SIG_SETMASK, &orig, NULL); + + if (status == -1 || !WIFEXITED(status)) + return -1; + + return WEXITSTATUS(status) == 0 ? 0 : -1; +} diff --git a/dutil.h b/dutil.h index be02c68cf4a7ff22..603556fa03085abf 100644 --- a/dutil.h +++ b/dutil.h @@ -351,6 +351,9 @@ static inline int elf_getshdrstrndx(Elf *elf, size_t *dst) char *strlwr(char *s); +int exec_objcopy(const char *objcopy, const char *add_section, + const char *filename); + void __zfree(void **ptr); #define zfree(ptr) __zfree((void **)(ptr)) -- 2.55.0