aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-09 19:05:11 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-09 19:05:11 +0200
commit9db344a0f4ed5f6f893940b734215d05e48320e9 (patch)
treeda03d9e54ffafbc22c3d4c795c82e872290fbc63 /shell/hush.c
parenteb0de05d682b28fcf7465358ea31cf8574c1221b (diff)
downloadbusybox-w32-9db344a0f4ed5f6f893940b734215d05e48320e9.tar.gz
busybox-w32-9db344a0f4ed5f6f893940b734215d05e48320e9.tar.bz2
busybox-w32-9db344a0f4ed5f6f893940b734215d05e48320e9.zip
hush: fix var_leaks.tests and var_preserved.tests on NOMMU
function old new delta remove_nested_vars - 77 +77 run_pipe 1756 1786 +30 pseudo_exec_argv 376 379 +3 leave_var_nest_level 98 32 -66 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/1 up/down: 110/-66) Total: 44 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to '')
-rw-r--r--shell/hush.c108
1 files changed, 59 insertions, 49 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 3a4b5d894..885561389 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -2266,6 +2266,7 @@ static int set_local_var(char *str, unsigned flags)
2266 } 2266 }
2267 2267
2268 /* Not found or shadowed - create new variable struct */ 2268 /* Not found or shadowed - create new variable struct */
2269 debug_printf_env("%s: alloc new var '%s'/%u\n", __func__, str, local_lvl);
2269 cur = xzalloc(sizeof(*cur)); 2270 cur = xzalloc(sizeof(*cur));
2270 cur->var_nest_level = local_lvl; 2271 cur->var_nest_level = local_lvl;
2271 cur->next = *cur_pp; 2272 cur->next = *cur_pp;
@@ -2420,7 +2421,7 @@ static void set_vars_and_save_old(char **strings)
2420 * global linked list. 2421 * global linked list.
2421 */ 2422 */
2422 } 2423 }
2423 //bb_error_msg("G.var_nest_level:%d", G.var_nest_level); 2424 debug_printf_env("%s: env override '%s'/%u\n", __func__, *s, G.var_nest_level);
2424 set_local_var(*s, (G.var_nest_level << SETFLAG_VARLVL_SHIFT) | SETFLAG_EXPORT); 2425 set_local_var(*s, (G.var_nest_level << SETFLAG_VARLVL_SHIFT) | SETFLAG_EXPORT);
2425 } else if (HUSH_DEBUG) { 2426 } else if (HUSH_DEBUG) {
2426 bb_error_msg_and_die("BUG in varexp4"); 2427 bb_error_msg_and_die("BUG in varexp4");
@@ -7358,6 +7359,58 @@ static void unset_func(const char *name)
7358} 7359}
7359# endif 7360# endif
7360 7361
7362static void remove_nested_vars(void)
7363{
7364 struct variable *cur;
7365 struct variable **cur_pp;
7366
7367 cur_pp = &G.top_var;
7368 while ((cur = *cur_pp) != NULL) {
7369 if (cur->var_nest_level <= G.var_nest_level) {
7370 cur_pp = &cur->next;
7371 continue;
7372 }
7373 /* Unexport */
7374 if (cur->flg_export) {
7375 debug_printf_env("unexporting nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
7376 bb_unsetenv(cur->varstr);
7377 }
7378 /* Remove from global list */
7379 *cur_pp = cur->next;
7380 /* Free */
7381 if (!cur->max_len) {
7382 debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
7383 free(cur->varstr);
7384 }
7385 free(cur);
7386 }
7387}
7388
7389static void enter_var_nest_level(void)
7390{
7391 G.var_nest_level++;
7392 debug_printf_env("var_nest_level++ %u\n", G.var_nest_level);
7393
7394 /* Try: f() { echo -n .; f; }; f
7395 * struct variable::var_nest_level is uint16_t,
7396 * thus limiting recursion to < 2^16.
7397 * In any case, with 8 Mbyte stack SEGV happens
7398 * not too long after 2^16 recursions anyway.
7399 */
7400 if (G.var_nest_level > 0xff00)
7401 bb_error_msg_and_die("fatal recursion (depth %u)", G.var_nest_level);
7402}
7403
7404static void leave_var_nest_level(void)
7405{
7406 G.var_nest_level--;
7407 debug_printf_env("var_nest_level-- %u\n", G.var_nest_level);
7408 if (HUSH_DEBUG && (int)G.var_nest_level < 0)
7409 bb_error_msg_and_die("BUG: nesting underflow");
7410
7411 remove_nested_vars();
7412}
7413
7361# if BB_MMU 7414# if BB_MMU
7362#define exec_function(to_free, funcp, argv) \ 7415#define exec_function(to_free, funcp, argv) \
7363 exec_function(funcp, argv) 7416 exec_function(funcp, argv)
@@ -7392,7 +7445,7 @@ static void exec_function(char ***to_free,
7392 7445
7393 /* "we are in a function, ok to use return" */ 7446 /* "we are in a function, ok to use return" */
7394 G_flag_return_in_progress = -1; 7447 G_flag_return_in_progress = -1;
7395 G.var_nest_level++; 7448 enter_var_nest_level();
7396 IF_HUSH_LOCAL(G.func_nest_level++;) 7449 IF_HUSH_LOCAL(G.func_nest_level++;)
7397 7450
7398 /* On MMU, funcp->body is always non-NULL */ 7451 /* On MMU, funcp->body is always non-NULL */
@@ -7412,53 +7465,6 @@ static void exec_function(char ***to_free,
7412# endif 7465# endif
7413} 7466}
7414 7467
7415static void enter_var_nest_level(void)
7416{
7417 G.var_nest_level++;
7418 debug_printf_env("var_nest_level++ %u\n", G.var_nest_level);
7419
7420 /* Try: f() { echo -n .; f; }; f
7421 * struct variable::var_nest_level is uint16_t,
7422 * thus limiting recursion to < 2^16.
7423 * In any case, with 8 Mbyte stack SEGV happens
7424 * not too long after 2^16 recursions anyway.
7425 */
7426 if (G.var_nest_level > 0xff00)
7427 bb_error_msg_and_die("fatal recursion (depth %u)", G.var_nest_level);
7428}
7429
7430static void leave_var_nest_level(void)
7431{
7432 struct variable *cur;
7433 struct variable **cur_pp;
7434
7435 cur_pp = &G.top_var;
7436 while ((cur = *cur_pp) != NULL) {
7437 if (cur->var_nest_level < G.var_nest_level) {
7438 cur_pp = &cur->next;
7439 continue;
7440 }
7441 /* Unexport */
7442 if (cur->flg_export) {
7443 debug_printf_env("unexporting nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
7444 bb_unsetenv(cur->varstr);
7445 }
7446 /* Remove from global list */
7447 *cur_pp = cur->next;
7448 /* Free */
7449 if (!cur->max_len) {
7450 debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
7451 free(cur->varstr);
7452 }
7453 free(cur);
7454 }
7455
7456 G.var_nest_level--;
7457 debug_printf_env("var_nest_level-- %u\n", G.var_nest_level);
7458 if (HUSH_DEBUG && (int)G.var_nest_level < 0)
7459 bb_error_msg_and_die("BUG: nesting underflow");
7460}
7461
7462static int run_function(const struct function *funcp, char **argv) 7468static int run_function(const struct function *funcp, char **argv)
7463{ 7469{
7464 int rc; 7470 int rc;
@@ -7648,6 +7654,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7648 G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */ 7654 G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */
7649#else 7655#else
7650 G.shadowed_vars_pp = &nommu_save->old_vars; 7656 G.shadowed_vars_pp = &nommu_save->old_vars;
7657 G.var_nest_level++;
7651#endif 7658#endif
7652 set_vars_and_save_old(new_env); 7659 set_vars_and_save_old(new_env);
7653 G.shadowed_vars_pp = sv_shadowed; 7660 G.shadowed_vars_pp = sv_shadowed;
@@ -8522,6 +8529,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
8522 while (cmd_no < pi->num_cmds) { 8529 while (cmd_no < pi->num_cmds) {
8523 struct fd_pair pipefds; 8530 struct fd_pair pipefds;
8524#if !BB_MMU 8531#if !BB_MMU
8532 int sv_var_nest_level = G.var_nest_level;
8525 volatile nommu_save_t nommu_save; 8533 volatile nommu_save_t nommu_save;
8526 nommu_save.old_vars = NULL; 8534 nommu_save.old_vars = NULL;
8527 nommu_save.argv = NULL; 8535 nommu_save.argv = NULL;
@@ -8615,6 +8623,8 @@ static NOINLINE int run_pipe(struct pipe *pi)
8615 /* Clean up after vforked child */ 8623 /* Clean up after vforked child */
8616 free(nommu_save.argv); 8624 free(nommu_save.argv);
8617 free(nommu_save.argv_from_re_execing); 8625 free(nommu_save.argv_from_re_execing);
8626 G.var_nest_level = sv_var_nest_level;
8627 remove_nested_vars();
8618 add_vars(nommu_save.old_vars); 8628 add_vars(nommu_save.old_vars);
8619#endif 8629#endif
8620 free(argv_expanded); 8630 free(argv_expanded);