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 <rol...@gnu.org> > Date: Sat Feb 10 10:00:27 1996 +0000 > > Sat Feb 10 04:18:48 1996 Roland McGrath <rol...@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 <rol...@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 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://listman.redhat.com/mailman/listinfo/libguestfs