libbb: spawn_and_wait() fflushes before forking NOEXEC; child reinits logmode
No binary (build failed)
—
(log yok)
| @@ -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 | |
| @@ -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; | |
| @@ -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 */ | |