["Followup-To:" header set to comp.unix.programmer.]
Post by Kenny McCormack
The idea is that you have a string (say "str") that comes from outside (so
is not trusted) and you want to pass it as an argument to a program, via
fp = popen(buffer, "r");
and this is peachy keen as long as str doesn't contain a single quote. The
problem is if str contains something like: foo';rm -rf $HOME;echo 'ha! ha!
so you end up with: program 'foo';rm -rf $HOME;echo 'ha! ha!'
Also, and this is related, is there a version of popen() (or some library
or something available) that is bidirectional - i.e., you can both write
and read from it - for example, you could run the Unix 'sort' utility this
way - send it some data, then read back the sorted result (*).
No. You have to "sandbox" the contents of "str" yourself before passing
it to popen.
Just for clarity, these topics are related, but not in the way you think.
I.e., I wasn't implying that a bidirectional popen() would somehow make it
possible to pass arbitrary strings to popen() and have it magically become
Rather, my (unstated) point was that if I had a bidirectional popen(),
then I could pass data into the sub-process via stdin, rather than on the
command line. This would, in the context of my actual use case (still as
of yet unstated in this thread), solve the real life use case problem.
If the two approaches are viable alternatives, it means that you in fact
do not have a requirement to allow an untrusted user to execute
arbitrary program syntax that they specify.
Allowing a "canned" (therefore safely chosen by you) command to receive
input solves the problem of otherwise having to pass the input via
parameters (where they are treated as shell syntax).
If that is the situation, it's not too difficult to escape some data so
that can be passed as arguments. Wrap it in single quotes, and replace
every embedded single quote with '\''.
So, is it enough to just purge any single quotes from str, before
constructing buffer? (Assuming, as is the case, that single quote should
not ever occur in valid data).
Yes, provided you also take care of any possibility that the program
itself can be attacked by the content of the properly escaped input.
If program applies special processing to options, you may need
sprintf(buffer, "program -- %s", single_quote_encoded_str);
and other measures. If program is actually /bin/sh, like in this
sprintf(buffer, "/bin/sh -c %s", single_quote_encoded_str);
then what we are doing is implementing a 100% reliable, properly quoted way for
the user to run an arbitrary command. The above is then equivalent to just:
sprintf(buffer, "%s", unquoted_raw_input);
By the way, if we use sprintf, we have to be sure the buffer is
big enough to hold the worst case input situation:
the longest possible input from the user, consisting of nothing
but apostrophe characters (each of which blows up to four
characers under the '\'' encoding).
Better to use snprintf and bail if truncation occurs.
TXR Programming Language: http://nongnu.org/txr