aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-08-04 02:20:19 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-08-04 02:20:19 +0200
commitcf792a58abc4fc55d0622333d0eb17c6a80dc497 (patch)
treebd740050c3ac79b0db76bd29728dd4d29120ccc6
parent0a53eadea528673a813c5f9312b1f53130429f7c (diff)
downloadbusybox-w32-cf792a58abc4fc55d0622333d0eb17c6a80dc497.tar.gz
busybox-w32-cf792a58abc4fc55d0622333d0eb17c6a80dc497.tar.bz2
busybox-w32-cf792a58abc4fc55d0622333d0eb17c6a80dc497.zip
NOFORK fixes
"rm -i FILE" and "yes" can now be interrupted by ^C in hush. This also now works: $ usleep 19999999 ^C $ echo $? 130 function old new delta run_pipe 1668 1711 +43 pseudo_exec_argv 312 321 +9 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 52/0) Total: 52 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--coreutils/rm.c5
-rw-r--r--coreutils/seq.c5
-rw-r--r--coreutils/usleep.c7
-rw-r--r--coreutils/yes.c3
-rw-r--r--docs/nofork_noexec.txt3
-rw-r--r--shell/hush.c31
6 files changed, 48 insertions, 6 deletions
diff --git a/coreutils/rm.c b/coreutils/rm.c
index cec34cb9d..158c69be5 100644
--- a/coreutils/rm.c
+++ b/coreutils/rm.c
@@ -16,7 +16,8 @@
16//config: help 16//config: help
17//config: rm is used to remove files or directories. 17//config: rm is used to remove files or directories.
18 18
19//applet:IF_RM(APPLET_NOFORK(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm)) 19//applet:IF_RM(APPLET_NOEXEC(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm))
20/* was NOFORK, but then "rm -i FILE" can't be ^C'ed if run by hush */
20 21
21//kbuild:lib-$(CONFIG_RM) += rm.o 22//kbuild:lib-$(CONFIG_RM) += rm.o
22 23
@@ -36,7 +37,7 @@
36 37
37#include "libbb.h" 38#include "libbb.h"
38 39
39/* This is a NOFORK applet. Be very careful! */ 40/* This is a NOEXEC applet. Be very careful! */
40 41
41int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 42int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
42int rm_main(int argc UNUSED_PARAM, char **argv) 43int rm_main(int argc UNUSED_PARAM, char **argv)
diff --git a/coreutils/seq.c b/coreutils/seq.c
index ed4946b05..d5c6451cd 100644
--- a/coreutils/seq.c
+++ b/coreutils/seq.c
@@ -12,7 +12,8 @@
12//config: help 12//config: help
13//config: print a sequence of numbers 13//config: print a sequence of numbers
14 14
15//applet:IF_SEQ(APPLET_NOFORK(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) 15//applet:IF_SEQ(APPLET_NOEXEC(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq))
16/* was NOFORK, but then "seq 1 999999999" can't be ^C'ed if run by hush */
16 17
17//kbuild:lib-$(CONFIG_SEQ) += seq.o 18//kbuild:lib-$(CONFIG_SEQ) += seq.o
18 19
@@ -26,7 +27,7 @@
26 27
27#include "libbb.h" 28#include "libbb.h"
28 29
29/* This is a NOFORK applet. Be very careful! */ 30/* This is a NOEXEC applet. Be very careful! */
30 31
31int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 32int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
32int seq_main(int argc, char **argv) 33int seq_main(int argc, char **argv)
diff --git a/coreutils/usleep.c b/coreutils/usleep.c
index 7bc30c2a2..e68bb4c4d 100644
--- a/coreutils/usleep.c
+++ b/coreutils/usleep.c
@@ -38,6 +38,13 @@ int usleep_main(int argc UNUSED_PARAM, char **argv)
38 bb_show_usage(); 38 bb_show_usage();
39 } 39 }
40 40
41 /* Safe wrt NOFORK? (noforks are not allowed to run for
42 * a long time). Try "usleep 99999999" + ^C + "echo $?"
43 * in hush with FEATURE_SH_NOFORK=y.
44 * At least on uclibc, usleep() thanslates to nanosleep()
45 * which returns early on any signal (even caught one),
46 * and uclibc does not loop back on EINTR.
47 */
41 usleep(xatou(argv[1])); 48 usleep(xatou(argv[1]));
42 49
43 return EXIT_SUCCESS; 50 return EXIT_SUCCESS;
diff --git a/coreutils/yes.c b/coreutils/yes.c
index 81d875589..6b863c3c9 100644
--- a/coreutils/yes.c
+++ b/coreutils/yes.c
@@ -17,7 +17,8 @@
17//config: yes is used to repeatedly output a specific string, or 17//config: yes is used to repeatedly output a specific string, or
18//config: the default string `y'. 18//config: the default string `y'.
19 19
20//applet:IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) 20//applet:IF_YES(APPLET_NOEXEC(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes))
21/* was NOFORK, but then yes can't be ^C'ed if run by hush */
21 22
22//kbuild:lib-$(CONFIG_YES) += yes.o 23//kbuild:lib-$(CONFIG_YES) += yes.o
23 24
diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt
index a24dd9c27..0ad4e6e60 100644
--- a/docs/nofork_noexec.txt
+++ b/docs/nofork_noexec.txt
@@ -52,6 +52,9 @@ xargs, find, shells do it (grep for "spawn_and_wait" and
52This poses much more serious limitations on what applet can do: 52This poses much more serious limitations on what applet can do:
53 53
54* all NOEXEC limitations apply. 54* all NOEXEC limitations apply.
55* do not run for a long time or wait for user input:
56 hush shell only handles signals (like ^C) after you return
57 from APPLET_main().
55* do not ever exit() or exec(). 58* do not ever exit() or exec().
56 - xfuncs are okay. They are using special trick to return 59 - xfuncs are okay. They are using special trick to return
57 to the caller applet instead of dying when they detect "x" condition. 60 to the caller applet instead of dying when they detect "x" condition.
diff --git a/shell/hush.c b/shell/hush.c
index 7cceab30d..2e435cf9f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -7063,6 +7063,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7063 if (APPLET_IS_NOEXEC(a)) { 7063 if (APPLET_IS_NOEXEC(a)) {
7064 /* Do not leak open fds from opened script files etc */ 7064 /* Do not leak open fds from opened script files etc */
7065 close_all_FILE_list(); 7065 close_all_FILE_list();
7066 /* Without this, "rm -i FILE" can't be ^C'ed: */
7067 switch_off_special_sigs(G.special_sig_mask);
7066 debug_printf_exec("running applet '%s'\n", argv[0]); 7068 debug_printf_exec("running applet '%s'\n", argv[0]);
7067 run_applet_no_and_exit(a, argv[0], argv); 7069 run_applet_no_and_exit(a, argv[0], argv);
7068 } 7070 }
@@ -7725,6 +7727,24 @@ static NOINLINE int run_pipe(struct pipe *pi)
7725 add_vars(old_vars); 7727 add_vars(old_vars);
7726/* clean_up_and_ret0: */ 7728/* clean_up_and_ret0: */
7727 restore_redirects(squirrel); 7729 restore_redirects(squirrel);
7730 /*
7731 * Try "usleep 99999999" + ^C + "echo $?"
7732 * with FEATURE_SH_NOFORK=y.
7733 */
7734 if (!funcp) {
7735 /* It was builtin or nofork.
7736 * if this would be a real fork/execed program,
7737 * it should have died if a fatal sig was received.
7738 * But OTOH, there was no separate process,
7739 * the sig was sent to _shell_, not to non-existing
7740 * child.
7741 * Let's just handle ^C only, this one is obvious:
7742 * we aren't ok with exitcode 0 when ^C was pressed
7743 * during builtin/nofork.
7744 */
7745 if (sigismember(&G.pending_set, SIGINT))
7746 rcode = 128 + SIGINT;
7747 }
7728 clean_up_and_ret1: 7748 clean_up_and_ret1:
7729 free(argv_expanded); 7749 free(argv_expanded);
7730 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 7750 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
@@ -7740,6 +7760,14 @@ static NOINLINE int run_pipe(struct pipe *pi)
7740 if (rcode == 0) { 7760 if (rcode == 0) {
7741 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", 7761 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
7742 argv_expanded[0], argv_expanded[1]); 7762 argv_expanded[0], argv_expanded[1]);
7763 /*
7764 * Note: signals (^C) can't interrupt here.
7765 * We remember them and they will be acted upon
7766 * after applet returns.
7767 * This makes applets which can run for a long time
7768 * and/or wait for user input ineligible for NOFORK:
7769 * for example, "yes" or "rm" (rm -i waits for input).
7770 */
7743 rcode = run_nofork_applet(n, argv_expanded); 7771 rcode = run_nofork_applet(n, argv_expanded);
7744 } 7772 }
7745 goto clean_up_and_ret; 7773 goto clean_up_and_ret;
@@ -8160,7 +8188,7 @@ static int run_list(struct pipe *pi)
8160 /* Last command's pid goes to $! */ 8188 /* Last command's pid goes to $! */
8161 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid; 8189 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid;
8162 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); 8190 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n");
8163/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash says 0 */ 8191/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash say 0 */
8164 rcode = EXIT_SUCCESS; 8192 rcode = EXIT_SUCCESS;
8165 goto check_traps; 8193 goto check_traps;
8166 } else { 8194 } else {
@@ -9791,6 +9819,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid
9791 /* So, did we get a signal? */ 9819 /* So, did we get a signal? */
9792 sig = check_and_run_traps(); 9820 sig = check_and_run_traps();
9793 if (sig /*&& sig != SIGCHLD - always true */) { 9821 if (sig /*&& sig != SIGCHLD - always true */) {
9822 /* Do this for any (non-ignored) signal, not only for ^C */
9794 ret = 128 + sig; 9823 ret = 128 + sig;
9795 break; 9824 break;
9796 } 9825 }