[Python-Dev] Re: Two patches for the new subprocess module

Nick Craig-Wood nick at craig-wood.com
Wed Nov 24 10:55:37 CET 2004


On Tue, Nov 23, 2004 at 12:47:37PM -0800, Russell E. Owen wrote:
> In article <20041123150846.GA22827 at craig-wood.com>,
>  Nick Craig-Wood <nick at craig-wood.com> wrote:
> 
> > I have submitted two patches for the subprocess module against cvs
> > HEAD.  The first notifies the user of a common mistake...
> >
> > subprocess has a very easy to mistake error in it - forgetting to pass
> > the command as a list.... with the patch...
> > 
> > >>> subprocess.call("ls", "-l")
> > Traceback (most recent call last):
> >   File "<stdin>", line 1, in ?
> >   File "subprocess.py", line 428, in call
> >     return Popen(*args, **kwargs).wait()
> >   File "subprocess.py", line 508, in __init__
> >     raise TypeError("bufsize must be an integer - "
> > TypeError: bufsize must be an integer - did you forget to pass your arguments 
> > in a list?
> 
> I hope you didn't totally eliminate the ability for Popen and call to 
> accept args as a string? It is a useful feature and one I've been using.

No, you can still pass *ONE* string as an arg, and that works fine.
If you attempt to pass two (not in a list) it raises an exception as
above.

If you pass two arguments to Popen() or call() the second actually
sets the buffer size...

> If you have broken this, please consider some alternative to your patch.
> 
> Perhaps changing the default for shell to True if args is a string, 
> False if a list would suffice? I'm not sure this is really the right 
> thing to do on all platforms, but it'd be an easy fix (use shell=None in 
> the argument list and then convert it to True or False as needed).

That is a really bad idea IMHO!  Its exactly what perl does in its
system() built in function, and it is a huge source of security holes
in perl scripts.

Eg programmer writes system("prog").  Then realises that prog needs an
argument so writes system("prog $arg").  This is now a potential
security problem if $arg was supplied by a user, because this will be
interpreted by the shell.  Say the user makes $arg="blah ; rm -rf *"
then you are in trouble.  If you are thinking about security you'd
write system("prog", $arg), but the only way this error is caught in
perl is with code review.

Back to python - the subprocess module doesn't have this problem.
subprocess.call("prog "+arg) won't actually work because it won't find
the binary called "prog "+arg.  It will just throw an exception at
that point - a very definite clue to the programmer that there is a
mistake.

Eg

>>> subprocess.call("ls -l")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "subprocess.py", line 447, in call
    return Popen(*args, **kwargs).wait()
  File "subprocess.py", line 592, in __init__
    errread, errwrite)
  File "subprocess.py", line 1024, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
>>> 

Having to write

  subprocess.call("prog "+arg, shell=True)

at least should give the programmer pause for thought, and hopefully
the shorter and better

  subprocess.call(["prog", arg])

would come to mind.

-- 
Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick


More information about the Python-Dev mailing list