On Wed, Mar 22, 2023 at 04:53:42PM +0100, Laszlo Ersek wrote:
...
> What is supposed to happen is this:
>
> (1) bash shall find test-execvp in the current directory per PATH,
> (2) execvp() shall find "hello.sh" in the current directory per PATH,
> (3) execvp() shall hit an internal failure -1/ENOEXEC,
> (4) execvp() shall then invoke the shell (under an unspecified pathname),
> (5) the shell shall get "foobar" for its argv[0], and "hello.sh"
for its argv[1]
> (6) we shall see "hello" on the standard output.
>
> That's exactly what happens on Linux/glibc. (Note: this result has absolutely
nothing to do with my execvpe() implementation, or libnbd in the first place.)
>
> Now, according to my above description of the busybox bug, we're tempted to
believe that step (6) fails on Alpine Linux (using musl + busybox). We expect the busybox
binary to be launched, via the /bin/sh symlink, in step (4), and we expect it to fail
after step (5), due to it not recognizing "foobar" as an "applet
name".
>
> It turns out however that step (4) does not happen. musl does not handle ENOEXEC:
It's getting crazier by the hour.
No joke.
Locally, I wrote:
$ cat foo
echo "hello from $0:$@"
$ chmod +x foo
$ bash ./foo foobar arg1
hello from ./foo:foobar arg1
$ bash -c ./foo foobar arg1
hello from ./foo:
$ bash -c 'exec -a "$0" ./foo "$@"' foobar arg1
hello from foobar:arg1
$ bash -c '. ./foo' foobar arg1
hello from foobar:arg1
The latter two match the behavior we want to see. Alas, POSIX has not
yet standardized 'exec -a', but the ability to use 'sh -c' to set
argv0, plus . to source a file as shell commands, gets us to the same
place.
I thought to create a reproducer for busybox, in spite of musl breaking down at an
earlier point (see above). For that, I *statically linked* "test-execvp" on
RHEL-9.1 (using glibc), and then executed the binary in the Alpine Linux container. This
should eliminate musl from the picture, and exercise the ENOEXEC fallback (from glibc),
invoking /bin/sh (aka busybox) under argv[0] "foobar", and trigger the
"unknown applet" bug in busybox.
However, this does not happen. Instead, I get "hello" printed. How is that
possible?
The solution is that glibc *too* has a bug, and that bug hides the busybox bug. Namely,
in glibc, going back to historical commit
commit 6a032d81581978187f562e5533a32e0a6a3d352b (tag: cvs/libc-960210)
Author: Roland McGrath <roland(a)gnu.org>
Date: Sat Feb 10 10:00:27 1996 +0000
Sat Feb 10 04:18:48 1996 Roland McGrath <roland(a)churchy.gnu.ai.mit.edu>
* posix/execvp.c: If execv fails with ENOEXEC, run the shell on
the file.
Fri Feb 9 11:46:45 1996 Roland McGrath <roland(a)churchy.gnu.ai.mit.edu>
* time/Makefile (CFLAGS-zdump.c, CFLAGS-zic.c, CFLAGS-ialloc.c,
CFLAGS-scheck.c): Use -DNOID instead of -Wno-unused.
* hurd/Makefile (user-interfaces): Added hurd/tioctl.
(note the date: 1996!), the POSIX-mandated fallback
execv(<shell path>, { argv[0], file, argv[1], ..., NULL })
is not being done. Instead, the following is done:
execv(<shell path>, { <shell path>, file, argv[1], ..., NULL })
In other words, the original argv[0] is not preserved, but is replaced by <shell
path>. (Look for _PATH_BSHELL in said historical glibc commit, and also in today's
glibc file "posix/execvpe.c".)
Wow. This is so historically old that it's probably worth asking on
the Austin Group if argv[0] must be preserved or can be changed to the
shell name, and/or whether the standard should add support for 'exec
-a argv0 cmd args' as a way to set argv[0] despite this long-standing
glibc behavior. I'll reply back when I have some URLs to list
archives of my pending questions.
This can be demonstrated with:
$ PATH=.:$PATH strace -etrace=execve test-execvp
execve("./test-execvp", ["test-execvp"], 0x7ffc0d1e5248 /* 85 vars
*/) = 0
execve("./hello.sh", ["foobar"], 0x7ffc528e14a8 /* 85 vars */) = -1
ENOEXEC (Exec format error)
execve("/bin/sh", ["/bin/sh", "./hello.sh"], 0x7ffc528e14a8
/* 85 vars */) = 0
hello
+++ exited with 0 +++
The third execve() call should be:
execve("/bin/sh", ["foobar", "./hello.sh"], 0x7ffc528e14a8
/* 85 vars */) = 0
^^^^^^^^
Laszlo
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization:
qemu.org |
libvirt.org