libbb: spawn_and_wait() fflushes before forking NOEXEC; child reinits logmode
authorDenys Vlasenko <vda.linux@googlemail.com>
Thu, 26 Jan 2017 00:13:58 +0000 (01:13 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 26 Jan 2017 00:13:58 +0000 (01:13 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
docs/nofork_noexec.txt
include/libbb.h
libbb/vfork_daemon_rexec.c

index 2fb184a0308f4a53ad8884a53aef596d212f4a12..a24dd9c27382069fbc044173e8d363092fa63a6a 100644 (file)
@@ -99,6 +99,13 @@ applet_name. Thus, for example, caller does not need to worry about
 option_mask32 getting trashed.
 
 
+       Calling NOEXEC applets
+
+It's the same trusty spawn_and_wait(argv). If FEATURE_PREFER_APPLETS=y,
+it does NOEXEC trick. It resets xfunc_error_retval = 1 and
+logmode = LOGMODE_STDIO in the child.
+
+
        Relevant CONFIG options
 
 FEATURE_PREFER_APPLETS
index 8c652e2d7f2b38e6d879120face94541fc427eef..07fe20daccfdead2a584b3f39a5ab6b2855b57e9 100644 (file)
@@ -1093,10 +1093,19 @@ pid_t wait_any_nohang(int *wstat) FAST_FUNC;
  */
 int wait4pid(pid_t pid) FAST_FUNC;
 int wait_for_exitstatus(pid_t pid) FAST_FUNC;
+/************************************************************************/
+/* spawn_and_wait/run_nofork_applet/run_applet_no_and_exit need to work */
+/* carefully together to reinit some global state while not disturbing  */
+/* other. Be careful if you change them. Consult docs/nofork_noexec.txt */
+/************************************************************************/
 /* Same as wait4pid(spawn(argv)), but with NOFORK/NOEXEC if configured: */
 int spawn_and_wait(char **argv) FAST_FUNC;
 /* Does NOT check that applet is NOFORK, just blindly runs it */
 int run_nofork_applet(int applet_no, char **argv) FAST_FUNC;
+#ifndef BUILD_INDIVIDUAL
+extern int find_applet_by_name(const char *name) FAST_FUNC;
+extern void run_applet_no_and_exit(int a, char **argv) NORETURN FAST_FUNC;
+#endif
 
 /* Helpers for daemonization.
  *
@@ -1303,11 +1312,6 @@ const struct hwtype *get_hwtype(const char *name) FAST_FUNC;
 const struct hwtype *get_hwntype(int type) FAST_FUNC;
 
 
-#ifndef BUILD_INDIVIDUAL
-extern int find_applet_by_name(const char *name) FAST_FUNC;
-extern void run_applet_no_and_exit(int a, char **argv) NORETURN FAST_FUNC;
-#endif
-
 #ifdef HAVE_MNTENT_H
 extern int match_fstype(const struct mntent *mt, const char *fstypes) FAST_FUNC;
 extern struct mntent *find_mount_point(const char *name, int subdir_too) FAST_FUNC;
index c192829b55fca8388f3f356a94c15d2314dd6e03..2e7dc2d9b1293848e224146e1f07b856e7e2ba02 100644 (file)
@@ -183,26 +183,28 @@ int FAST_FUNC spawn_and_wait(char **argv)
 #if ENABLE_FEATURE_PREFER_APPLETS
        int a = find_applet_by_name(argv[0]);
 
-       if (a >= 0 && (APPLET_IS_NOFORK(a)
-# if BB_MMU
-                       || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */
-# endif
-       )) {
-# if BB_MMU
+       if (a >= 0) {
                if (APPLET_IS_NOFORK(a))
-# endif
-               {
                        return run_nofork_applet(a, argv);
+# if BB_MMU /* NOEXEC needs fork(), thus this is done only on MMU machines: */
+               if (APPLET_IS_NOEXEC(a)) {
+                       fflush_all();
+                       rc = fork();
+                       if (rc) /* parent or error */
+                               return wait4pid(rc);
+
+                       /* child */
+                       /* reset some state and run without execing */
+
+                       /* msg_eol = "\n"; - no caller needs this reinited yet */
+                       logmode = LOGMODE_STDIO;
+                       /* die_func = NULL; - needed if the caller is a shell,
+                        * init, or a NOFORK applet. But none of those call us
+                        * as of yet (and that should probably always stay true).
+                        */
+                       /* xfunc_error_retval and applet_name are init by: */
+                       run_applet_no_and_exit(a, argv);
                }
-# if BB_MMU
-               /* MMU only */
-               /* a->noexec is true */
-               rc = fork();
-               if (rc) /* parent or error */
-                       return wait4pid(rc);
-               /* child */
-               xfunc_error_retval = EXIT_FAILURE;
-               run_applet_no_and_exit(a, argv);
 # endif
        }
 #endif /* FEATURE_PREFER_APPLETS */