aboutsummaryrefslogtreecommitdiff
path: root/shell (follow)
Commit message (Collapse)AuthorAgeFilesLines
* ash: allow wait to handle more than 64 processeswaitforRon Yorston2026-07-161-1/+12
| | | | | | | | | | | | | | | | | | | WaitForMultipleObjects() can only handle 64 processes (actually, MAXIMUM_WAIT_OBJECTS) in a single call. Using the 'wait' shell built-in after a command like: for i in $(seq 1 70); do echo $i; sleep 10 & done resulted in an uninterruptible 'wait'. Handle processes in batches of MAXIMUM_WAIT_OBJECTS. The problem was noted by Morgan Bartlett, who also supplied a fix which I claim to have 'improved'. Adds 32-48 bytes. Signed-off-by: Ron Yorston <rmy@pobox.com>
* Merge branch 'busybox' into mergeRon Yorston2026-07-082-13/+21
|\ | | | | | | Signed-off-by: Ron Yorston <rmy@pobox.com>
| * ash: fix out-of-bounds read in ifsbreakup()Sanghyun Park2026-07-061-9/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ifsfree() does not only release allocated ifsregion nodes; it also clears the global IFS region state used by ifsbreakup(). If argstr() raises an error while expanding an argument, ash longjmps out of expandarg() before that cleanup runs, leaving stale IFS split offsets behind. A later expansion can reuse the stack for a shorter string. ifsbreakup() then sees the stale IFS state, trusts the old offsets, and can walk past the current stack block before dereferencing p. Follow dash's root-cause fix: when an expansion-related handler catches EXERROR and continues, restore the handler and call ifsfree(). Apply the cleanup to redirectsafe(), expandstr(), and evaltree(). Upstream commit: Date: Mon Dec 5 23:02:01 2022 +0800 expand: Add ifsfree to expand to fix a logic error that causes a buffer over-read On Mon, Jun 20, 2022 at 02:27:10PM -0400, Alex Gorinson wrote: > Due to a logic error in the ifsbreakup function in expand.c if a > heredoc and normal command is run one after the other by means of a > semi-colon, when the second command drops into ifsbreakup the command > will be evaluated with the ifslastp/ifsfirst struct that was set when > the here doc was evaluated. This results in a buffer over-read that > can leak the program's heap, stack, and arena addresses which can be > used to beat ASLR. > > Steps to Reproduce: > First bug: > cmd args: ~/exampleDir/example> dash > $ M='AAAAAAAAAAAAAAAAA' <note: 17 A's> > $ q00(){ > $ <<000;echo > $ ${D?$M$M$M$M$M$M} <note: 6 $M's> > $ 000 > $ } > $ q00 <note: After the q00 is typed in, the leak > should be echo'd out; this works with ash, busybox ash, and dash and > with all option args.> > > Patch: > Adding the following to expand.c will fix both bugs in one go. > (Thank you to Harald van Dijk and Michael Greenberg for doing the > heavy lifting for this patch!) > ========================== > --- a/src/expand.c > +++ b/src/expand.c > @@ -859,6 +859,7 @@ > if (discard) > return -1; > > +ifsfree(); > sh_error("Bad substitution"); > } > > @@ -1739,6 +1740,7 @@ > } else > msg = umsg; > } > +ifsfree(); > sh_error("%.*s: %s%s", end - var - 1, var, msg, tail); > } > ========================== Thanks for the report! I think it's better to add the ifsfree() call to the exception handling path as other sh_error calls may trigger this too. function old new delta restore_handler_expandarg - 33 +33 evaltree 725 711 -14 static.redirectsafe 141 124 -17 expandstr 262 242 -20 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/3 up/down: 36/-45) Total: -18 bytes Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * hush: placate warning: 'print_pfx_escaped_nl' defined but not usedDenys Vlasenko2026-05-141-0/+2
| | | | | | | | Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * hush: fix build for !HUSH_CASE configDenys Vlasenko2026-04-291-4/+4
| | | | | | | | Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
* | ash: only report background jobs in root shellRon Yorston2026-06-301-1/+1
| | | | | | | | | | | | | | | | | | | | | | Background jobs were being reported in shells other than an interactive, top-level shell. Suppress this unnecessary report. Adds 16 bytes. Signed-off-by: Ron Yorston <rmy@pobox.com>
* | ash: only copy jobtab if needed for job hackRon Yorston2026-06-301-6/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This script: #!/bin/bash ( ( true ) & ( true ) & ( true ) & ( true ) & ( true ) & ) resulted in a crash. The problem was introduced by commit 7b692ddf0c (ash: improved support for jobs built-in). This commit copies the job table into child shells for use by the 'jobs' built-in. The crash happens because when the job table is cleared in the child it becomes available for reuse. If only four jobs are required this is OK but going over four causes the table to be reallocated. This doesn't work because in the child it's in shared memory. The fix is not to pass the job table to the child unless it's required by the 'jobs' built-in. This is also more efficient. Adds 0-16 bytes. (GitHub issue #604) Signed-off-by: Ron Yorston <rmy@pobox.com>
* | ash: scan drives directly for 'pwd -a'Ron Yorston2026-06-151-8/+6
| | | | | | | | | | | | | | | | | | | | | | The shell builtin 'pwd' takes a Windows-specific '-a' option to display the current directory on each drive. Use Windows APIs directly to scan for valid drives instead of 'getmntent()'. Future changes will result in 'getmntent()' returning mounted volumes as well as drives. Signed-off-by: Ron Yorston <rmy@pobox.com>
* | ash: don't treat process substitutions as background jobsRon Yorston2026-05-311-3/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Commit bda604a70 (ash: prevent leakage of process handles) added job tracking for process substitutions. This had the unwanted side-effect that if the user tried to exit from the shell after a command involving process substitution the shell reported that background jobs were present and refused to exit. Use the flag introduced in commit e6c716317 (ash: don't report completion of process substitution) to avoid this. Adds 16 bytes. (GitHub issue #587) Signed-off-by: Ron Yorston <rmy@pobox.com>
* | ash: read built-in should respect stty -echoRon Yorston2026-05-241-1/+11
| | | | | | | | | | | | | | | | | | | | | | | | If echo has been disabled by the command 'stty -echo' the shell 'read' built-in should match its behaviour on Linux and not echo keyboard input. Adds 32-48 bytes. (GitHub issue #594) Signed-off-by: Ron Yorston <rmy@pobox.com>
* | ash: don't report completion of process substitutionRon Yorston2026-05-171-2/+20
| | | | | | | | | | | | | | | | | | | | | | | | | | Commit bda604a70 (ash: prevent leakage of process handles) added job tracking for process substitutions. This had the unwanted side-effect that the completion of such processes was then reported in interactive shells. Set a flag in such jobs so their completion isn't reported. Adds 32 bytes. (GitHub issue #587)
* | ash: prevent leakage of process handlesRon Yorston2026-05-131-4/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | When the shell invoked process substitution it retained a process handle to the child. These handles could accumulate without limit. The shell in upstream BusyBox doesn't bother to create a job structure for process substitutions or here documents. This isn't appropriate on Windows, where we need to track the child process handles. Create job structures as required. Saves 32-48 bytes. (GitHub issue #587)
* | ash: further fixes to merge of upstream changesFRP-6075-g169694ebdRon Yorston2026-05-061-24/+60
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Commits e23652908 and 686a0803f (ash: fix execution of applets via Unix-style path) were necessary following a major revision of the shell upstream. Another problem was found: $ sh $ PATH="/usr/bin;$PATH" exec non-existent resulted in a segfault. This happened because during a PATH search tryexec() modified argv[0] when it detected a Unix-style path (in this case '/usr/bin/non-existent') but failed to restore it if the execution failed. There were other issues: - The logic of the new code failed to match the original: the test for a Unix-style path should only have happened if an attempt to execute the full path had already failed. - The test for a script running an interpreter which is an applet also modified argv. If the execution failed argv should have been restored to its original state. - During a PATH search the 'path' pointer walked through the elements of the path. This pointer was also used to determine if an applet was overridden by an executable. This is wrong: the full PATH variable should have been used. The code around tryexec()/shellexec() has been rewritten to take these issues into account. Adds 32-48 bytes. (GitHub issue #584)
* | ash: fix build failure if SH_STANDALONE is disabledRon Yorston2026-05-051-0/+4
| | | | | | | | | | | | | | | | It wasn't possible to build ash if FEATURE_SH_STANDALONE was disabled. This issue was introduced during the large merge of upstream changes to ash in commit e23652908.
* | Merge branch 'busybox' into mergeRon Yorston2026-03-111-18/+8
|\|
| * ash: fix here strings causing segfault in function invocationRon Yorston2026-03-091-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | The size of the NFROMSTR struct wasn't initialised in the nodesize array, so we got: $ ./busybox sh $ f() { cat <<< hello; } $ f Segmentation fault (core dumped) ./busybox sh Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: fix help builtin and tab completion of builtinsRon Yorston via busybox2026-02-281-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Commit 56143ea63 (ash: code shrink: eliminate pstrcmp1()) changed the layout of struct builtincmd so the name member points to the start of the name, not the flag in the first element of the string. This broke the help builtin and tab completion of builtins. Remove the unnecessary '+ 1' in ash_command_name() and helpcmd(). ash_command_name 92 91 -1 helpcmd 106 102 -4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-5) Total: -5 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * *: placate warnings where strchr/strstr returns constant pointerDenys Vlasenko2026-02-151-7/+7
| | | | | | | | | | | | | | | | | | Newer glibc is now smarter and can propagate const-ness from those! function old new delta readtoken1 3111 3108 -3 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
* | ash: fix here strings causing segfault in subshellsRon Yorston2026-03-041-0/+3
| | | | | | | | | | | | | | | | A here string in a subshell or function invocation caused a SEGV. This was due to an upstream bug: the size of the NFROMSTR struct wasn't initialised in the nodesize array. (GitHub issue #567)
* | ash: allow execution of busybox-w32 binary without extensionRon Yorston2026-02-251-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If the busybox-w32 binary didn't have an extension the shell was unable to spawn itself: $ ls -l busybox -rwxrwxr-x 1 rmy rmy 661006 Feb 25 09:37 busybox $ ./busybox sh $ ls sh: unable to spawn shell This happened because the shell used spawnve() from the C runtime to execute itself. Microsoft insists on trying to add an extension to the name of the binary unless it has an explicit '.' as its last character. Use the internal spawnveq() instead, as it handles various quirks like the above. Adds 16-32 bytes. (GitHub issue #566)
* | ash: fix execution of applets via Unix-style pathRon Yorston2026-02-141-18/+15
| | | | | | | | | | | | | | | | | | Merging of upstream changes to ash failed to ensure that applets could be executed using a Unix-style path. Move the necessary code from shellexec() to tryexec(). (GitHub issue #565)
* | Merge branch 'busybox' into mergeRon Yorston2026-02-122-5/+2
|\|
| * *: use is_prefixed_with() where appropriateDenys Vlasenko2026-02-071-1/+1
| | | | | | | | | | | | | | | | | | | | | | function old new delta resume_main 560 556 -4 uuidcache_check_device 107 101 -6 ntp_init 1005 997 -8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-18) Total: -18 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * *: use xasprintf_inplace() in more placesDenys Vlasenko2026-02-061-4/+1
| | | | | | | | | | | | | | | | | | | | | | | | function old new delta .rodata 107009 107018 +9 parse_stream 3075 3069 -6 buffer_print 612 603 -9 expand_args 159 144 -15 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: 9/-30) Total: -21 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
* | ash: fix help builtin and tab completion of builtinsRon Yorston2026-02-091-0/+8
| | | | | | | | | | | | | | | | | | | | | | Commit 56143ea63 (ash: code shrink: eliminate pstrcmp1()) changed the layout of struct builtincmd so the name member points to the start of the name, not the flag in the first element of the string. This broke the help builtin and tab completion of builtins. Remove the unnecessary '+ 1' in ash_command_name() and helpcmd(). This patch has been submitted upstream.
* | Merge branch 'busybox' into mergeRon Yorston2026-02-091-1281/+1366
|\|
| * ash: fix \ooo octal printout in DEBUG codeDenys Vlasenko2026-01-281-16/+12
| | | | | | | | | | | | | | function old new delta ash_main 1624 1645 +21 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: code shrink: eliminate pstrcmp1()Denys Vlasenko2026-01-281-66/+63
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | function old new delta find_command 961 963 +2 evalcommand 1631 1633 +2 hashcmd 299 300 +1 describe_command 320 321 +1 clearcmdentry 93 94 +1 cdcmd 695 696 +1 pstrcmp1 16 - -16 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 6/0 up/down: 8/-16) Total: -8 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: remove non-standard chdir builtinDenys Vlasenko2026-01-281-17/+14
| | | | | | | | | | | | | | | | | | | | function old new delta .rodata 106853 106846 -7 builtintab 352 344 -8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-15) Total: -15 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: get rid of a static in cmdlookup()/delete_cmd_entry()Denys Vlasenko2026-01-281-26/+38
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | function old new delta cmdlookup_pp - 120 +120 find_command 953 961 +8 unsetcmd 74 76 +2 hashcmd 297 299 +2 lastcmdentry 4 - -4 delete_cmd_entry 47 43 -4 cmdlookup 132 - -132 ------------------------------------------------------------------------------ (add/remove: 1/2 grow/shrink: 3/1 up/down: 132/-140) Total: -8 bytes text data bss dec hex filename 47470 8 149 47627 ba0b shell/ash.o.orig 47466 8 145 47619 ba03 shell/ash.o Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: group command hashing/searching code together, no code changesDenys Vlasenko2026-01-281-346/+351
| | | | | | | | Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: move casematch() directly to its only caller, no code changesDenys Vlasenko2026-01-271-31/+36
| | | | | | | | Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: reorder functions to reduce forward declarations, no code changesDenys Vlasenko2026-01-271-165/+156
| | | | | | | | Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: JOBSTOPPED can only be set if job control is compiled in - ↵Denys Vlasenko2026-01-271-2/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | conditionalize code which depends on it With !ASH_JOB_CONTROL: function old new delta cmdloop 363 351 -12 exitcmd 47 31 -16 .rodata 106422 106398 -24 stoppedjobs 58 - -58 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 0/3 up/down: 0/-110) Total: -110 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: reorder functions to reduce forward declarations, no code changesDenys Vlasenko2026-01-271-450/+453
| | | | | | | | Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: move applet handling out of tryexec() - making it similar to dashDenys Vlasenko2026-01-271-62/+61
| | | | | | | | | | | | | | | | | | | | function old new delta tryexec - 60 +60 shellexec 476 349 -127 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/1 up/down: 60/-127) Total: -67 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash: unset traps before entering NOEXEC programs after [v]forkDenys Vlasenko2026-01-271-7/+89
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If we don't do that, if INT trap was set, ^C will set a flag "run trap later" and _return_, which is not expected by the NOFORK! function old new delta clear_traps - 107 +107 evalcommand 1617 1631 +14 shellexec 471 476 +5 setsignal 333 327 -6 forkchild 620 480 -140 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/2 up/down: 126/-146) Total: -20 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
* | Merge branch 'busybox' into mergeRon Yorston2026-02-042-5/+17
|\|
| * ash: code shrinkDenys Vlasenko2026-01-241-0/+4
| | | | | | | | | | | | | | | | | | | | function old new delta fg_bgcmd 294 296 +2 killpg 43 - -43 ------------------------------------------------------------------------------ (add/remove: 0/2 grow/shrink: 1/0 up/down: 2/-43) Total: -41 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| * ash,hush: allow 0x in arith (bash supports it for 0x$v case when v='')Denys Vlasenko2026-01-241-5/+13
| | | | | | | | | | | | | | function old new delta parse_with_base 174 196 +22 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
* | ash: remove unnecessary conditional compilationRon Yorston2026-01-301-4/+0
| | | | | | | | | | | | | | | | Additional support for background jobs was added in commits 010abea6f and 1403d81c4. The condition ENABLE_PLATFORM_POSIX || JOBS_WIN32 in showjob() is always true. The conditional compilation can be removed.
* | ash: don't skip exec() if std streams are invalidRon Yorston2026-01-291-1/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This didn't produce the expected output when run from ash: ash -c "echo abc | sed s/a/x/" <&- In general, if the last command in the pipe read from stdin the command didn't work; if it read from file descriptor 0 (e.g. cat) it did. Closing a file descriptor caused the corresponding stream to become invalid. For performance reasons the shell in busybox-w32 runs applets without an exec(), but that results in their seeing the invalid stream from their parent. Avoid the problem by calling exec() in such cases. This causes the child process to get a new stdin stream initialised from the file descriptor. The test also applies to stdout and stderr. There's no discernable affect on performance when running the test suite. Adds 64-96 bytes. (GitHub issue #558)
* | ash: don't display ^C twiceRon Yorston2026-01-201-1/+1
| | | | | | | | | | | | | | | | | | | | Since commit f7bcc977c (ash: make ctrl-c trap handling closer to upstream) when ctrl-c was entered at an interactive prompt without a 'trap INT' in force, '^C' was echoed to the console twice. Detect this condition and avoid the duplication. Adds 16 bytes.
* | ash: Extend ARM msvcrt workaround to 32 bit ARM tooMartin Storsjö2025-12-081-1/+1
| | | | | | | | | | | | | | | | | | The fact that "environ" is not assignable goes the same for both 32 and 64 bit ARM on msvcrt - this is not an issue on UCRT as noted in c44f23f4acbbd854eccd962110e41343d8f03296. This extends the original workaround from ea8742bc1657cd0aae32ac555560c8228795488f to 32 bit ARM too.
* | ash: allow ctrl-c to interrupt read in minttyRon Yorston2025-11-231-19/+20
| | | | | | | | | | | | | | | | | | | | | | | | | | The command 'read -t 10' couldn't be interrupted by ctrl-c when ash was running in the mintty terminal emulator. This issue was introduced by commits 8e6991733 and b2901ce8e which fixed other problems with the 'read' builtin. Rearrange the code to avoid calling poll(2) in an interactive shell on Windows. (GitHub issue #547)
* | win32: use RtlGenRandom for /dev/urandomRon Yorston2025-10-093-15/+0
| | | | | | | | | | | | | | | | | | Use the (somewhat ancient) Microsoft RtlGenRandom() function to provide random data for /dev/urandom. Saves 176-240 bytes. (GitHub issue #519)
* | ash: output '^C' direct to consoleRon Yorston2025-10-081-1/+1
| | | | | | | | | | | | | | | | | | The '^C' displayed on interrupt should go directly to the console to emulate the typical behaviour of the Unix tty driver. Adds 16 bytes. (GitHub issue #531)
* | ash: output '^C' when wait builtin is interruptedRon Yorston2025-10-061-3/+13
| | | | | | | | | | | | | | When the wait builtin detects an interrupt it should print '^C' to stdout, as is done in other similar cases. Saves 16 bytes in the 64-bit build.
* | Merge branch 'busybox' into mergeRon Yorston2025-10-061-7/+3
|\|
| * ash: change procargs() to match recent dash changeDenys Vlasenko2025-09-231-7/+3
| | | | | | | | Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>