472,791 Members | 979 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,791 software developers and data experts.

Avoiding shell metacharacters in os.popen

I'm trying to avoid using shell metacharacters in os.popen in a portable
fashion.

os.popen() only seems to take a string as the command which would need
tricky quoting.

os.popen2() can take a string or a list - the relevant code in Unix
python (in popen2.py) being...

def _run_child(self, cmd):
if isinstance(cmd, basestring):
cmd = ['/bin/sh', '-c', cmd]
for i in range(3, MAXFD):
try:
os.close(i)
except OSError:
pass
try:
os.execvp(cmd[0], cmd)
finally:
os._exit(1)

This is perfect behaviour as far as I'm concerned - if you pass a list
it doesn't go through the shell and if you pass a string it does.

eg

w, r = os.popen2(["ls", "-l"])
r.read()

This leads on to my questions :-

1) is this behaviour (string vs list) of popen2 intentional? Its not
documented anywhere and it doesn't work under Windows (gives
"TypeError: popen2() argument 1 must be string, not list")

2) is there anything similar for os.popen() planned?

3) is there an equivalent to the perl quotemeta() command. This
quotes meta-characters in a string for use in the shell. Here is a
suitable definition for Unix, but I don't think that \ quoting works
in Windows

cmd = re.sub(r"(\W)", r"\\\1", cmd)

Avoiding shell metacharacter attacks is a must for secure programs.
Python does pretty well with its os.exec* and os.spawn* functions, but
seems to be lacking in the os.popen* department!

Any insights appreciated!

--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Jul 18 '05 #1
10 2820
Nick Craig-Wood wrote:
Avoiding shell metacharacter attacks is a must for secure programs.


Not passing down commands into a shell is a must for secure programs.

What you should do is recognize a command, identify it as a
valid and allowed one, then call it yourself. If you think that
escaping metacharacters gives you any kind of security you are
deceiving yourself.

Istvan.
Jul 18 '05 #2
Istvan Albert <ia*****@mailblocks.com> wrote:
Nick Craig-Wood wrote:
Avoiding shell metacharacter attacks is a must for secure programs.
Not passing down commands into a shell is a must for secure programs.

What you should do is recognize a command, identify it as a
valid and allowed one, then call it yourself.


I'm not running commands passed by the user - that would be nuts!

I'm running another program written by us. The program doing the
running is a CGI and it needs to pass parameters to the second program
which come from the user. It also needs to read the output of that
program - hence popen.

What my post was about was avoiding the shell completely. If you use
os.system(string) then you go via the shell. However if you use
os.spawnl(mode, file, *args) then it doesn't go anywhere near the
shell. As I pointed out in my post there isn't an equivalent for
os.popen* which doesn't go via the shell (except for undocumented
os.popen2).
If you think that escaping metacharacters gives you any kind of
security you are deceiving yourself.


As a second best escaping the metacharacters and using os.popen will
work, but AFAICS there isn't a portable metacharacter escaping routine
built into python.

--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Jul 18 '05 #3
In article <sl*****************@irishsea.home.craig-wood.com>,
Nick Craig-Wood <ni**@craig-wood.com> wrote:
....
What my post was about was avoiding the shell completely. If you use
os.system(string) then you go via the shell. However if you use
os.spawnl(mode, file, *args) then it doesn't go anywhere near the
shell. As I pointed out in my post there isn't an equivalent for
os.popen* which doesn't go via the shell (except for undocumented
os.popen2).


Well, it sounded to me like the real problem is that Microsoft
Windows doesn't support any functional equivalent to spawnv
for pipes. I don't know if that's true or not, I'm just
taking it from you that os.popen2 doesn't support a list of
parameters [1] on Microsoft Windows platforms, and inferring
that it doesn't because it can't - there isn't any specific
function that does it, and you can't just roll your own out
of pipe/fork/execve like you can on UNIX, as in fact popen2 does.

If that's really a question and not a well known fact, you
might pose it again with a subject line that would attract
more attention from Microsoft Windows developers, since
only they would know. The attempt to cast it as a general
Python problem could be counterproductive, if it means the
people who read about this problem tend to be those who
don't really suffer from it.

Donn Cave, do**@u.washington.edu
Jul 18 '05 #4
Nick Craig-Wood wrote:
As I pointed out in my post there isn't an equivalent for
os.popen* which doesn't go via the shell (except for undocumented
os.popen2).


Is it the undocumented nature of it that is unnerving you?

I submitted a bug on the documentation more than six months ago but no
one has responded.

http://sourceforge.net/tracker/?func...70&atid=105470
--
Michael Hoffman
Jul 18 '05 #5
Michael Hoffman <m.*********************************@example.com > wrote:
Nick Craig-Wood wrote:
As I pointed out in my post there isn't an equivalent for
os.popen* which doesn't go via the shell (except for undocumented
os.popen2).
Is it the undocumented nature of it that is unnerving you?


Yes! If it was documented then it would have to be made to work on
Windows too I gues.
I submitted a bug on the documentation more than six months ago but no
one has responded.

http://sourceforge.net/tracker/?func...70&atid=105470


At least it is in the system.

--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Jul 18 '05 #6
Donn Cave <do**@u.washington.edu> wrote:
Well, it sounded to me like the real problem is that Microsoft
Windows doesn't support any functional equivalent to spawnv for
pipes. I don't know if that's true or not,
No me neither!
I'm just taking it from you that os.popen2 doesn't support a list
of parameters [1] on Microsoft Windows platforms,
Well it didn't work when I tried it.
and inferring that it doesn't because it can't - there isn't any
specific function that does it, and you can't just roll your own
out of pipe/fork/execve like you can on UNIX, as in fact popen2
does.
It could always do " ".join(cmd) which would leave windows users
exactly where they are at the moment.

I'll probably end up writing a little wrapper to popen2 which does
something like that, possibly with a bit better quoting for windows.
If that's really a question and not a well known fact, you
might pose it again with a subject line that would attract
more attention from Microsoft Windows developers, since
only they would know. The attempt to cast it as a general
Python problem could be counterproductive, if it means the
people who read about this problem tend to be those who
don't really suffer from it.


Good point. I'll have a think about it (and a look at the Windows
source of popen2!)

--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Jul 18 '05 #7
Nick Craig-Wood <ni**@craig-wood.com> writes:
Michael Hoffman <m.*********************************@example.com > wrote:
Nick Craig-Wood wrote:
As I pointed out in my post there isn't an equivalent for
os.popen* which doesn't go via the shell (except for undocumented
os.popen2).
Is it the undocumented nature of it that is unnerving you?


Yes! If it was documented then it would have to be made to work on
Windows too I gues.


I think this might be part of the reason it's underdocumented. I also
have a sneaking suspicion it's impossible on windows, but don't really
know...

Cheers,
mwh

-- Why are we talking about bricks and concrete in a lisp newsgroup?

After long experiment it was found preferable to talking about why
Lisp is slower than C++...
-- Duane Rettig & Tim Bradshaw, comp.lang.lisp
Jul 18 '05 #8
Nick Craig-Wood wrote:
I'm trying to avoid using shell metacharacters in os.popen in a portable
fashion.

os.popen() only seems to take a string as the command which would need
tricky quoting.

os.popen2() can take a string or a list - the relevant code in Unix
python (in popen2.py) being...

def _run_child(self, cmd):
if isinstance(cmd, basestring):
cmd = ['/bin/sh', '-c', cmd]
for i in range(3, MAXFD):
try:
os.close(i)
except OSError:
pass
try:
os.execvp(cmd[0], cmd)
finally:
os._exit(1)

This is perfect behaviour as far as I'm concerned - if you pass a list
it doesn't go through the shell and if you pass a string it does.

eg

w, r = os.popen2(["ls", "-l"])
r.read()

This leads on to my questions :-

1) is this behaviour (string vs list) of popen2 intentional? Its not
documented anywhere and it doesn't work under Windows (gives
"TypeError: popen2() argument 1 must be string, not list")

2) is there anything similar for os.popen() planned?

3) is there an equivalent to the perl quotemeta() command. This
quotes meta-characters in a string for use in the shell. Here is a
suitable definition for Unix, but I don't think that \ quoting works
in Windows

cmd = re.sub(r"(\W)", r"\\\1", cmd)

Avoiding shell metacharacter attacks is a must for secure programs.
Python does pretty well with its os.exec* and os.spawn* functions, but
seems to be lacking in the os.popen* department!

Any insights appreciated!


I can't exactly remember the details but I now I've had painful
experiences on Windows trying to do this kind of thing. It seems to mess
up quoting parameters / exe file names

David
Jul 18 '05 #9
David Fraser <da****@sjsoft.com> wrote:
Nick Craig-Wood wrote:
3) is there an equivalent to the perl quotemeta() command. This
quotes meta-characters in a string for use in the shell. Here is a
suitable definition for Unix, but I don't think that \ quoting works
in Windows

cmd = re.sub(r"(\W)", r"\\\1", cmd)


I can't exactly remember the details but I now I've had painful
experiences on Windows trying to do this kind of thing. It seems to mess
up quoting parameters / exe file names


Last time I did this for Windows was in C (urk!). I put every
parameter in double quotes and then doubled up any " in the parameter.
This worked mostly but I don't think the OS parsed some bizarre cases
properly.

--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Jul 18 '05 #10
Nick Craig-Wood wrote:
David Fraser <da****@sjsoft.com> wrote:
Nick Craig-Wood wrote:
3) is there an equivalent to the perl quotemeta() command. This
quotes meta-characters in a string for use in the shell. Here is a
suitable definition for Unix, but I don't think that \ quoting works
in Windows

cmd = re.sub(r"(\W)", r"\\\1", cmd)


I can't exactly remember the details but I now I've had painful
experiences on Windows trying to do this kind of thing. It seems to mess
up quoting parameters / exe file names

Last time I did this for Windows was in C (urk!). I put every
parameter in double quotes and then doubled up any " in the parameter.
This worked mostly but I don't think the OS parsed some bizarre cases
properly.

If I recall correctly (yikes) the problem was that Python's os.system
would handle either a program name with spaces in it or a parameter with
spaces in it, but quoting them both didn't work. Anyway if someone can
get it to work nicely please post the details here :-)

David
Jul 18 '05 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

12
by: km | last post by:
hi all, can any linux command be invoked/ executed without using shell (bash) ? what abt security concerns ? regards, KM
0
by: Tom Brown | last post by:
I need to chain together three linux commands and get the final output. I read the documentation for Popen in the subprocess module for replacing the shell pipe line. I followed the example and...
4
by: jelle | last post by:
Hi, I use python quite a bit to couple different programs together. Doing so has been a _lot_ easier since subprocess came around, but would really like to be able to use the succinct shell...
2
by: Jeremy Moles | last post by:
I'm not sure if this is really the right place to ask this question, but since the implementation is in Python, I figured I'd give it a shot. I want to "wrap" a shell process using popen inside...
7
by: Bin Chen | last post by:
Hi, I want to do following: get a user input regex, then pass this as a parameter to grep, and then get the result from grep. Any code snip to implement the similar function? I am a python...
3
by: metaperl | last post by:
I downloaded a file which has a space in the filename. I want to run a shell unzip on it, but it fails in my current code: syscmd = "cd %s ; unzip %s" % (self.storage.input, file.basename())...
2
by: Gerard Flanagan | last post by:
Hello, I have a third party shell script which updates multiple environment values, and I want to investigate (and ultimately capture to python) the environment state after the script has run....
3
by: George Sakkis | last post by:
I'm trying to figure out why Popen captures the stderr of a specific command when it runs through the shell but not without it. IOW: cmd = if 1: # this captures both stdout and stderr as...
7
by: Samuel A. Falvo II | last post by:
I have a shell script script.sh that launches a Java process in the background using the &-operator, like so: #!/bin/bash java ... arguments here ... & In my Python code, I want to invoke...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
by: erikbower65 | last post by:
Using CodiumAI's pr-agent is simple and powerful. Follow these steps: 1. Install CodiumAI CLI: Ensure Node.js is installed, then run 'npm install -g codiumai' in the terminal. 2. Connect to...
0
linyimin
by: linyimin | last post by:
Spring Startup Analyzer generates an interactive Spring application startup report that lets you understand what contributes to the application startup time and helps to optimize it. Support for...
0
by: erikbower65 | last post by:
Here's a concise step-by-step guide for manually installing IntelliJ IDEA: 1. Download: Visit the official JetBrains website and download the IntelliJ IDEA Community or Ultimate edition based on...
0
by: kcodez | last post by:
As a H5 game development enthusiast, I recently wrote a very interesting little game - Toy Claw ((http://claw.kjeek.com/))。Here I will summarize and share the development experience here, and hope it...
0
by: Taofi | last post by:
I try to insert a new record but the error message says the number of query names and destination fields are not the same This are my field names ID, Budgeted, Actual, Status and Differences ...
14
DJRhino1175
by: DJRhino1175 | last post by:
When I run this code I get an error, its Run-time error# 424 Object required...This is my first attempt at doing something like this. I test the entire code and it worked until I added this - If...
0
by: Rina0 | last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
2
by: DJRhino | last post by:
Was curious if anyone else was having this same issue or not.... I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.