From 1c5455284234e894dfb6086bf7f3e9a6d5d9611f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 2 Aug 2022 11:13:44 +0200 Subject: ash: fix ifs cleanup on error paths Patch by Alex Gorinson function old new delta evalvar 477 495 +18 varvalue 603 618 +15 subevalvar 1557 1572 +15 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 48/0) Total: 48 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 ++ shell/ash_test/ash-heredoc/heredoc_and_cmd.right | 2 ++ shell/ash_test/ash-heredoc/heredoc_and_cmd.tests | 8 ++++++++ shell/hush_test/hush-heredoc/heredoc_and_cmd.right | 2 ++ shell/hush_test/hush-heredoc/heredoc_and_cmd.tests | 8 ++++++++ 5 files changed, 22 insertions(+) create mode 100644 shell/ash_test/ash-heredoc/heredoc_and_cmd.right create mode 100755 shell/ash_test/ash-heredoc/heredoc_and_cmd.tests create mode 100644 shell/hush_test/hush-heredoc/heredoc_and_cmd.right create mode 100755 shell/hush_test/hush-heredoc/heredoc_and_cmd.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index d29de37b7..c731a333b 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7028,6 +7028,7 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) msg = umsg; } } + ifsfree(); ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); } @@ -7453,6 +7454,7 @@ varvalue(char *name, int varflags, int flags, int quoted) if (discard) return -1; + ifsfree(); raise_error_syntax("bad substitution"); } diff --git a/shell/ash_test/ash-heredoc/heredoc_and_cmd.right b/shell/ash_test/ash-heredoc/heredoc_and_cmd.right new file mode 100644 index 000000000..25ae70561 --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc_and_cmd.right @@ -0,0 +1,2 @@ +./heredoc_and_cmd.tests: line 4: D: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +Y diff --git a/shell/ash_test/ash-heredoc/heredoc_and_cmd.tests b/shell/ash_test/ash-heredoc/heredoc_and_cmd.tests new file mode 100755 index 000000000..197542de7 --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc_and_cmd.tests @@ -0,0 +1,8 @@ +# The bug was only happening with < Date: Tue, 2 Aug 2022 12:41:18 +0200 Subject: ash: fix use-after-free in pattern substituon code Patch by soeren@soeren-tempel.net The idx variable points to a value in the stack string (as managed by STPUTC). STPUTC may resize this stack string via realloc(3). If this happens, the idx pointer needs to be updated. Otherwise, dereferencing idx may result in a use-after free. function old new delta subevalvar 1562 1566 +4 Signed-off-by: Denys Vlasenko --- shell/ash.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index c731a333b..105edd4c8 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7324,13 +7324,15 @@ subevalvar(char *start, char *str, int strloc, if (idx >= end) break; STPUTC(*idx, expdest); + if (stackblock() != restart_detect) + goto restart; if (quotes && (unsigned char)*idx == CTLESC) { idx++; len++; STPUTC(*idx, expdest); + if (stackblock() != restart_detect) + goto restart; } - if (stackblock() != restart_detect) - goto restart; idx++; len++; rmesc++; -- cgit v1.2.3-55-g6feb From 7c2a3bdde0a1316771fdd07ff03413f00383f70e Mon Sep 17 00:00:00 2001 From: Sören Tempel Date: Tue, 2 Aug 2022 18:23:32 +0200 Subject: ash: fix use-after-free in bash pattern substitution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit function old new delta subevalvar 1566 1564 -2 Signed-off-by: Sören Tempel Signed-off-by: Denys Vlasenko --- shell/ash.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 105edd4c8..55c1034f5 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7357,6 +7357,13 @@ subevalvar(char *start, char *str, int strloc, idx = loc; } + /* The STPUTC invocations above may resize and move the + * stack via realloc(3). Since repl is a pointer into the + * stack, we need to reconstruct it relative to stackblock(). + */ + if (slash_pos >= 0) + repl = (char *)stackblock() + strloc + slash_pos + 1; + //bb_error_msg("repl:'%s'", repl); for (loc = (char*)repl; *loc; loc++) { char *restart_detect = stackblock(); -- cgit v1.2.3-55-g6feb From 58598eb7093561d914a6254697e137b815f1fdfc Mon Sep 17 00:00:00 2001 From: Shawn Landden Date: Sat, 27 Aug 2022 19:56:21 +0200 Subject: ash: optional sleep builtin function old new delta sleepcmd - 10 +10 builtintab 352 360 +8 .rodata 105264 105271 +7 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/0 up/down: 25/0) Total: 25 bytes Signed-off-by: Shawn Landden Signed-off-by: Denys Vlasenko --- coreutils/sleep.c | 1 + include/libbb.h | 1 + libbb/duration.c | 6 ++++++ shell/ash.c | 11 +++++++++++ 4 files changed, 19 insertions(+) (limited to 'shell') diff --git a/coreutils/sleep.c b/coreutils/sleep.c index 2658e84df..442841210 100644 --- a/coreutils/sleep.c +++ b/coreutils/sleep.c @@ -37,6 +37,7 @@ //applet:IF_SLEEP(APPLET(sleep, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_SLEEP) += sleep.o +//kbuild:lib-$(CONFIG_ASH_SLEEP) += sleep.o /* BB_AUDIT SUSv3 compliant */ /* BB_AUDIT GNU issues -- fancy version matches except args must be ints. */ diff --git a/include/libbb.h b/include/libbb.h index abbc9ac59..19ed9ec09 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1510,6 +1510,7 @@ int ash_main(int argc, char** argv) IF_SHELL_ASH(MAIN_EXTERNALLY_VISIBLE); int hush_main(int argc, char** argv) IF_SHELL_HUSH(MAIN_EXTERNALLY_VISIBLE); /* If shell needs them, they exist even if not enabled as applets */ int echo_main(int argc, char** argv) IF_ECHO(MAIN_EXTERNALLY_VISIBLE); +int sleep_main(int argc, char **argv) IF_SLEEP(MAIN_EXTERNALLY_VISIBLE); int printf_main(int argc, char **argv) IF_PRINTF(MAIN_EXTERNALLY_VISIBLE); int test_main(int argc, char **argv) #if ENABLE_TEST || ENABLE_TEST1 || ENABLE_TEST2 diff --git a/libbb/duration.c b/libbb/duration.c index a6a29ddae..793d02f42 100644 --- a/libbb/duration.c +++ b/libbb/duration.c @@ -76,6 +76,12 @@ void FAST_FUNC sleep_for_duration(duration_t duration) ts.tv_sec = duration; ts.tv_nsec = (duration - ts.tv_sec) * 1000000000; } + /* NB: if ENABLE_ASH_SLEEP, we end up here if "sleep N" + * is run in ash. ^C will still work, because ash's signal handler + * does not return (it longjumps), the below loop + * will not continue looping. + * (This wouldn't work in hush) + */ do { errno = 0; nanosleep(&ts, &ts); diff --git a/shell/ash.c b/shell/ash.c index 55c1034f5..326f8b2a9 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -134,6 +134,11 @@ //config: default y //config: depends on SHELL_ASH //config: +//config:config ASH_SLEEP +//config: bool "sleep builtin" +//config: default y +//config: depends on SHELL_ASH +//config: //config:config ASH_HELP //config: bool "help builtin" //config: default y @@ -10155,6 +10160,9 @@ static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, #if ENABLE_ASH_TEST || BASH_TEST2 static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } #endif +#if ENABLE_ASH_SLEEP +static int FAST_FUNC sleepcmd(int argc, char **argv) { return sleep_main(argc, argv); } +#endif /* Keep these in proper order since it is searched via bsearch() */ static const struct builtincmd builtintab[] = { @@ -10217,6 +10225,9 @@ static const struct builtincmd builtintab[] = { { BUILTIN_SPEC_REG "return" , returncmd }, { BUILTIN_SPEC_REG "set" , setcmd }, { BUILTIN_SPEC_REG "shift" , shiftcmd }, +#if ENABLE_ASH_SLEEP + { BUILTIN_REGULAR "sleep" , sleepcmd }, +#endif #if BASH_SOURCE { BUILTIN_SPEC_REG "source" , dotcmd }, #endif -- cgit v1.2.3-55-g6feb