Hi,
I have a script that runs under mod_ruby with Apache 2.0.40. At a
certain point, it needs to invoke Kernel.system. For reasons of
security, I pass this method multiple arguments, so that it doesn’t hand
off the whole thing to the shell, as then I’d need to worry about
sanitising the tainted data.
Unfortunately, the output of the binary called by system does not get
sent to the browser, even though the binary sends its output to stdout.
Presumably, mod_ruby is discarding the output.
Is there any way around this phenomenon? I don’t want to have to use
backticks for the same security consideration mentioned above.
Ian
···
–
Ian Macdonald | Ah, but a man’s grasp should exceed his
System Administrator | reach, Or what’s a heaven for ? –
ian@caliban.org | Robert Browning, "Andrea del Sarto"
http://www.caliban.org |
>
I had kind_of? same problem, so I made a wrapper for system/backquote.
the code for ‘system’ is here:
unittesting here… some examples of how to use it.
You will need to overload ‘system’ + ‘Kernel#system’ + ‘backquote’
def my_own_system(cmd, *args)
p cmd
p args
end
overload ‘system’
def system(cmd, *args)
my_own_system(cmd, *args)
end
overload ‘backquote’
def `(cmd)
my_own_system(cmd)
end
system(“hello”, “42”)
world
···
On Fri, 30 May 2003 18:32:13 +0900, Ian Macdonald wrote:
Unfortunately, the output of the binary called by system does not get
sent to the browser, even though the binary sends its output to stdout.
Presumably, mod_ruby is discarding the output.
–
Simon Strandgaard
I think that you have to capture the output of the command yourself. Your
Unix stdout cannot be captured by Apache unless your applicaton is a
separate process (which is true of a CGI or FastCGI application, but not
true of mod_ruby where your code is in the same process as the Apache
worker)
There was a thread about capturing the output of system() a few days ago.
Here is a better version: system2() is like system() but returns three items
(stdout string, stderr string, exit status), and system3() has an extra
initial parameter for a string to pass to stdin. It’s based very much on
‘open3.rb’ from the Ruby standard library.
module Kernel
private
def system3(inp_data, cmd, *args)
pw = IO::pipe
pr = IO::pipe
pe = IO::pipe
pid = fork do
pw[1].close
pr[0].close
pe[0].close
STDIN.reopen(pw[0])
STDOUT.reopen(pr[1])
STDERR.reopen(pe[1])
exec(cmd, *args)
end
pw[0].close
pr[1].close
pe[1].close
out_data = err_data = nil
t1 = Thread.new do
pw[1].write inp_data if inp_data
pw[1].close
end
t2 = Thread.new do
out_data = pr[0].read
pr[0].close
end
t3 = Thread.new do
err_data = pe[0].read
pe[0].close
end
wpid, wstatus = Process.waitpid2(pid)
t1.join
t2.join
t3.join
return out_data, err_data, wstatus
end
def system2(cmd, *args)
system3(nil, cmd, *args)
end
end
Example:
a, b, c = system2(“ls”,“/dev/null”,“/nonexistent”)
p a,b,c
>> “/dev/null\n”
>> “ls: /nonexistent: No such file or directory\n”
>> 256 (= exit code 1 from ls)
···
On Fri, May 30, 2003 at 05:32:13PM +0900, Ian Macdonald wrote:
I have a script that runs under mod_ruby with Apache 2.0.40. At a
certain point, it needs to invoke Kernel.system. For reasons of
security, I pass this method multiple arguments, so that it doesn’t hand
off the whole thing to the shell, as then I’d need to worry about
sanitising the tainted data.
Unfortunately, the output of the binary called by system does not get
sent to the browser, even though the binary sends its output to stdout.
Presumably, mod_ruby is discarding the output.
Is there any way around this phenomenon?