hush: plug the leak on NOMMU re-execute path

function                                             old     new   delta
clean_up_after_re_execute                              -      58     +58
re_execute_shell                                     226     244     +18
run_pipe                                            1271    1276      +5
generate_stream_from_string                          133     138      +5
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/0 up/down: 86/0)               Total: 86 bytes
This commit is contained in:
Denis Vlasenko 2009-04-05 07:38:48 +00:00
parent c3ff48b921
commit cc4c693ec5

View File

@ -481,11 +481,14 @@ struct globals {
smallint fake_mode; smallint fake_mode;
/* These four support $?, $#, and $1 */ /* These four support $?, $#, and $1 */
smalluint last_return_code; smalluint last_return_code;
/* is global_argv and global_argv[1..n] malloced? (note: not [0]) */ /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */
smalluint global_args_malloced; smalluint global_args_malloced;
/* how many non-NULL argv's we have. NB: $# + 1 */ /* how many non-NULL argv's we have. NB: $# + 1 */
int global_argc; int global_argc;
char **global_argv; char **global_argv;
#if !BB_MMU
char **argv_for_re_execing;
#endif
#if ENABLE_HUSH_LOOPS #if ENABLE_HUSH_LOOPS
unsigned depth_break_continue; unsigned depth_break_continue;
unsigned depth_of_loop; unsigned depth_of_loop;
@ -1127,7 +1130,9 @@ static int set_local_var(char *str, int flg_export, int flg_read_only)
set_str_and_exp: set_str_and_exp:
cur->varstr = str; cur->varstr = str;
#if !BB_MMU
cur->flg_read_only = flg_read_only; cur->flg_read_only = flg_read_only;
#endif
exp: exp:
if (flg_export == 1) if (flg_export == 1)
cur->flg_export = 1; cur->flg_export = 1;
@ -2338,6 +2343,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
#if !BB_MMU
static void re_execute_shell(const char *s) NORETURN; static void re_execute_shell(const char *s) NORETURN;
static void re_execute_shell(const char *s) static void re_execute_shell(const char *s)
{ {
@ -2354,7 +2360,7 @@ static void re_execute_shell(const char *s)
cnt += 2; cnt += 2;
} }
//TODO: need to free these strings in parent! //TODO: need to free these strings in parent!
argv = pp = xmalloc(sizeof(argv[0]) * cnt); G.argv_for_re_execing = pp = xmalloc(sizeof(argv[0]) * cnt);
*pp++ = (char *) applet_name; *pp++ = (char *) applet_name;
*pp++ = xasprintf("-$%u", G.root_pid); *pp++ = xasprintf("-$%u", G.root_pid);
*pp++ = xasprintf("-?%u", G.last_return_code); *pp++ = xasprintf("-?%u", G.last_return_code);
@ -2379,11 +2385,28 @@ static void re_execute_shell(const char *s)
//TODO: pass traps and functions //TODO: pass traps and functions
debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
execv(bb_busybox_exec_path, argv); sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
execv(bb_busybox_exec_path, G.argv_for_re_execing);
//TODO: fallback for init=/bin/hush? //TODO: fallback for init=/bin/hush?
_exit(127); _exit(127);
} }
static void clean_up_after_re_execute(void)
{
char **pp = G.argv_for_re_execing;
if (pp) {
/* Must match re_execute_shell's allocations */
free(pp[1]);
free(pp[2]);
free(pp[3]);
free(pp);
G.argv_for_re_execing = NULL;
}
}
#else
#define clean_up_after_re_execute() ((void)0)
#endif
static int run_list(struct pipe *pi); static int run_list(struct pipe *pi);
/* Called after [v]fork() in run_pipe() /* Called after [v]fork() in run_pipe()
@ -2892,9 +2915,11 @@ static int run_pipe(struct pipe *pi)
pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded); pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded);
/* pseudo_exec() does not return */ /* pseudo_exec() does not return */
} }
/* parent */ /* parent */
#if !BB_MMU #if !BB_MMU
/* Clean up after vforked child */ /* Clean up after vforked child */
clean_up_after_re_execute();
free(nommu_save.argv); free(nommu_save.argv);
free_strings_and_unsetenv(nommu_save.new_env, 1); free_strings_and_unsetenv(nommu_save.new_env, 1);
putenv_all(nommu_save.old_env); putenv_all(nommu_save.old_env);
@ -3890,6 +3915,7 @@ static FILE *generate_stream_from_string(const char *s)
} }
/* parent */ /* parent */
clean_up_after_re_execute();
close(channel[1]); close(channel[1]);
pf = fdopen(channel[0], "r"); pf = fdopen(channel[0], "r");
return pf; return pf;
@ -4827,6 +4853,9 @@ static struct pipe *parse_stream(char **pstring,
* while if false; then false; fi do break; done * while if false; then false; fi do break; done
* (bash accepts it) * (bash accepts it)
* while if false; then false; fi; do break; fi * while if false; then false; fi; do break; fi
* Samples to catch leaks at execution:
* while if (true | {true;}); then echo ok; fi; do break; done
* while if (true | {true;}); then echo ok; fi; do (if echo ok; break; then :; fi) | cat; break; done
*/ */
pctx = &ctx; pctx = &ctx;
do { do {