> Given the code we've found that depends on NULL argv, I think we likely can't make the change outright, so we're down this weird rabbit hole of trying to reject what we can and create work-around behaviors for the cases that currently exist.
> Given the code we've found that depends on NULL argv, I think we likely can't make the change outright, so we're down this weird rabbit hole of trying to reject what we can and create work-around behaviors for the cases that currently exist.
It really isn't a kernel problem at all, of course.
The POSIX spec says "The first argument, argv[0], is required and must contain the name of the executable file for the new process image."[1] Linux is not fully POSIX-compliant, but it generally follows the POSIX standard for kernel calls defined in POSIX.
FreeBSD's man page says "At least one argument must be present in the array; by custom, the first element should be the name of the executed program (for example, the last component of path)."[2] So, "must", compatible with the POSIX spec.
QNX implements the POSIX API, pretty much per the spec. The QNX spec says: "The value in argv[0] must point to a filename that's associated with the process being started."[4] So, "must", again compatible with the spec.
The Linux man page says, unfortunately, "By convention, the first of these strings (i.e., argv[0]) should contain the filename associated with the file being executed."[3] That's the problem. POSIX says "must" but the Linux page only says "should". That was a mistake.
One somewhat kludgy fix would be to disallow argv[0] == NULL && envp[0] != NULL. That allows launching a program with no args at all, which might be used somewhere in some ancient program, while disallowing launch with no command line args but with environment args, which is probably a bug.
(I liked the QNX approach to program loading. The kernel isn't involved. The "exec" functions link to a shared object, which requests memory and does the loading using regular I/O operations. The kernel contains no loader and is thus immune to problems from malformed executables.)
[1] https://support.sas.com/documentation/onlinedoc/sasc/doc750/...
[2] https://manpages.debian.org/unstable/freebsd-manpages/execve...
[3] https://www.man7.org/linux/man-pages/man2/execve.2.html
[4] https://www.qnx.com/developers/docs/6.4.0/neutrino/lib_ref/e...
"The arguments represented by arg0,... are pointers to null-terminated character strings. These strings shall constitute the argument list available to the new process image. The list is terminated by a null pointer. The argument arg0 should point to a filename string that is associated with the process being started by one of the exec functions."
"The argument argv is an array of character pointers to null-terminated strings. The application shall ensure that the last member of this array is a null pointer. These strings shall constitute the argument list available to the new process image. The value in argv[0] should point to a filename string that is associated with the process being started by one of the exec functions."
[1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/e...
I don't agree with your reading that argv being non-NULL is a "should."
The POSIX Specification does not say "The value in argv[0] should exist" it says "The value in argv[0] should point to a filename string..."
The value existing is a foundational assumption in the specification. It is therefore required.
(This is consistent with the fact that it's explicitly required that argv[argc] == NULL, which necessarily means that argv != NULL. Consider this: https://pastebin.com/1gieMqEd If argv is NULL, then pointer arithmetic on it and dereferencing it is undefined behavior, and cannot possibly conform to the guarantee.)
Edit: delete commentary
https://github.com/freebsd/freebsd-src/commit/773fa8cd136a57...
It's worth noting that as far as changes in FreeBSD forbidding long-standing permitted behavior goes, this one was notably very uncontroversial.
> The manpage has contained the following verbiage on the matter for just
> under 31 years:
>
> "At least one argument must be present in the array"
(edit: found an answer here: https://lwn.net/ml/linux-kernel/5e963fab-88d4-2039-1cf4-6661...)
multicall programs will try to use argv[0] and might crash in this scenario. If we're going to fake an argv, I guess we should try to do it right.