diff options
author | Burdette Lamar <BurdetteLamar@Yahoo.com> | 2022-02-18 06:46:04 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-18 06:46:04 -0600 |
commit | e9a2b30744a62268c66d6c17730ed96486d9783c (patch) | |
tree | fb36036ef21bdfc71104a527766a692f8a834b65 | |
parent | 542a38f619bea9fa7aa5a6be1449fc5f9b4d01e9 (diff) | |
download | ruby-e9a2b30744a62268c66d6c17730ed96486d9783c.tar.gz |
Enhanced RDoc concerning command injection (#5537)
Clarifies security vulnerabilities for commands.
Treats:
Kernel.system
Kernel.` (backtick)
IO.popen
IO.read
IO.write
IO.binread
IO.binwrite
IO.readlines
IO.foreach
-rw-r--r-- | doc/command_injection.rdoc | 29 | ||||
-rw-r--r-- | io.c | 71 | ||||
-rw-r--r-- | object.c | 2 | ||||
-rw-r--r-- | process.c | 3 |
4 files changed, 79 insertions, 26 deletions
diff --git a/doc/command_injection.rdoc b/doc/command_injection.rdoc new file mode 100644 index 0000000000..8f1303bcf7 --- /dev/null +++ b/doc/command_injection.rdoc @@ -0,0 +1,29 @@ +== Command Injection + +Some Ruby core methods accept string data +that includes text to be executed as a system command. + +They should not be called with unknown or unsanitized commands. + +These methods include: + +- Kernel.system +- {`command` (backtick method)}[rdoc-ref:Kernel#`] + (also called by the expression <tt>%x[command]</tt>). +- IO.popen(command). +- IO.read(command). +- IO.write(command). +- IO.binread(command). +- IO.binwrite(command). +- IO.readlines(command). +- IO.foreach(command). + +Note that some of these methods do not execute commands when called +from subclass \File: + +- File.read(path). +- File.write(path). +- File.binread(path). +- File.binwrite(path). +- File.readlines(path). +- File.foreach(path). @@ -7374,6 +7374,9 @@ static VALUE popen_finish(VALUE port, VALUE klass); * Executes the given command +cmd+ as a subprocess * whose $stdin and $stdout are connected to a new stream +io+. * + * This method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[command_injection.rdoc]. + * * If no block is given, returns the new stream, * which depending on given +mode+ may be open for reading, writing, or both. * The stream should be explicitly closed (eventually) to avoid resource leaks. @@ -9813,10 +9816,15 @@ argf_readlines(int argc, VALUE *argv, VALUE argf) /* * call-seq: - * `cmd` -> string + * `command` -> string + * + * Returns the <tt>$stdout</tt> output from running +command+ in a subshell; + * sets global variable <tt>$?</tt> to the process status. * - * Returns the <tt>$stdout</tt> output fromm running +cmd+ in a subshell; - * sets global variable <tt>$?</tt> to the process status: + * This method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[command_injection.rdoc]. + * + * Examples: * * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n" * $ `echo oops && exit 99` # => "oops\n" @@ -11196,36 +11204,29 @@ io_s_foreach(VALUE v) /* * call-seq: - * IO.foreach(command, sep = $/, **opts) {|line| block } -> nil - * IO.foreach(command, limit, **opts) {|line| block } -> nil - * IO.foreach(command, sep, limit, **opts) {|line| block } -> nil * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil * IO.foreach(path, limit, **opts) {|line| block } -> nil * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil + * IO.foreach(command, sep = $/, **opts) {|line| block } -> nil + * IO.foreach(command, limit, **opts) {|line| block } -> nil + * IO.foreach(command, sep, limit, **opts) {|line| block } -> nil * IO.foreach(...) -> an_enumerator * * Calls the block with each successive line read from the stream. * - * The first argument must be a string; - * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>): + * When called from class \IO (but not subclasses of \IO), + * this method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[command_injection.rdoc]. * - * - If so (and if +self+ is \IO), - * the rest of the string is a command to be executed as a subprocess. - * - Otherwise, the string is the path to a file. + * The first argument must be a string that is one of the following: * - * With only argument +command+ given, executes the command in a shell, - * parses its $stdout into lines, as determined by the default line separator, - * and calls the block with each successive line: - * - * IO.foreach('| cat t.txt') {|line| p line } - * - * Output: - * - * "First line\n" - * "Second line\n" - * "\n" - * "Third line\n" - * "Fourth line\n" + * - Path: if +self+ is a subclass of \IO (\File, for example), + * or if the string _does_ _not_ start with the pipe character (<tt>'|'</tt>), + * the string is the path to a file. + * - Command: if +self+ is the class \IO, + * and if the string starts with the pipe character, + * the rest of the string is a command to be executed as a subprocess. + * See the {Note on Security}[@Note+on+Security]. * * With only argument +path+ given, parses lines from the file at the given +path+, * as determined by the default line separator, @@ -11327,6 +11328,10 @@ io_s_readlines(VALUE v) * * Returns an array of all lines read from the stream. * + * When called from class \IO (but not subclasses of \IO), + * this method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[command_injection.rdoc]. + * * The first argument must be a string; * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>): * @@ -11427,6 +11432,10 @@ seek_before_access(VALUE argp) * Opens the stream, reads and returns some or all of its content, * and closes the stream; returns +nil+ if no bytes were read. * + * When called from class \IO (but not subclasses of \IO), + * this method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[command_injection.rdoc]. + * * The first argument must be a string; * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>): * @@ -11498,6 +11507,10 @@ rb_io_s_read(int argc, VALUE *argv, VALUE io) * Behaves like IO.read, except that the stream is opened in binary mode * with ASCII-8BIT encoding. * + * When called from class \IO (but not subclasses of \IO), + * this method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[command_injection.rdoc]. + * */ static VALUE @@ -11599,10 +11612,14 @@ io_s_write(int argc, VALUE *argv, VALUE klass, int binary) * Opens the stream, writes the given +data+ to it, * and closes the stream; returns the number of bytes written. * + * When called from class \IO (but not subclasses of \IO), + * this method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[command_injection.rdoc]. + * * The first argument must be a string; * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>): * - * - If so (and if +self+ is an instance of \IO), + * - If so (and if +self+ is \IO), * the rest of the string is a command to be executed as a subprocess. * - Otherwise, the string is the path to a file. * @@ -11660,6 +11677,10 @@ rb_io_s_write(int argc, VALUE *argv, VALUE io) * Behaves like IO.write, except that the stream is opened in binary mode * with ASCII-8BIT encoding. * + * When called from class \IO (but not subclasses of \IO), + * this method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[command_injection.rdoc]. + * */ static VALUE @@ -4389,7 +4389,7 @@ InitVM_Object(void) * * === Subprocesses * - * - #`cmd`:: Returns the standard output of running +cmd+ in a subshell. + * - #`command`:: Returns the standard output of running +command+ in a subshell. * - #exec:: Replaces current process with a new process. * - #fork:: Forks the current process into two processes. * - #spawn:: Executes the given command and returns its pid without waiting @@ -4755,6 +4755,9 @@ rb_spawn(int argc, const VALUE *argv) * Executes _command..._ in a subshell. * _command..._ is one of following forms. * + * This method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[command_injection.rdoc]. + * * [<code>commandline</code>] * command line string which is passed to the standard shell * [<code>cmdname, arg1, ...</code>] |