[PATCH] printf: more error handling

2024-01-22 Thread Grisha Levit
The size of the buffer used for printf -v is tracked in an int but this
can overflow since the buffer can be built up by multiple vsnprintf(3)
calls, each of which can append up to INT_MAX bytes to the buffer:

$ INT_MAX=$(getconf INT_MAX)
$ printf -v VAR "%$((INT_MAX-1))s%$((INT_MAX-1))s"
Bus error: 10

or when appending individual chars:

$ printf -v VAR "%$((INT_MAX-1))sXXX"
-bash: xrealloc: cannot allocate 18446744071562068032 bytes

The return value of vsnprintf(3) or printf(3) can be negative if, e.g.
the underlying write(2) call fails, or if a width or precision is out
of range.  Currently, this return value used unchecked as an offset
into vbuf:

$ printf -v VAR "%.$((INT_MAX+1))s"
heap-buffer-overflow builtins/printf.def:1253:15 in vbprintf

and added to the total when counting bytes written for the %n conversion
specifier:

$ printf "%$((INT_MAX+1))s%n" "" N
$ echo "$N"
-1

Also, skip ferror(), fflush(), and clearerr() when running with the -v
flag.


0001-printf-more-error-handling.patch
Description: Binary data


Re: ./script doesn't work in completion function

2024-01-22 Thread Martin D Kealey
Chet has since pointed out that the debugger is not involved at all.

On Mon, 22 Jan 2024, 18:17 Grisha Levit,  wrote:

>
> That's not quite what happens. These scripts get executed by forking the
> current bash process (without exec). The new shell resets its state and
> runs the script.
>

I'm broadly aware that this is what happens; however it's not impossible
that such could be handled by a short script built into the Shell, rather
than as native C code.

The debugger message is afaict an artifact of not quite resetting
> completely -- if you had extdebug on in the shell from which you ran `./b`,
> the forked shell will try to load the debugger start file (as when running
> `bash -O extdebug ./b`)
>

Okay that makes sense; I leave extdebug turned on in my interactive Shell
so that caller will report more info.

Note that the script still runs, `B` is printed.
>

Yeah I saw that.

So these are both sides effects of the same thing: not properly resetting
the Shell state when creating an interpreter for a script without a #!

-Martin

>


wait -n misses signaled subprocess

2024-01-22 Thread Steven Pelley
Hello,
I've encountered what I believe is a bug in bash's "wait -n".  wait -n
fails to return for processes that terminate due to a signal prior to
calling wait -n.  Instead, it returns 127 with an error that the
process id cannot be found.  Calling wait  (without -n) then
returns its exit code (e.g., 143).  I expect wait -n to return each
process through successive calls to wait -n, which is the case for
processes that terminate in other manners even prior to calling wait
-n.  Killing a process while the wait -n is actively blocking works
correctly.  Test script at bottom.

The specific situation I encountered this is when trying to coordinate
my own cooperative exit and handling/propagating SIGTERM.  If I
propagate this SIGTERM by killing multiple processes at once (kill
pid1 pid2 pid3 ...) the next call to wait -n will return 143 and
indicate a pid (via -p) but the next call to wait -n returns 127 as
all processes previously terminated.  If any of the awaited processes
haven't yet terminated then you only discover the previously-killed
process whenever the next terminates.  I have workarounds/I'm not
blocked but this seems a reasonable use case and worth sharing.

I've tried:
killing with SIGTERM and SIGALRM
killing from the test script, a subshell, and another terminal.  I
don't believe this is related to kill being a builtin.
enabling job control (set -m)
bash versions 4.4.12, 5.2.15, 5.2.21.  All linux arm64

Test script:
# change to test other signals
sig=TERM

echo "TEST: KILL PRIOR TO wait -n @${SECONDS}"
{ sleep 1; exit 1; } &
pid=$!
echo "kill -$sig $pid @${SECONDS}"
kill -$sig $pid

sleep 2
wait -n $pid
echo "wait -n $pid return code $? @${SECONDS} (BUG)"
wait $pid
echo "wait $pid return code $? @${SECONDS}"

echo "TEST: KILL DURING wait -n @${SECONDS}"
{ sleep 2; exit 1; } &
pid=$!
{ sleep 1; echo "kill -$sig $pid @${SECONDS}"; kill -$sig $pid; } &

wait -n $pid
echo "wait -n $pid return code $? @${SECONDS}"
wait $pid
echo "wait $pid return code $? @${SECONDS}"


For which I get the following example output:
TEST: KILL PRIOR TO wait -n @0
kill -TERM 1384 @0
./test.sh: line 14:  1384 Terminated  { sleep 1; exit 1; }
wait -n 1384 return code 127 @2 (BUG)
wait 1384 return code 143 @2
TEST: KILL DURING wait -n @2
kill -TERM 1402 @3
./test.sh: line 25:  1402 Terminated  { sleep 2; exit 1; }
wait -n 1402 return code 143 @3
wait 1402 return code 143 @3

I expect the line ending (BUG) to indicate a return code of 143.

Thanks,
Steve Pelley



Re: ./script doesn't work in completion function

2024-01-22 Thread Chet Ramey

On 1/22/24 8:02 AM, Oğuz wrote:

On Mon, Jan 22, 2024 at 3:25 PM Greg Wooledge  wrote:

But in any case, writing a "script" without a shebang and then counting
on the shell to work around the broken script is not ideal.

Unlike shebangs that behavior is standardized. Which is what I
consider ideal. Thanks for your input


For those who are wondering:

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01_01

"If the execl() function fails due to an error equivalent to the [ENOEXEC]
error defined in the System Interfaces volume of POSIX.1-2017, the shell
shall execute a command equivalent to having a shell invoked with the
pathname resulting from the search as its first operand, with any remaining
arguments passed to the new shell, except that the value of "$0" in the new
shell may be set to the command name. If the executable file is not a text
file, the shell may bypass this command execution. In this case, it shall
write an error message, and shall return an exit status of 126."

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/



OpenPGP_signature.asc
Description: OpenPGP digital signature


Re: ./script doesn't work in completion function

2024-01-22 Thread Chet Ramey

On 1/22/24 1:53 AM, Martin D Kealey wrote:

Hi Oğuz

On Sun, 21 Jan 2024 at 03:20, Oğuz  wrote:


 $ echo echo foo bar >s
 $ chmod +x s



You seem to have created an invalid executable. It seems that scripts
without a #! can only be run with help from the debugger library;


This isn't correct. I don't know how you managed to enable debugging mode,
unless it was enabled in the interactive shell you're running, but since
you did, the subshell inherited it and attempted to start the debugger.
Scripts without a `#!' don't have anything to do with the debugger.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/



OpenPGP_signature.asc
Description: OpenPGP digital signature


Re: ./script doesn't work in completion function

2024-01-22 Thread Chet Ramey

On 1/20/24 12:20 PM, Oğuz wrote:

See:

 $ echo echo foo bar >s
 $ chmod +x s
 $ f(){ COMPREPLY=($(bash ./s));}
 $ complete -F f g
 $
 $ g
 bar  foo
 $ g ^C
 $
 $ f(){ COMPREPLY=($(./s));}
 $ g ^C^C
 $

I press tab after typing `g ' in both cases, this moves the cursor to
the right in the second case instead of showing the completion
options.


Thanks for the report. The script works, it just leaves the terminal in
icanon mode, so the tabs don't cause word completion until you hit newline.

The problem is the subshell inherits the readline state, so it can tell
whether or not the terminal is in icanon mode should it need to, but resets
it to icanon mode at exit without making sure it was the one that set it to
-icanon in the first place.

Chet

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/



OpenPGP_signature.asc
Description: OpenPGP digital signature


Re: ./script doesn't work in completion function

2024-01-22 Thread Oğuz
On Mon, Jan 22, 2024 at 3:25 PM Greg Wooledge  wrote:
> But in any case, writing a "script" without a shebang and then counting
> on the shell to work around the broken script is not ideal.
Unlike shebangs that behavior is standardized. Which is what I
consider ideal. Thanks for your input



Re: ./script doesn't work in completion function

2024-01-22 Thread Greg Wooledge
On Mon, Jan 22, 2024 at 12:17:12PM +0200, Oğuz wrote:
> On Monday, January 22, 2024, Martin D Kealey 
> wrote:
> >
> > You seem to have created an invalid executable. It seems that scripts
> > without a #! can only be run with help from the debugger library
> >
> 
> Hi Martin, POSIX shells interpret such executables as shell scripts, I
> don't think bash would take a hacky approach like that for implementing
> this basic functionality. It must be something else

Bash attempts to execute the command normally, and when the kernel
returns ENOEXEC, bash decides to try a different approach.  It opens
the file, reads a hundred or so bytes, and scans them for NUL bytes.
If it doesn't find a NUL, it forks a subshell of itself, and uses
that to read the file as a script.  If a NUL is found, bash aborts with
an error message.

Without a NUL:

unicorn:~$ printf 'echo foo' > foo
unicorn:~$ strace -f bash -c ./foo
execve("/usr/bin/bash", ["bash", "-c", "./foo"], 0x7ffe1badab60 /* 53 vars */) 
= 0
[...]
execve("./foo", ["./foo"], 0x562def3ca230 /* 53 vars */) = -1 ENOEXEC (Exec 
format error)
openat(AT_FDCWD, "./foo", O_RDONLY) = 3
read(3, "echo foo", 128)= 8
close(3)= 0
[...]

With a NUL:

unicorn:~$ printf 'echo foo\0' > foo
unicorn:~$ bash -c ./foo
bash: line 1: ./foo: cannot execute binary file: Exec format error

I don't currently have a build of bash-5.3 (prerelease) to test the
original bug report, so I can neither confirm nor deny it.

But in any case, writing a "script" without a shebang and then counting
on the shell to work around the broken script is not ideal.  You get
differing behaviors depending on which shell you're currently in.
Bash forks a subshell.  Zsh and GNU find fork /bin/sh.  Systemd will
just report the original error and will not do any workarounds.



Re: ./script doesn't work in completion function

2024-01-22 Thread Oğuz
On Monday, January 22, 2024, Martin D Kealey 
wrote:
>
> You seem to have created an invalid executable. It seems that scripts
> without a #! can only be run with help from the debugger library
>

Hi Martin, POSIX shells interpret such executables as shell scripts, I
don't think bash would take a hacky approach like that for implementing
this basic functionality. It must be something else


-- 
Oğuz


Re: ./script doesn't work in completion function

2024-01-22 Thread Grisha Levit
On Mon, Jan 22, 2024, 01:54 Martin D Kealey  wrote:

> You seem to have created an invalid executable. It seems that scripts
> without a #! can only be run with help from the debugger library;


That's not quite what happens. These scripts get executed by forking the
current bash process (without exec). The new shell resets its state and
runs the script.

$ ./b
> ./b:
>
> /home/martin/lib/bash/f3a35a2d601a55f337f8ca02a541f8c033682247/share/bashdb/bashdb-main.inc:
> No such file or directory
> ./b: warning: cannot start debugger; debugging mode disabled
> B


The debugger message is afaict an artifact of not quite resetting
completely -- if you had extdebug on in the shell from which you ran `./b`,
the forked shell will try to load the debugger start file (as when running
`bash -O extdebug ./b`)

Note that the script still runs, `B` is printed.

>