diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2025-08-17 05:03:41 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2025-08-17 05:03:41 +0200 |
| commit | 36f1b16b055c64e98d8982581bd06bdcd998d7cc (patch) | |
| tree | 1fac3ff0061cfc360c5f8bbbb4ac74366f65de1c | |
| parent | 1a947654b598ce3a1325d78958b3632e834a663a (diff) | |
hush: fix infinite loop expanding alias a="nice&&a"
function old new delta
parse_stream 2857 2940 +83
i_peek 55 69 +14
i_free_alias_buffer 33 37 +4
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 101/0) Total: 101 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | shell/hush.c | 51 |
1 files changed, 45 insertions, 6 deletions
diff --git a/shell/hush.c b/shell/hush.c index 1e970922e..4c6647bba 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2937,14 +2937,29 @@ static void i_prepend_to_alias_buffer(struct in_str *i, char *prepend, char ch) } i->saved_ibuf = i->p; i->p = i->albuf = xasprintf("%s%c", prepend, ch); + //bb_error_msg("albuf'%s'", i->albuf); } static void i_free_alias_buffer(struct in_str *i) { if (i->saved_ibuf) { - /* We are here if there was an alias expansion and it has ended just now */ + /* We are here if alias expansion has ended just now */ free(i->albuf); i->p = i->saved_ibuf; i->saved_ibuf = NULL; +/* We re-enable aliases only if expansion has finished, not on command boundaries. + * Example: + * alias a="nice&&a" + * a;a + * This should run "nice" and then "can't execute 'a': No such file or directory", + * then should run "nice" again and then "can't execute 'a': No such file or directory" again + * because the second "a" in alias definition must not expand (to prevent infinite expansion), + * but the "a" after ; must expand (there is no danger of infinite expansion). + * alias a="nice&&nice" + * a;a&&a + * should execute "nice" six times. + */ + debug_printf_parse("end of alias\n"); + enable_all_aliases(); } } #else @@ -3015,6 +3030,16 @@ static int i_peek(struct in_str *i) if (i->p) { /* string-based in_str, or line editing buffer, or alias buffer */ +#if ENABLE_HUSH_ALIAS + if (*i->p == '\0' && i->saved_ibuf) { + /* corner case: "an_alias&&..." expansion will have + * i->p = "<alias_expansion>&", i->saved_ibuf = "&..." + * and at the end of it, we must not return NUL, + * this would logically split && into & & during parsing. + */ + return (unsigned char)*i->saved_ibuf; + } +#endif return (unsigned char)*i->p; } @@ -6273,8 +6298,6 @@ static struct pipe *parse_stream(char **pstring, ctx.ctx_res_w = RES_MATCH; /* "we are in PATTERN)" */ } #endif - finished_cmd_reenable_aliases: - enable_all_aliases(); /* try: { an_alias; an_alias; } */ finished_cmd: /* We just finished a cmd. New one may start * with an assignment */ @@ -6282,6 +6305,14 @@ static struct pipe *parse_stream(char **pstring, debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); continue; /* get next char */ case '&': +#if ENABLE_HUSH_ALIAS + /* Check for alias expansion (only for first word of command) */ + if (G_interactive_fd && !ctx.command->argv) { + alias = word_matches_alias(&ctx); + if (alias) + goto add_to_albuf_and_get_next_char; + } +#endif if (done_word(&ctx)) goto parse_error_exitcode1; if (ctx.pipe->num_cmds == 0 && IS_NULL_CMD(ctx.command)) { @@ -6305,7 +6336,7 @@ static struct pipe *parse_stream(char **pstring, goto parse_error_exitcode1; } } - goto finished_cmd_reenable_aliases; /* try: an_alias &[&] an_alias */ + goto finished_cmd; case '|': #if ENABLE_HUSH_CASE if (ctx.ctx_res_w == RES_MATCH) { @@ -6321,6 +6352,14 @@ static struct pipe *parse_stream(char **pstring, continue; /* get next char */ } #endif +#if ENABLE_HUSH_ALIAS + /* Check for alias expansion (only for first word of command) */ + if (G_interactive_fd && !ctx.command->argv) { + alias = word_matches_alias(&ctx); + if (alias) + goto add_to_albuf_and_get_next_char; + } +#endif if (done_word(&ctx)) goto parse_error_exitcode1; if (next == '|') { /* || */ @@ -6345,7 +6384,7 @@ static struct pipe *parse_stream(char **pstring, } done_command(&ctx); } - goto finished_cmd_reenable_aliases; /* try: an_alias |[|] an_alias */ + goto finished_cmd; case '(': #if ENABLE_HUSH_CASE /* "case... in (PATTERNS)..."? */ @@ -6364,7 +6403,7 @@ static struct pipe *parse_stream(char **pstring, goto parse_error_exitcode1; debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n); heredoc_cnt += n; - goto finished_cmd_reenable_aliases; + goto finished_cmd; } case ')': #if ENABLE_HUSH_CASE |
