-
-
Notifications
You must be signed in to change notification settings - Fork 29.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deprecate os.popen() function #86807
Comments
The os.popen() function uses a shell by default which usually leads to shell injection vulnerability. It also has a weird API:
(*) see https://docs.python.org/dev/library/os.html#os.waitstatus_to_exitcode for the meaning of a "wait status". IMO the subprocess module provides better and safer alternatives with a clean API. The subprocess module already explains how to replace os.popen() with subprocess: In Python 2, os.popen() was deprecated since Python 2.6, but Python 3.0 removed the deprecation (commit dcf97b9, then commit f5a4292 extended os.popen() documentation again: bpo-6490). platform.popen() existed until Python 3.8 (bpo-35345). It was deprecated since Python 3.3 (bpo-11377). -- There is also the os.system() function which exposes the libc system() function. Should we deprecate this one as well? |
In the past, multiple os.popen() usage have been replaced with subprocess in the stdlib to prevent the risk of shell injection: By the way, there is an open issue bpo-21557 "os.popen & os.system lack shell-related security warnings". See also bpo-6490 "os.popen documentation is probably wrong" (fixed). |
os.popen() doesn't emit a ResourceWarning when close() is not called, leading to weird issues like bpo-15408. |
The pipes module uses os.popen(): The open_r() and open_w() methods of pipes.Template are implemented with os.popen(). Multiple tests still use os.popen():
And os.popen() tests:
|
About the pipes module, see bpo-41150: "... unapplicable for processing binary data and text data non-encodable with the locale encoding". |
See also bpo-26124: "shlex.quote and pipes.quote do not quote shell keywords". |
About shell injection, subprocess.getstatusoutput() uses subprocess.Popen(shell=True). It's done on purpose: "Execute the string cmd in a shell with Popen.check_output()". |
Searching os.popen in code on GitHub gives around 4.5 millions of results. Seems that most of them are with literal strings which are very specific to the program, like check2 = os.popen('grep "net\.ipv4\.ip_forward" /etc/sysctl.conf /etc/sysctl.d/*').read() They are not vulnerable to shell injection and other drawbacks of os.popen do not matter in that cases. Most of that code looks like specialized scripts rather than parts of general libraries. Yes, some examples can be vulnerable to shell injection (although in they use cases, with restricted data and environment, they can be pretty safe). But deprecating os.popen can break millions of scripts and cause more harm than prevent bugs. It may be better strategy to document drawbacks and limitations of os.popen and advertise alternatives. |
Such code leaks a zombi process when the child process completes, because the parent never reads its exit status :-( |
I created bpo-42648: "subprocess: add a helper/parameter to catch exec() OSError exception". |
This sounds like a good idea in any case ;-) |
Please don't deprecate os.system. For quick and dirty scripts used in trusted environments with trusted data, it is simple to use, effective and safe enough. |
It seems like they are legit use cases for os.popen(), so I abandon my idea of deprecating it. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: