This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: POSIX semantics of PATH search in execvpe is not respected
Type: behavior Stage:
Components: Library (Lib) Versions: Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Alex Samuel, eric.smith, glondu, r.david.murray, ztane
Priority: normal Keywords:

Created on 2013-12-10 14:55 by glondu, last changed 2022-04-11 14:57 by admin.

Messages (10)
msg205819 - (view) Author: Stéphane Glondu (glondu) Date: 2013-12-10 14:55
Hello,

According to [1],

"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);"

This is not the case with os.execvp which keeps looking in PATH for other executables. To reproduce:

 1. pick some executable that exists in /usr/bin (let's say "curl")
 2. prepend to PATH a directory where you put an executable file with name "curl" and some random shell commands, without the #! line
 3. run os.execvp("curl", ["curl"])

Instead of running the #!-less shell script, /usr/bin/curl is executed. With GNU libc's execvp(), the shell script is executed. According to my interpretation of POSIX, the shell script should be executed.

[1] http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01_01

Cheers,

-- 
Stéphane
msg205850 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2013-12-10 20:10
What platform is this on? Looking quickly through posix.execve (which is what I think gets called), it looks like it just calls C's execve().

Also, what's your use case for this? I realize it might be a standard behavior, but it seems like a bad idea to me. (Not that that's a reason not to be standards compliant: I'm mostly just curious why you'd want this.)
msg205899 - (view) Author: Stéphane Glondu (glondu) Date: 2013-12-11 10:13
> What platform is this on?

I'm on Linux (Debian testing).

> Looking quickly through posix.execve (which is what I think gets called), it looks like it just calls C's execve().

Yes, but I'm talking about os.execvp, here. With the search in PATH.

> Also, what's your use case for this?

I discovered that by accident while investigating another bug...

> I realize it might be a standard behavior, but it seems like a bad idea to me.

What is the bad idea? Keep looking in subsequent directories in PATH when you find a candidate for which execve() fails? Sorry, but I beg to differ, and POSIX is on my side.
msg205900 - (view) Author: Stéphane Glondu (glondu) Date: 2013-12-11 10:14
> What is the bad idea? Keep looking in subsequent directories in PATH when you find a candidate for which execve() fails? Sorry, but I beg to differ, and POSIX is on my side.

Sorry, I meant "Stop looking in subsequent [..]".
msg205908 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2013-12-11 15:10
os.execvp calls os._execvpe which calls posix.execv which calls execv. At least that's how I think it works.
msg205909 - (view) Author: Stéphane Glondu (glondu) Date: 2013-12-11 15:23
> os.execvp calls os._execvpe which calls posix.execv which calls execv. At least that's how I think it works.

I am not contesting that. This bug is about the "search the command in PATH" part. More precisely, the fact that os.execvp continues the search after execv fails.
msg205910 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2013-12-11 15:25
I know that. This is mostly just a note to myself so I can remember what I've looked at the next time I have a few moments to look at the bug. Or, anyone else who wants to track it down.
msg279943 - (view) Author: Alex Samuel (Alex Samuel) Date: 2016-11-02 20:49
Here's a real-world case where this can cause unexpected results:  A shell script has a typo in the shebang ("#/!bin/bash") but the execute bit set.  It still runs via the C library's execvp() and also via bash (which uses execve() but reimplements the behavior) but not with Python's os.execvp().

Would there be interest in a patch that fixes this?
msg281335 - (view) Author: Antti Haapala (ztane) * Date: 2016-11-21 08:48
Someone on Stack Overflow just had a problem where their shell script would work in shell but get `OSError: [Errno 8] Exec format error` when calling it with `subprocess.call`. I'd say rather fix this (on POSIX platforms).

Why does Python do path resolving on its own anyway? Shouldn't it delegate these all to appropriate execv* variants.
msg281338 - (view) Author: Antti Haapala (ztane) * Date: 2016-11-21 09:29
While at it, another POSIX semantic that execvp doesn't support is the behaviour when `PATH` is not set, e.g. on Linux, the search path is set to '.', followed by confstr(_CS_PATH). It is debatable whether this is desired (having current directory first in search path doesn't exactly sound right, which is also acknowledged by Linux man pages: 

NOTES
       On some other systems, the default path (used when the environment
       does not contain the variable PATH) has the current working direc‐
       tory  listed after /bin and /usr/bin, as an anti-Trojan-horse mea‐
       sure.  Linux uses here the traditional "current  directory  first"
       default path.
History
Date User Action Args
2022-04-11 14:57:55adminsetgithub: 64147
2016-11-21 09:29:50ztanesetmessages: + msg281338
2016-11-21 08:48:53ztanesetnosy: + ztane
messages: + msg281335
2016-11-02 20:49:39Alex Samuelsetnosy: + Alex Samuel
messages: + msg279943
2013-12-11 15:26:00eric.smithsetmessages: + msg205910
2013-12-11 15:23:52glondusetmessages: + msg205909
2013-12-11 15:10:37eric.smithsetmessages: + msg205908
2013-12-11 10:14:42glondusetmessages: + msg205900
2013-12-11 10:13:05glondusetmessages: + msg205899
2013-12-10 20:10:42eric.smithsetnosy: + eric.smith
messages: + msg205850
2013-12-10 15:29:55r.david.murraysetnosy: + r.david.murray
2013-12-10 14:55:25glonducreate