diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-09 19:05:11 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-09 19:05:11 +0200 |
commit | 9db344a0f4ed5f6f893940b734215d05e48320e9 (patch) | |
tree | da03d9e54ffafbc22c3d4c795c82e872290fbc63 /shell/hush.c | |
parent | eb0de05d682b28fcf7465358ea31cf8574c1221b (diff) | |
download | busybox-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.c | 108 |
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 | ||
7362 | static 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 | |||
7389 | static 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 | |||
7404 | static 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 | ||
7415 | static 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 | |||
7430 | static 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 | |||
7462 | static int run_function(const struct function *funcp, char **argv) | 7468 | static 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); |