|Anonymous | Login||2021-01-16 06:20 UTC|
|Main | My View | View Issues | Change Log | Docs|
|Viewing Issue Simple Details|
|ID||Category||Severity||Type||Date Submitted||Last Update|
|0001435||[1003.1(2016/18)/Issue7+TC2] System Interfaces||Objection||Error||2020-12-15 14:50||2020-12-16 02:08|
|Final Accepted Text|
|Summary||0001435: execlp and execvp should not execute a command interpreter when other members of the exec family would fail with ENOEXEC|
When execve would fail for a particular process image file and set errno to [ENOEXEC], execlp and execvp are specified to retry execution of that file as-if it were a shell script (see the text quoted as to-be-deleted, under "Desired Action").
This behavior exists only for historical reasons -- it predates the `#!` mechanism implemented by all current-generation Unixes -- and *may* constitute a security hole. On the computer where I'm typing this, the first eight bytes of a machine-code executable are consistently 7f 45 46 02 01 01 00. The behavior of `sh` when fed a file beginning with these bytes is not specified, as far as I can tell; I have observed at least one implementation which, when given an input file containing those eight bytes, attempts to execute a program whose name is "\177ELF\002\001\001" (C string notation). Suppose an unprivileged process that can create a program with that name in a location on a higher-privileged process's PATH. The higher-privileged process is believed only to run programs with known names, but one of the programs with a known name is corrupt and will be rejected by `execve` with ENOEXEC, causing `execvp` to attempt to run it as a shell script, and in turn to execution of the injected program named "\177ELF\002\001\001".
Yes, this exploit chain involves a questionable implementation of `sh` *and* two different system misconfigurations, but I think we all know that vendors will try to argue that each of those three things is harmless and does not need fixing.
From <https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html>, [^] delete all of the following text from the DESCRIPTION section:
There are two distinct ways in which the contents of the process image file may cause the execution to fail, distinguished by the setting of errno to either [ENOEXEC] or [EINVAL] (see the ERRORS section). In the cases where the other members of the exec family of functions would fail and set errno to [ENOEXEC], the execlp() and execvp() functions shall execute a command interpreter and the environment of the executed command shall be as if the process invoked the sh utility using execl() as follows:
execl(<shell path>, arg0, file, arg1, ..., (char *)0);
where <shell path> is an unspecified pathname for the sh utility, file is the process image file, and for execvp(), where arg0, arg1, and so on correspond to the values passed to execvp() in argv, argv, and so on.
Also, in the ERRORS section, move the entry for [ENOEXEC] to the first group of errors ("The exec functions shall fail if: ...")
|Tags||No tags attached.|
There is no point changing execlp() and execvp() as there are many other ways that a shell can be invoked to try to execute such a file (e.g. system(), popen(), or just interactive use of a shell). The right place to deal with the issue is in the shell, and this was done in bug 0001226.
However, looking again at 1226 I see that there are two occurrences of the text that it fixes, and it only fixes one of them. Since that bug has already been applied, we should use this new bug as an opportunity to fix the other one.
On page 2368 line 75615 section 184.108.40.206, change:
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.to:
The shell may apply a heuristic check to determine if the file to be executed could be a script and may bypass this command execution if it determines that the file cannot be a script. In this case, it shall write an error message, and shall return an exit status of 126.
|The other C-level APIs you mention, system and popen, are expected to invoke a shell. The exec family, on the other hand, is expected *not* to invoke a shell. I think it is worth changing execlp and execvp just to eliminate this corner case where a shell might be invoked, contrary to expectations.|
Re Note: 0005174
No, only execl, execle, execv, and execve are expected not to invoke a shell. The execlp and execvp functions have always invoked a shell if the file cannot be executed directly and are very much expected to do so. Changing this would break a huge number of applications which rely on them executing a shell in cases where the shell script does not start with #! or the system does not support #!, including every strictly conforming application that includes a shell script to be executed using execlp or execvp (since strictly conforming applications cannot use #!)
|If you would prefer a more practical rationale for the proposed change, consider a program (a test suite driver, for instance) that wants to execute binaries that may have been cross-compiled and therefore may not be executable on the system where it's running, and distinguish ENOEXEC-type failure from other forms of failure. It runs on a wide variety of systems and therefore cannot rely on any binary-rejection heuristic being implemented by the shell. The only alternative is to avoid using execlp and execvp, but this means reimplementing PATH search by hand, and depending on the implementation language, it may not even be possible. (For instance, the Perl interpreter *only* exposes execvp and system to Perl programs.)|
|On a closely related note, why on earth hasn't #! been standardized? I have *never* encountered a system that claims POSIX conformance but doesn't implement it, not even 25 years ago.|
> Changing this would break a huge number of applications
Please give one example of such an application.
Those interfaces support the idea a utility may be implemented as a binary or a script, with binaries having attempt priority. The #! concept is an adjunct to this, not a replacement. It is for hardware and configuration dependant reasons like in the description why #! is precluded by the standard, however. There was a request to add it, a few years ago, and the issues discussed for rejecting it include factors out of scope for the standard.
It is also on the shell to provide a heuristic that recognizes sequences like in the description as being non-text, as the specified behavior, and reject processing it, per bug 1226. This is the same as the binary loader is expected to reject binaries for an incompatible processor. If it doesn't do this adequately it is a bug in that shell or loader, that I see, not a standard defect.
edited on: 2020-12-16 02:18
As a read-only member on the mailing list who currently supervises the security logic of the web app deployed on our Linux server, I totally agree this is a serious potential security exploit.
I suggest a moderate modification. That is:
> execlp() and execvp() functions shall execute a command interpreter ...
> execlp() and execvp() functions may execute the "sh" command interpreter ...
This would allow implementations with additional access control deny certain scripts with say "security flags" attached to them when they're fetched from network or scanned by anti-virus software.
|2020-12-15 14:50||zackw||New Issue|
|2020-12-15 14:50||zackw||Name||=> Zack Weinberg|
|2020-12-15 14:50||zackw||Organization||=> GNU|
|2020-12-15 14:50||zackw||Section||=> exec|
|2020-12-15 14:50||zackw||Page Number||=> (unknown)|
|2020-12-15 14:50||zackw||Line Number||=> (unknown)|
|2020-12-15 15:22||geoffclare||Note Added: 0005173|
|2020-12-15 15:22||geoffclare||Relationship added||related to 0001226|
|2020-12-15 15:31||zackw||Note Added: 0005174|
|2020-12-15 15:45||geoffclare||Note Added: 0005175|
|2020-12-15 15:53||zackw||Note Added: 0005176|
|2020-12-15 15:54||zackw||Note Added: 0005177|
|2020-12-15 15:56||zackw||Note Added: 0005178|
|2020-12-15 16:11||shware_systems||Note Added: 0005179|
|2020-12-16 02:08||dannyniu||Note Added: 0005180|
|2020-12-16 02:18||dannyniu||Note Edited: 0005180|
|Mantis 1.1.6[^] Copyright © 2000 - 2008 Mantis Group|