On 10/24/23 13:59, Oğuz via austin-group-l at The Open Group wrote:
Oğuz
On Tue, Oct 24, 2023 at 1:53 PM Jonathan Wakely <[email protected]> wrote:
On Tue, 24 Oct 2023 at 07:10, Oğuz via austin-group-l at The Open Group
<[email protected]> wrote:
On Tuesday, October 24, 2023, enh via austin-group-l at The Open Group
<[email protected]> wrote:
netbsd checks that _PATH_BSHELL is exectuable with access(2)
(but doesn't actually _execute_ anything). apple's copy of freebsd has
a local change similar to the netbsd one. glibc seems to actually try
to _run_ a shell:
```
[pid 3612818] execve("/bin/sh", ["sh", "-c", "exit 0"], 0x7fff98502fe8
```
None of those guarantee that the shell is actually gonna work. I think they all
should just return 1.
but a
POSIX system can have those kinds of features that could mean
system(3) doesn't actually work _for this process_
Such a system should provide the means for testing if a process is in that
state, and the means shouldn't involve auditing the shell executable.
Why not? Checking if you can run /bin/sh seems like the most direct and accurate way of
checking if the process can run /bin/sh. POSIX might require /bin/sh to be usable, so a
"pure POSIX" system can safely just return non-zero from system(NULL). But a
system that supports features like SELinux that aren't part of POSIX might want to do
extra checks, which wouldn't be required on a system where /bin/sh is always available.
Why require those systems to provide some other non-standard API for testing it
when system(NULL) is specified by C to do that job?
system(NULL) is specified by both C and POSIX to return whether the
host environment features a command processor or not. It's merely a
feature test, as evident from the following paragraphs from POSIX
Issue 8 draft 3 P2196 L71808-71821:
Note that, system(NULL) is required to return non-zero, indicating that there
is a command
language interpreter. At first glance, this would seem to conflict with the ISO
C standard which
allows system(NULL) to return zero. There is no conflict, however. A system
must have a
command language interpreter, and is non-conforming if none is present. It is
therefore
permissible for the system() function on such a system to implement the
behavior specified by
the ISO C standard as long as it is understood that the implementation does not
conform to
POSIX.1-202x if system(NULL) returns zero.
It was explicitly decided that when command is NULL, system() should not be
required to check
to make sure that the command language interpreter actually exists with the
correct mode, that
there are enough processes to execute it, and so on. The call system(NULL)
could, theoretically,
check for such problems as too many existing child processes, and return zero.
However, it
would be inappropriate to return zero due to such a (presumably) transient
condition. If some
condition exists that is not under the control of this application and that
would cause any
system() call to fail, that system has been rendered non-conforming.
On a system where certain users/processes can have limited/no shell
access, providing a separate interface like do_I_have_shell_access()
would be more appropriate than overloading system(NULL).
Isn't this a similar situation to e.g. `getuid`/`geteuid`/etc. failures
? I don't see the distinction between `getuid` and other associated
functions saying that they "shall always be successful and no return
value is reserved to indicate the error" and `system` stating "The
system( ) function shall always return non-zero when command is NULL." -
personally I would consider the note in `getuid`'s rationale stating:
> It is possible for implementations to provide an extension where a
process in a non-conforming environment will not be associated with a
user or group ID. It is recommended that such implementations return
`(uid_t)−1` and set errno to indicate such an environment; doing so does
not violate this standard, since such an environment is already an
extension.
to mean `system(NULL)` is allowed to check whether it is in a
non-conforming environment.