diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-08-08 01:21:49 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-08-08 01:21:49 +0200 |
commit | 8858a9864e1d56cfc121755d613d1292727d15f3 (patch) | |
tree | 773321143ecee85069a3db801cff89a227d602b7 | |
parent | 73adef14b25533b71238362da75bfb482d43d98b (diff) | |
download | busybox-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.lst | 4 | ||||
-rw-r--r-- | libbb/vfork_daemon_rexec.c | 125 |
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 | |||
124 | fbset - hardware, leaks: open+xfunc | 124 | fbset - hardware, leaks: open+xfunc |
125 | fbsplash - runner, longterm | 125 | fbsplash - runner, longterm |
126 | fdflush - hardware, leaks: open+ioctl_or_perror_and_die | 126 | fdflush - hardware, leaks: open+ioctl_or_perror_and_die |
127 | fdformat - hardware, needs ^C (floppy may be unresponsive), longterm | 127 | fdformat - hardware, longterm |
128 | fdisk - interactive, longterm | 128 | fdisk - interactive, longterm |
129 | fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds | 129 | fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds |
130 | fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) | 130 | fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) |
@@ -413,7 +413,7 @@ wget - longterm | |||
413 | which - NOFORK | 413 | which - NOFORK |
414 | who - noexec. nofork candidate(is getutxent ok?) | 414 | who - noexec. nofork candidate(is getutxent ok?) |
415 | whoami - NOFORK | 415 | whoami - NOFORK |
416 | whois - needs ^C | 416 | whois - talks to network |
417 | xargs - noexec. spawner | 417 | xargs - noexec. spawner |
418 | xxd - noexec. runner | 418 | xxd - noexec. runner |
419 | xz - runner | 419 | xz - 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 |
23 | pid_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. */ | ||
64 | pid_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 |
74 | static jmp_buf die_jmp; | 25 | static 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) |
162 | void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) | 118 | void 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. */ | ||
145 | pid_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. */ | ||
186 | pid_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 | |||
181 | int FAST_FUNC spawn_and_wait(char **argv) | 194 | int FAST_FUNC spawn_and_wait(char **argv) |
182 | { | 195 | { |
183 | int rc; | 196 | int rc; |