[git commit] libbb: rearrange NOFORK/NOEXEC code, logic is not changed

Denys Vlasenko vda.linux at googlemail.com
Mon Aug 7 23:21:49 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=8858a9864e1d56cfc121755d613d1292727d15f3
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 NOFORK_NOEXEC.lst          |   4 +-
 libbb/vfork_daemon_rexec.c | 125 +++++++++++++++++++++++++--------------------
 2 files changed, 71 insertions(+), 58 deletions(-)

diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst
index 98e1bff..bfb76a1 100644
--- a/NOFORK_NOEXEC.lst
+++ b/NOFORK_NOEXEC.lst
@@ -124,7 +124,7 @@ fatattr - noexec. leaks: open+xioctl, complex
 fbset - hardware, leaks: open+xfunc
 fbsplash - runner, longterm
 fdflush - hardware, leaks: open+ioctl_or_perror_and_die
-fdformat - hardware, needs ^C (floppy may be unresponsive), longterm
+fdformat - hardware, longterm
 fdisk - interactive, longterm
 fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds
 fgrep - longterm runner ("CMD | fgrep ..."  may run indefinitely, better to exec to conserve memory)
@@ -413,7 +413,7 @@ wget - longterm
 which - NOFORK
 who - noexec. nofork candidate(is getutxent ok?)
 whoami - NOFORK
-whois - needs ^C
+whois - talks to network
 xargs - noexec. spawner
 xxd - noexec. runner
 xz - runner
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index a349459..c96cd61 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -14,61 +14,12 @@
  *
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
-
 #include "busybox.h" /* uses applet tables */
 #include "NUM_APPLETS.h"
 
-/* This does a fork/exec in one call, using vfork().  Returns PID of new child,
- * -1 for failure.  Runs argv[0], searching path if that has no / in it. */
-pid_t FAST_FUNC spawn(char **argv)
-{
-	/* Compiler should not optimize stores here */
-	volatile int failed;
-	pid_t pid;
-
-	fflush_all();
-
-	/* Be nice to nommu machines. */
-	failed = 0;
-	pid = vfork();
-	if (pid < 0) /* error */
-		return pid;
-	if (!pid) { /* child */
-		/* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
-		BB_EXECVP(argv[0], argv);
-
-		/* We are (maybe) sharing a stack with blocked parent,
-		 * let parent know we failed and then exit to unblock parent
-		 * (but don't run atexit() stuff, which would screw up parent.)
-		 */
-		failed = errno;
-		/* mount, for example, does not want the message */
-		/*bb_perror_msg("can't execute '%s'", argv[0]);*/
-		_exit(111);
-	}
-	/* parent */
-	/* Unfortunately, this is not reliable: according to standards
-	 * vfork() can be equivalent to fork() and we won't see value
-	 * of 'failed'.
-	 * Interested party can wait on pid and learn exit code.
-	 * If 111 - then it (most probably) failed to exec */
-	if (failed) {
-		safe_waitpid(pid, NULL, 0); /* prevent zombie */
-		errno = failed;
-		return -1;
-	}
-	return pid;
-}
-
-/* Die with an error message if we can't spawn a child process. */
-pid_t FAST_FUNC xspawn(char **argv)
-{
-	pid_t pid = spawn(argv);
-	if (pid < 0)
-		bb_simple_perror_msg_and_die(*argv);
-	return pid;
-}
-
+/*
+ * NOFORK support
+ */
 #if ENABLE_FEATURE_PREFER_APPLETS \
  || ENABLE_FEATURE_SH_NOFORK
 static jmp_buf die_jmp;
@@ -127,10 +78,10 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
 	 * reset the libc getopt() function, which keeps internal state.
 	 */
 	GETOPT_RESET();
+//?	applet_long_options = NULL;
+//?	opt_complementary = NULL;
 
-	argc = 1;
-	while (argv[argc])
-		argc++;
+	argc = string_array_len(argv);
 
 	/* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */
 	die_func = jump;
@@ -153,11 +104,16 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
 	restore_nofork_data(&old);
 	/* Other globals can be simply reset to defaults */
 	GETOPT_RESET();
+//?	applet_long_options = NULL;
+//?	opt_complementary = NULL;
 
 	return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
 }
 #endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */
 
+/*
+ * NOEXEC support
+ */
 #if (NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE)
 void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv)
 {
@@ -167,17 +123,74 @@ void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv)
 	xfunc_error_retval = EXIT_FAILURE;
 	die_func = NULL;
 	GETOPT_RESET();
+//?	applet_long_options = NULL;
+//?	opt_complementary = NULL;
 
 //TODO: think pidof, pgrep, pkill!
 //set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"),
 //but one from procps-ng-3.3.10 needs more!
 //Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!)
 	set_task_comm(name);
-	/* xfunc_error_retval and applet_name are init by: */
+	/* applet_name is set by this function: */
 	run_applet_no_and_exit(a, name, argv);
 }
 #endif
 
+/*
+ * Higher-level code, hiding optional NOFORK/NOEXEC trickery.
+ */
+
+/* This does a fork/exec in one call, using vfork().  Returns PID of new child,
+ * -1 for failure.  Runs argv[0], searching path if that has no / in it. */
+pid_t FAST_FUNC spawn(char **argv)
+{
+	/* Compiler should not optimize stores here */
+	volatile int failed;
+	pid_t pid;
+
+	fflush_all();
+
+	/* Be nice to nommu machines. */
+	failed = 0;
+	pid = vfork();
+	if (pid < 0) /* error */
+		return pid;
+	if (!pid) { /* child */
+		/* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
+		BB_EXECVP(argv[0], argv);
+
+		/* We are (maybe) sharing a stack with blocked parent,
+		 * let parent know we failed and then exit to unblock parent
+		 * (but don't run atexit() stuff, which would screw up parent.)
+		 */
+		failed = errno;
+		/* mount, for example, does not want the message */
+		/*bb_perror_msg("can't execute '%s'", argv[0]);*/
+		_exit(111);
+	}
+	/* parent */
+	/* Unfortunately, this is not reliable: according to standards
+	 * vfork() can be equivalent to fork() and we won't see value
+	 * of 'failed'.
+	 * Interested party can wait on pid and learn exit code.
+	 * If 111 - then it (most probably) failed to exec */
+	if (failed) {
+		safe_waitpid(pid, NULL, 0); /* prevent zombie */
+		errno = failed;
+		return -1;
+	}
+	return pid;
+}
+
+/* Die with an error message if we can't spawn a child process. */
+pid_t FAST_FUNC xspawn(char **argv)
+{
+	pid_t pid = spawn(argv);
+	if (pid < 0)
+		bb_simple_perror_msg_and_die(*argv);
+	return pid;
+}
+
 int FAST_FUNC spawn_and_wait(char **argv)
 {
 	int rc;


More information about the busybox-cvs mailing list