[PATCH v8 09/14] ash: use bb_execve to execute commands and applets in tryexec

Nadav Tasher tashernadav at gmail.com
Sun Mar 9 23:55:31 UTC 2025


This commit makes the shell use the bb_execve proxy function.
bb_execve calls applet_execve, which might execute applets
directly.

Signed-off-by: Nadav Tasher <tashernadav at gmail.com>
---
 shell/ash.c | 72 +++++++++++++++++++----------------------------------
 1 file changed, 26 insertions(+), 46 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 9173b8608..5e21ac7e1 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -8271,34 +8271,23 @@ static int builtinloc = -1;     /* index in path of %builtin, or -1 */
 
 
 static void
-tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
+tryexec(const char *cmd, char **argv, char **envp)
 {
-#if ENABLE_FEATURE_SH_STANDALONE
-	if (applet_no >= 0) {
-		if (APPLET_IS_NOEXEC(applet_no)) {
-			clearenv();
-			while (*envp)
-				putenv(*envp++);
-			popredir(/*drop:*/ 1);
-			run_noexec_applet_and_exit(applet_no, cmd, argv);
-		}
-		/* re-exec ourselves with the new arguments */
-		execve(bb_busybox_exec_path, argv, envp);
-		/* If they called chroot or otherwise made the binary no longer
-		 * executable, fall through */
-	}
-#endif
+	/* because we might not actually exec, redirected fds
+	 * might not close, since they have the CLOEXEC flag.
+	 * this ensures they are closed. */
+	popredir(/*drop:*/ 1);
 
  repeat:
 #ifdef SYSV
 	do {
-		execve(cmd, argv, envp);
+		bb_execve(cmd, argv, envp);
 	} while (errno == EINTR);
 #else
-	execve(cmd, argv, envp);
+	bb_execve(cmd, argv, envp);
 #endif
 
-	if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
+	if (strcmp(cmd, "ash") != 0 && errno == ENOEXEC) {
 		/* Run "cmd" as a shell script:
 		 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
 		 * "If the execve() function fails with ENOEXEC, the shell
@@ -8316,12 +8305,15 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c
 		 * to interpret foreign ELF binaries as shell scripts.
 		 */
 		argv[0] = (char*) cmd;
-		cmd = bb_busybox_exec_path;
+
 		/* NB: this is only possible because all callers of shellexec()
 		 * ensure that the argv[-1] slot exists!
-		 */
+		 * it is also required, as ash expects args to start at argv[1]. */
 		argv--;
 		argv[0] = (char*) "ash";
+
+		/* this makes the following repeat execute ash by re-exec or NOEXEC */
+		cmd = (char*) "ash";
 		goto repeat;
 	}
 }
@@ -8338,33 +8330,21 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
 	int e;
 	char **envp;
 	int exerrno;
-	int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
 
 	envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
-	if (strchr(prog, '/') != NULL
-#if ENABLE_FEATURE_SH_STANDALONE
-	 || (applet_no = find_applet_by_name(prog)) >= 0
-#endif
-	) {
-		tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
-		if (applet_no >= 0) {
-			/* We tried execing ourself, but it didn't work.
-			 * Maybe /proc/self/exe doesn't exist?
-			 * Try $PATH search.
-			 */
-			goto try_PATH;
-		}
-		e = errno;
-	} else {
- try_PATH:
-		e = ENOENT;
-		while (padvance(&path, argv[0]) >= 0) {
-			cmdname = stackblock();
-			if (--idx < 0 && pathopt == NULL) {
-				tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
-				if (errno != ENOENT && errno != ENOTDIR)
-					e = errno;
-			}
+	/* try executing using tryexec, which might execute applets
+	 * using NOEXEC logic, and might execute a matching binary.
+	 */
+	tryexec(prog, argv, envp);
+	e = errno;
+
+	/* fallback to PATH search and try executing using tryexec */
+	while (padvance(&path, argv[0]) >= 0) {
+		cmdname = stackblock();
+		if (--idx < 0 && pathopt == NULL) {
+			tryexec(cmdname, argv, envp);
+			if (errno != ENOENT && errno != ENOTDIR)
+				e = errno;
 		}
 	}
 
-- 
2.43.0



More information about the busybox mailing list