Skip to content

Commit 2c7ae1b

Browse files
committed
NUL char cannot be in shell words
1 parent d1a2605 commit 2c7ae1b

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

lib/shellwords.rb

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ module Shellwords
7373
# argv = Shellwords.split('here are "two words"')
7474
# argv #=> ["here", "are", "two words"]
7575
#
76+
# +line+ must not contain NUL characters because of nature of
77+
# +exec+ system call.
78+
#
7679
# Note, however, that this is not a command line parser. Shell
7780
# metacharacters except for the single and double quotes and
7881
# backslash are not treated as such.
@@ -87,9 +90,14 @@ module Shellwords
8790
def shellsplit(line)
8891
words = []
8992
field = String.new
90-
line.scan(/\G\s*(?>([^\s\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|\\.)*)"|(\\.?)|(\S))(\s|\z)?/m) do
93+
line.scan(/\G\s*(?>([^\0\s\\\'\"]+)|'([^\0\']*)'|"((?:[^\0\"\\]|\\[^\0])*)"|(\\[^\0]?)|(\S))(\s|\z)?/m) do
9194
|word, sq, dq, esc, garbage, sep|
92-
raise ArgumentError, "Unmatched quote: #{line.inspect}" if garbage
95+
if garbage
96+
b = $~.begin(0)
97+
line = $~[0]
98+
line = "..." + line if b > 0
99+
raise ArgumentError, "#{garbage == "\0" ? 'Nul character' : 'Unmatched quote'} at #{b}: #{line}"
100+
end
93101
# 2.2.3 Double-Quotes:
94102
#
95103
# The <backslash> shall retain its special meaning as an
@@ -118,6 +126,9 @@ class << self
118126
# command line. +str+ can be a non-string object that responds to
119127
# +to_s+.
120128
#
129+
# +str+ must not contain NUL characters because of nature of +exec+
130+
# system call.
131+
#
121132
# Note that a resulted string should be used unquoted and is not
122133
# intended for use in double quotes nor in single quotes.
123134
#
@@ -150,6 +161,9 @@ def shellescape(str)
150161
# An empty argument will be skipped, so return empty quotes.
151162
return "''".dup if str.empty?
152163

164+
# Shellwords cannot contain NUL characters.
165+
raise ArgumentError, "NUL character" if str.index("\0")
166+
153167
str = str.dup
154168

155169
# Treat multibyte characters as is. It is the caller's responsibility
@@ -175,6 +189,7 @@ class << self
175189
# All elements are joined into a single string with fields separated by a
176190
# space, where each element is escaped for the Bourne shell and stringified
177191
# using +to_s+.
192+
# See also Shellwords.shellescape.
178193
#
179194
# ary = ["There's", "a", "time", "and", "place", "for", "everything"]
180195
# argv = Shellwords.join(ary)

test/test_shellwords.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,13 @@ def test_multibyte_characters
128128
# used as shell meta-character that needs to be escaped.
129129
assert_equal "\\\\い", "あい".shellescape
130130
end
131+
132+
def test_nul_char
133+
assert_raise(ArgumentError) do
134+
shellescape("\0")
135+
end
136+
assert_raise(ArgumentError) do
137+
shelljoin(["\0"])
138+
end
139+
end
131140
end

0 commit comments

Comments
 (0)