This patch makes BB_EXECVPE the gateway to the exec syscall family. When called, it first looks for a matching applet, and executes it directly of indirectly by re-executing busybox binary. This feature takes NOEXEC definitions into account by checking NOEXEC with the APPLET_IS_NOEXEC function.
When FEATURE_FORCE_APPLETS is enabled, BB_EXECVPE will fail when trying to execute external binaries, and only pre-compiled applets will be able to run. This allows for better control over the programs executed by busybox. BB_EXECVP is redefined as a macro to BB_EXECVPE that uses environ as the default envp argument. Signed-off-by: Nadav Tasher <tasherna...@gmail.com> --- Config.in | 10 +++++++++ include/libbb.h | 28 +++++++++++-------------- libbb/executable.c | 51 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 63 insertions(+), 26 deletions(-) diff --git a/Config.in b/Config.in index dfab102bb..9d40431ee 100644 --- a/Config.in +++ b/Config.in @@ -311,6 +311,16 @@ config FEATURE_PREFER_APPLETS problems in chroot jails without mounted /proc and with ps/top (command name can be shown as 'exe' for applets started this way). +config FEATURE_FORCE_APPLETS + bool "only use applets" + default n + depends on FEATURE_PREFER_APPLETS + help + This is an experimental option which makes exec calls fail when trying + to execute external binaries that are not part of busybox. + + This feature extends the "exec prefers applets" feature. + config BUSYBOX_EXEC_PATH string "Path to busybox executable" default "/proc/self/exe" diff --git a/include/libbb.h b/include/libbb.h index 4d6193795..79fa5f1e9 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1230,22 +1230,18 @@ int file_is_executable(const char *name) FAST_FUNC; char *find_executable(const char *filename, const char **PATHp) FAST_FUNC; int executable_exists(const char *filename) FAST_FUNC; -/* BB_EXECxx always execs (it's not doing NOFORK/NOEXEC stuff), - * but it may exec busybox and call applet instead of searching PATH. - */ -#if ENABLE_FEATURE_PREFER_APPLETS -int BB_EXECVP(const char *file, char *const argv[]) FAST_FUNC; -#define BB_EXECLP(prog,cmd,...) \ - do { \ - if (find_applet_by_name(prog) >= 0) \ - execlp(bb_busybox_exec_path, cmd, __VA_ARGS__); \ - execlp(prog, cmd, __VA_ARGS__); \ - } while (0) -#else -#define BB_EXECVP(prog,cmd) execvp(prog,cmd) -#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd,__VA_ARGS__) -#endif -void BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; +/* BB_EXECVP is just a macro to use BB_EXECVPE + * with a default environ argument. */ +#define BB_EXECVP(file, argv) BB_EXECVPE(file, argv, environ) +#define BB_EXECVP_or_die(argv) BB_EXECVP_or_die_msg(argv, "can't execute '%s'") + +/* BB_EXECVPE is called instead of using exec directly. + * this allows implementation of NOEXEC applet logic. */ +int BB_EXECVPE(const char *file, char *const argv[], char *const envp[]) FAST_FUNC; + +/* BB_EXECVP_or_die is commonly used in functions that must + * exit if the execution of the desired program fails. */ +void BB_EXECVP_or_die_msg(char *const argv[], const char *msg) NORETURN FAST_FUNC; /* xvfork() can't be a _function_, return after vfork in child mangles stack * in the parent. It must be a macro. */ diff --git a/libbb/executable.c b/libbb/executable.c index 09bed1eaf..01506062b 100644 --- a/libbb/executable.c +++ b/libbb/executable.c @@ -7,6 +7,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" +#include "busybox.h" /* for APPLET_IS_NOEXEC */ /* check if path points to an executable file; * return 1 if found; @@ -78,20 +79,50 @@ int FAST_FUNC executable_exists(const char *name) return ret != NULL; } -#if ENABLE_FEATURE_PREFER_APPLETS -/* just like the real execvp, but try to launch an applet named 'file' first */ -int FAST_FUNC BB_EXECVP(const char *file, char *const argv[]) +/* just like the real execvpe, but we might try to launch an applet named 'file' first */ +int FAST_FUNC BB_EXECVPE(const char *file, char *const argv[], char *const envp[]) { - if (find_applet_by_name(file) >= 0) - execvp(bb_busybox_exec_path, argv); - return execvp(file, argv); -} +#if ENABLE_FEATURE_PREFER_APPLETS + int applet = find_applet_by_name(file); + if (applet >= 0) { + if (APPLET_IS_NOEXEC(applet)) { + /* if non-default environ was passed, replace environ */ + if (envp != environ) { + clearenv(); + + /* envp is NULL terminated. */ + while (*envp) + putenv(*envp++); + } + + /* this should never return. */ + run_noexec_applet_and_exit(applet, file, argv); + + /* if this is reached, error out */ + errno = ENOEXEC; + return -1; + } else { + /* applet has to be executed using an exec syscall */ + return execvpe(bb_busybox_exec_path, argv, envp); + } + } +# if ENABLE_FEATURE_FORCE_APPLETS + else { + /* no external programs are allowed, error out */ + errno = ENOENT; + return -1; + } +# endif #endif -void FAST_FUNC BB_EXECVP_or_die(char **argv) + /* we can always fall back to execvpe */ + return execvpe(file, argv, envp); +} + +void FAST_FUNC BB_EXECVP_or_die_msg(char *const argv[], const char *msg) { BB_EXECVP(argv[0], argv); /* SUSv3-mandated exit codes */ xfunc_error_retval = (errno == ENOENT) ? 127 : 126; - bb_perror_msg_and_die("can't execute '%s'", argv[0]); -} + bb_perror_msg_and_die(msg, argv[0]); +} \ No newline at end of file -- 2.43.0 _______________________________________________ busybox mailing list busybox@busybox.net https://lists.busybox.net/mailman/listinfo/busybox