Austin Group Defect Tracker

Aardvark Mark IV

Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
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
Reporter zackw View Status public  
Assigned To
Priority normal Resolution Open  
Status New  
Name Zack Weinberg
Organization GNU
User Reference
Section exec
Page Number (unknown)
Line Number (unknown)
Interp Status ---
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
Description 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.
Desired Action From <>, [^] 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[0], argv[1], 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.
Attached Files

- Relationships
related to 0001226Applied shell can not test if a file is text 

-  Notes
geoffclare (manager)
2020-12-15 15:22

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, 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.
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.
<small>Note: A common heuristic for rejecting files that cannot be a script is locating a NUL byte prior to a <newline> byte within a fixed-length prefix of the file. Since sh is required to accept input files with unlimited line lengths, the heuristic check cannot be based on line length.</small>
zackw (reporter)
2020-12-15 15:31

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.
geoffclare (manager)
2020-12-15 15:45

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 #!)
zackw (reporter)
2020-12-15 15:53

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.)
zackw (reporter)
2020-12-15 15:54

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.
zackw (reporter)
2020-12-15 15:56

> Changing this would break a huge number of applications

Please give one example of such an application.
shware_systems (reporter)
2020-12-15 16:11

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.
dannyniu (reporter)
2020-12-16 02:08
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.

- Issue History
Date Modified Username Field Change
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
Powered by Mantis Bugtracker