[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [MiNT] popen()/pclose() and the pipes?



Hi!

On Wed, Jul 25, 2001 at 11:53:30PM +0200, you wrote:
> Besides, I realised that I can't pass a command line to the popen'ed
> program. That's useless.

Sorry? From popen()'s manpage:

-- snip --
       The  command  argument  is  a pointer to a null-terminated
       string containing a shell command line.  This  command  is
       passed  to  /bin/sh  using the -c flag; interpretation, if
       any, is performed by the shell.  The mode  argument  is  a
       pointer  to  a null-terminated string which must be either
       `r' for reading or `w' for writing.
-- snap --

So, calling

popen("ls -lF", "r")

will return a FILE pointer to a pipe connected with the command "ls
-lF", thus reading from it will return a directory listing.

This also is one of the dangerous features of popen() (and system() as
well), as it will pass the command to sh -c. That means you must never
use it to call popen() with (unfiltered) user supplied data (at least
not in suid-binaries or other stuff where the user supplying the data is
not the same as the user running the program, e.g. in CGIs).

For example, a common mistake in CGIs using popen() to sendmail to send
an email is doing the following:

snprintf(buffer, sizeof(buffer), "/usr/lib/sendmail -oi %s", email);
sendmail = popen(buffer, "w");
[...]

If email contains unfiltered input the user can supply via a form field,
one could enter "bogus@email.address; rm -rf /". This would lead to
popen() calling

sh -c /usr/lib/sendmail -oi bogus@email.address; rm -rf /

and that will not start sendmail, but also remove all files in
directories the httpd-user has write access to. That's because the ";"
is a command separator for the shell.

One method to prevent that for any command is to replace every ' in the
user-supplied data with '\'' (note that you have to double the backslash
when adding that to C code) and enclose the resulting string in '. This
way, the above command would become

sh -c /usr/lib/sendmail -oi 'bogus@email.address; rm -rf /'

This isn't dangerous anymore, as the ; is now part of the third
parameter to sendmail and thus is no longer special to the shell.

And even if someone entered "bogus@email.address'; rm -rf /" the first
step would neutralize the ', resulting in

sh -c /usr/lib/sendmail -oi 'bogus@email.address'\''; rm -rf /'

I know this is far beyond the scope of the original question, but it's
important to know when using popen() nonetheless. Also don't forget that
the same applies to system() as well, which internally uses sh -c, too!


Ciao

Thomas


-- 
Thomas Binder (Gryf @ IRCNet)  gryf@hrzpub.tu-darmstadt.de
PGP-key available on request!
Vote against SPAM:             http://www.politik-digital.de/spam/

Attachment: pgpekjBQ7B26m.pgp
Description: PGP signature