[PATCH v2 15/27] BB_EXECVP: make BB_EXECVP do NOEXEC logic and allow it to to force applet execution

Nadav Tasher tashernadav at gmail.com
Tue Jan 21 22:34:54 UTC 2025


This patch makes BB_EXECVP 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 the
binary. This new behaviour is configurable by the new
FEATURE_FORCE_NOEXEC option.

When FEATURE_FORCE_APPLETS is enabled, BB_EXECVP will
fail when trying to execute things that are not busybox
applets. This allows more control over the executed
processes.

Signed-off-by: Nadav Tasher <tashernadav at gmail.com>
---
 Config.in          | 22 ++++++++++++++++++++++
 include/libbb.h    | 16 +++-------------
 libbb/executable.c | 33 ++++++++++++++++++++++++++++-----
 3 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/Config.in b/Config.in
index dfab102bb..e5d08b33f 100644
--- a/Config.in
+++ b/Config.in
@@ -311,6 +311,28 @@ 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_NOEXEC
+	bool "call applets without exec"
+	default n
+	depends on FEATURE_PREFER_APPLETS
+	help
+	This is an experimental option which allows calling applets directly
+	and bypassing NOEXEC restrictions, instead of exec'ing /proc/self/exe.
+	This reduces the amount of exec syscalls used when running applets,
+	especially in shells.
+
+	This feature extends the "exec prefers applets" feature.
+
+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..af33d94b6 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1230,21 +1230,11 @@ 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.
+/* BB_EXECxx are called instead of using execXX directly, to allow
+ * implementation of NOFORK/NOEXEC applet logic if required.
  */
-#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
+int BB_EXECVPE(const char *file, char *const argv[], char *const envp[]) FAST_FUNC;
 void BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC;
 
 /* xvfork() can't be a _function_, return after vfork in child mangles stack
diff --git a/libbb/executable.c b/libbb/executable.c
index 09bed1eaf..09d15bfec 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,15 +79,37 @@ 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 */
+/* just like the real execvp, but we might try to launch an applet named 'file' first */
 int FAST_FUNC BB_EXECVP(const char *file, char *const argv[])
 {
-	if (find_applet_by_name(file) >= 0)
-		execvp(bb_busybox_exec_path, argv);
+#if ENABLE_FEATURE_PREFER_APPLETS
+	int applet = find_applet_by_name(file);
+	if (applet >= 0) {
+		if (ENABLE_FEATURE_FORCE_NOEXEC || APPLET_IS_NOEXEC(applet)) 
+			run_noexec_applet_and_exit(applet, file, (char **) argv);
+		else
+			execvp(bb_busybox_exec_path, argv);
+	}
+# if ENABLE_FEATURE_FORCE_APPLETS
+	else {
+		/* set errno accordingly */
+		errno = ENOENT;
+		return -1;
+	}
+# endif
+#endif
+
 	return execvp(file, argv);
 }
-#endif
+
+int FAST_FUNC BB_EXECVPE(const char *file, char *const argv[], char *const envp[])
+{
+	clearenv();
+	while (*envp)
+		putenv(*envp++);
+	
+	return BB_EXECVP(file, argv);
+}
 
 void FAST_FUNC BB_EXECVP_or_die(char **argv)
 {
-- 
2.43.0



More information about the busybox mailing list