aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-08-08 01:21:49 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-08-08 01:21:49 +0200
commit8858a9864e1d56cfc121755d613d1292727d15f3 (patch)
tree773321143ecee85069a3db801cff89a227d602b7
parent73adef14b25533b71238362da75bfb482d43d98b (diff)
downloadbusybox-w32-8858a9864e1d56cfc121755d613d1292727d15f3.tar.gz
busybox-w32-8858a9864e1d56cfc121755d613d1292727d15f3.tar.bz2
busybox-w32-8858a9864e1d56cfc121755d613d1292727d15f3.zip
libbb: rearrange NOFORK/NOEXEC code, logic is not changed
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--NOFORK_NOEXEC.lst4
-rw-r--r--libbb/vfork_daemon_rexec.c125
2 files changed, 71 insertions, 58 deletions
diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst
index 98e1bffdf..bfb76a12e 100644
--- a/NOFORK_NOEXEC.lst
+++ b/NOFORK_NOEXEC.lst
@@ -124,7 +124,7 @@ fatattr - noexec. leaks: open+xioctl, complex
124fbset - hardware, leaks: open+xfunc 124fbset - hardware, leaks: open+xfunc
125fbsplash - runner, longterm 125fbsplash - runner, longterm
126fdflush - hardware, leaks: open+ioctl_or_perror_and_die 126fdflush - hardware, leaks: open+ioctl_or_perror_and_die
127fdformat - hardware, needs ^C (floppy may be unresponsive), longterm 127fdformat - hardware, longterm
128fdisk - interactive, longterm 128fdisk - interactive, longterm
129fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds 129fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds
130fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) 130fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory)
@@ -413,7 +413,7 @@ wget - longterm
413which - NOFORK 413which - NOFORK
414who - noexec. nofork candidate(is getutxent ok?) 414who - noexec. nofork candidate(is getutxent ok?)
415whoami - NOFORK 415whoami - NOFORK
416whois - needs ^C 416whois - talks to network
417xargs - noexec. spawner 417xargs - noexec. spawner
418xxd - noexec. runner 418xxd - noexec. runner
419xz - runner 419xz - runner
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index a349459f0..c96cd61a5 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -14,61 +14,12 @@
14 * 14 *
15 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 15 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
16 */ 16 */
17
18#include "busybox.h" /* uses applet tables */ 17#include "busybox.h" /* uses applet tables */
19#include "NUM_APPLETS.h" 18#include "NUM_APPLETS.h"
20 19
21/* This does a fork/exec in one call, using vfork(). Returns PID of new child, 20/*
22 * -1 for failure. Runs argv[0], searching path if that has no / in it. */ 21 * NOFORK support
23pid_t FAST_FUNC spawn(char **argv) 22 */
24{
25 /* Compiler should not optimize stores here */
26 volatile int failed;
27 pid_t pid;
28
29 fflush_all();
30
31 /* Be nice to nommu machines. */
32 failed = 0;
33 pid = vfork();
34 if (pid < 0) /* error */
35 return pid;
36 if (!pid) { /* child */
37 /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
38 BB_EXECVP(argv[0], argv);
39
40 /* We are (maybe) sharing a stack with blocked parent,
41 * let parent know we failed and then exit to unblock parent
42 * (but don't run atexit() stuff, which would screw up parent.)
43 */
44 failed = errno;
45 /* mount, for example, does not want the message */
46 /*bb_perror_msg("can't execute '%s'", argv[0]);*/
47 _exit(111);
48 }
49 /* parent */
50 /* Unfortunately, this is not reliable: according to standards
51 * vfork() can be equivalent to fork() and we won't see value
52 * of 'failed'.
53 * Interested party can wait on pid and learn exit code.
54 * If 111 - then it (most probably) failed to exec */
55 if (failed) {
56 safe_waitpid(pid, NULL, 0); /* prevent zombie */
57 errno = failed;
58 return -1;
59 }
60 return pid;
61}
62
63/* Die with an error message if we can't spawn a child process. */
64pid_t FAST_FUNC xspawn(char **argv)
65{
66 pid_t pid = spawn(argv);
67 if (pid < 0)
68 bb_simple_perror_msg_and_die(*argv);
69 return pid;
70}
71
72#if ENABLE_FEATURE_PREFER_APPLETS \ 23#if ENABLE_FEATURE_PREFER_APPLETS \
73 || ENABLE_FEATURE_SH_NOFORK 24 || ENABLE_FEATURE_SH_NOFORK
74static jmp_buf die_jmp; 25static jmp_buf die_jmp;
@@ -127,10 +78,10 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
127 * reset the libc getopt() function, which keeps internal state. 78 * reset the libc getopt() function, which keeps internal state.
128 */ 79 */
129 GETOPT_RESET(); 80 GETOPT_RESET();
81//? applet_long_options = NULL;
82//? opt_complementary = NULL;
130 83
131 argc = 1; 84 argc = string_array_len(argv);
132 while (argv[argc])
133 argc++;
134 85
135 /* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */ 86 /* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */
136 die_func = jump; 87 die_func = jump;
@@ -153,11 +104,16 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
153 restore_nofork_data(&old); 104 restore_nofork_data(&old);
154 /* Other globals can be simply reset to defaults */ 105 /* Other globals can be simply reset to defaults */
155 GETOPT_RESET(); 106 GETOPT_RESET();
107//? applet_long_options = NULL;
108//? opt_complementary = NULL;
156 109
157 return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ 110 return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
158} 111}
159#endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */ 112#endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */
160 113
114/*
115 * NOEXEC support
116 */
161#if (NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE) 117#if (NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE)
162void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) 118void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv)
163{ 119{
@@ -167,17 +123,74 @@ void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv)
167 xfunc_error_retval = EXIT_FAILURE; 123 xfunc_error_retval = EXIT_FAILURE;
168 die_func = NULL; 124 die_func = NULL;
169 GETOPT_RESET(); 125 GETOPT_RESET();
126//? applet_long_options = NULL;
127//? opt_complementary = NULL;
170 128
171//TODO: think pidof, pgrep, pkill! 129//TODO: think pidof, pgrep, pkill!
172//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), 130//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"),
173//but one from procps-ng-3.3.10 needs more! 131//but one from procps-ng-3.3.10 needs more!
174//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) 132//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!)
175 set_task_comm(name); 133 set_task_comm(name);
176 /* xfunc_error_retval and applet_name are init by: */ 134 /* applet_name is set by this function: */
177 run_applet_no_and_exit(a, name, argv); 135 run_applet_no_and_exit(a, name, argv);
178} 136}
179#endif 137#endif
180 138
139/*
140 * Higher-level code, hiding optional NOFORK/NOEXEC trickery.
141 */
142
143/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
144 * -1 for failure. Runs argv[0], searching path if that has no / in it. */
145pid_t FAST_FUNC spawn(char **argv)
146{
147 /* Compiler should not optimize stores here */
148 volatile int failed;
149 pid_t pid;
150
151 fflush_all();
152
153 /* Be nice to nommu machines. */
154 failed = 0;
155 pid = vfork();
156 if (pid < 0) /* error */
157 return pid;
158 if (!pid) { /* child */
159 /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
160 BB_EXECVP(argv[0], argv);
161
162 /* We are (maybe) sharing a stack with blocked parent,
163 * let parent know we failed and then exit to unblock parent
164 * (but don't run atexit() stuff, which would screw up parent.)
165 */
166 failed = errno;
167 /* mount, for example, does not want the message */
168 /*bb_perror_msg("can't execute '%s'", argv[0]);*/
169 _exit(111);
170 }
171 /* parent */
172 /* Unfortunately, this is not reliable: according to standards
173 * vfork() can be equivalent to fork() and we won't see value
174 * of 'failed'.
175 * Interested party can wait on pid and learn exit code.
176 * If 111 - then it (most probably) failed to exec */
177 if (failed) {
178 safe_waitpid(pid, NULL, 0); /* prevent zombie */
179 errno = failed;
180 return -1;
181 }
182 return pid;
183}
184
185/* Die with an error message if we can't spawn a child process. */
186pid_t FAST_FUNC xspawn(char **argv)
187{
188 pid_t pid = spawn(argv);
189 if (pid < 0)
190 bb_simple_perror_msg_and_die(*argv);
191 return pid;
192}
193
181int FAST_FUNC spawn_and_wait(char **argv) 194int FAST_FUNC spawn_and_wait(char **argv)
182{ 195{
183 int rc; 196 int rc;