svn commit: [25945] trunk/busybox/shell: hush_test/hush-misc

vda at busybox.net vda at busybox.net
Fri Apr 3 22:31:18 UTC 2009


Author: vda
Date: 2009-04-03 22:31:18 +0000 (Fri, 03 Apr 2009)
New Revision: 25945

Log:
hush: finally make `cmd` safe on NOMMU

function                                             old     new   delta
generate_stream_from_string                            -     157    +157
expand_variables                                    2050    2003     -47
generate_stream_from_list                            139       -    -139
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 0/1 up/down: 157/-186)          Total: -29 bytes



Modified:
   trunk/busybox/shell/hush.c
   trunk/busybox/shell/hush_test/hush-misc/syntax_err.right


Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c	2009-04-03 21:16:45 UTC (rev 25944)
+++ trunk/busybox/shell/hush.c	2009-04-03 22:31:18 UTC (rev 25945)
@@ -90,14 +90,6 @@
 #define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 #endif
 
-#if !BB_MMU && ENABLE_HUSH_TICK
-//#undef ENABLE_HUSH_TICK
-//#define ENABLE_HUSH_TICK 0
-#warning On NOMMU, hush command substitution is dangerous.
-#warning Dont use it for commands which produce lots of output.
-#warning For more info see shell/hush.c, generate_stream_from_list().
-#endif
-
 #if !ENABLE_HUSH_INTERACTIVE
 #undef ENABLE_FEATURE_EDITING
 #define ENABLE_FEATURE_EDITING 0
@@ -1649,7 +1641,7 @@
 
 /* Expansion can recurse */
 #if ENABLE_HUSH_TICK
-static int process_command_subs(o_string *dest, struct in_str *input);
+static int process_command_subs(o_string *dest, const char *s);
 #endif
 static char *expand_string_to_string(const char *str);
 static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end);
@@ -1798,18 +1790,15 @@
 			ored_ch = 0x80;
 			break;
 #if ENABLE_HUSH_TICK
-		case '`': { /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
-			struct in_str input;
+		case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
 			*p = '\0';
 			arg++;
 //TODO: can we just stuff it into "output" directly?
 			debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
-			setup_string_in_str(&input, arg);
-			process_command_subs(&subst_result, &input);
+			process_command_subs(&subst_result, arg);
 			debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
 			val = subst_result.data;
 			goto store_val;
-		}
 #endif
 #if ENABLE_SH_MATH_SUPPORT
 		case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */
@@ -3711,35 +3700,20 @@
 }
 
 static struct pipe *parse_stream(struct in_str *input, int end_trigger);
+static void parse_and_run_string(const char *s);
 
 #if ENABLE_HUSH_TICK
-static FILE *generate_stream_from_list(struct pipe *head)
+static FILE *generate_stream_from_string(const char *s)
 {
 	FILE *pf;
 	int pid, channel[2];
 
 	xpipe(channel);
-/* *** NOMMU WARNING *** */
-/* By using vfork here, we suspend parent till child exits or execs.
- * If child will not do it before it fills the pipe, it can block forever
- * in write(STDOUT_FILENO), and parent (shell) will be also stuck.
- * Try this script:
- * yes "0123456789012345678901234567890" | dd bs=32 count=64k >TESTFILE
- * huge=`cat TESTFILE` # will block here forever
- * echo OK
- */
 	pid = BB_MMU ? fork() : vfork();
 	if (pid < 0)
 		bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
+
 	if (pid == 0) { /* child */
-		if (ENABLE_HUSH_JOB)
-			die_sleep = 0; /* let nofork's xfuncs die */
-		close(channel[0]); /* NB: close _first_, then move fd! */
-		xmove_fd(channel[1], 1);
-		/* Prevent it from trying to handle ctrl-z etc */
-#if ENABLE_HUSH_JOB
-		G.run_list_level = 1;
-#endif
 		/* Process substitution is not considered to be usual
 		 * 'command execution'.
 		 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not.
@@ -3749,40 +3723,47 @@
 			+ (1 << SIGTTIN)
 			+ (1 << SIGTTOU)
 			, SIG_IGN);
-
-		/* Note: freeing 'head' here would break NOMMU. */
-		_exit(run_list(head));
+		if (ENABLE_HUSH_JOB)
+			die_sleep = 0; /* let nofork's xfuncs die */
+		close(channel[0]); /* NB: close _first_, then move fd! */
+		xmove_fd(channel[1], 1);
+		/* Prevent it from trying to handle ctrl-z etc */
+		USE_HUSH_JOB(G.run_list_level = 1;)
+#if BB_MMU
+		parse_and_run_string(s);
+		_exit(G.last_return_code);
+#else
+	/* We re-execute after vfork on NOMMU. This makes this script safe:
+	 * yes "0123456789012345678901234567890" | dd bs=32 count=64k >TESTFILE
+	 * huge=`cat TESTFILE` # was blocking here forever
+	 * echo OK
+	 */
+//TODO: pass non-exported variables, traps, and functions
+		execl(CONFIG_BUSYBOX_EXEC_PATH, "hush", "-c", s, NULL);
+		_exit(127);
+#endif
 	}
+
+	/* parent */
 	close(channel[1]);
 	pf = fdopen(channel[0], "r");
 	return pf;
-	/* 'head' is freed by the caller */
 }
 
 /* Return code is exit status of the process that is run. */
-static int process_command_subs(o_string *dest,
-		struct in_str *input)
+static int process_command_subs(o_string *dest, const char *s)
 {
-	int retcode, ch, eol_cnt;
-	struct pipe *pipe_list;
-	FILE *p;
+	FILE *pf;
 	struct in_str pipe_str;
+	int ch, eol_cnt;
 
-	/* Recursion to generate command */
-	pipe_list = parse_stream(input, '\0');
-	if (pipe_list == NULL)
-		return 0;  /* EOF: empty `cmd`: ``, `  ` etc */
-	if (pipe_list == ERR_PTR)
-		return 1;  /* parse error. can this really happen? */
-
-	p = generate_stream_from_list(pipe_list);
-	free_pipe_list(pipe_list, /* indent: */ 0);
-	if (p == NULL)
+	pf = generate_stream_from_string(s);
+	if (pf == NULL)
 		return 1;
-	close_on_exec_on(fileno(p));
+	close_on_exec_on(fileno(pf));
 
 	/* Now send results of command back into original context */
-	setup_file_in_str(&pipe_str, p);
+	setup_file_in_str(&pipe_str, pf);
 	eol_cnt = 0;
 	while ((ch = i_getch(&pipe_str)) != EOF) {
 		if (ch == '\n') {
@@ -3799,12 +3780,13 @@
 	debug_printf("done reading from pipe, pclose()ing\n");
 	/* Note: we got EOF, and we just close the read end of the pipe.
 	 * We do not wait for the `cmd` child to terminate. bash and ash do.
-	 * Try this:
-	 * echo `echo Hi; exec 1>&-; sleep 2`
+	 * Try these:
+	 * echo `echo Hi; exec 1>&-; sleep 2` - bash waits 2 sec
+	 * `false`; echo $? - bash outputs "1"
 	 */
-	retcode = fclose(p);
-	debug_printf("closed FILE from child, retcode=%d\n", retcode);
-	return retcode;
+	fclose(pf);
+	debug_printf("closed FILE from child. return 0\n");
+	return 0;
 }
 #endif
 

Modified: trunk/busybox/shell/hush_test/hush-misc/syntax_err.right
===================================================================
--- trunk/busybox/shell/hush_test/hush-misc/syntax_err.right	2009-04-03 21:16:45 UTC (rev 25944)
+++ trunk/busybox/shell/hush_test/hush-misc/syntax_err.right	2009-04-03 22:31:18 UTC (rev 25945)
@@ -1,2 +1,4 @@
 shown
 hush: syntax error: unterminated '
+test
+not shown



More information about the busybox-cvs mailing list