qapi: Restrict strings to printable ASCII

RFC 8259 on string contents:

   All Unicode characters may be placed within the quotation marks,
   except for the characters that MUST be escaped: quotation mark,
   reverse solidus, and the control characters (U+0000 through
   U+001F).

The QAPI schema parser accepts both less and more than JSON: it
accepts only ASCII with \u (less), and accepts control characters
other than LF (new line) unescaped.  How it treats unescaped non-ASCII
input differs between Python 2 and Python 3.

Make it accept strictly less: require printable ASCII.  Drop support
for \b, \f, \n, \r, \t.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20190913201349.24332-7-armbru@redhat.com>
This commit is contained in:
Markus Armbruster 2019-09-13 22:13:39 +02:00
parent 05d6ecd049
commit 56a8caff92
12 changed files with 20 additions and 21 deletions

View file

@ -515,6 +515,7 @@ class QAPISchemaParser(object):
elif self.tok in '{}:,[]':
return
elif self.tok == "'":
# Note: we accept only printable ASCII
string = ''
esc = False
while True:
@ -523,17 +524,9 @@ class QAPISchemaParser(object):
if ch == '\n':
raise QAPIParseError(self, 'Missing terminating "\'"')
if esc:
if ch == 'b':
string += '\b'
elif ch == 'f':
string += '\f'
elif ch == 'n':
string += '\n'
elif ch == 'r':
string += '\r'
elif ch == 't':
string += '\t'
elif ch == 'u':
# Note: we don't recognize escape sequences
# for control characters
if ch == 'u':
value = 0
for _ in range(0, 4):
ch = self.src[self.cursor]
@ -552,20 +545,21 @@ class QAPISchemaParser(object):
'For now, \\u escape '
'only supports non-zero '
'values up to \\u007f')
string += chr(value)
elif ch in '\\/\'"':
string += ch
else:
ch = chr(value)
elif ch not in '\\/\'"':
raise QAPIParseError(self,
"Unknown escape \\%s" % ch)
esc = False
elif ch == '\\':
esc = True
continue
elif ch == "'":
self.val = string
return
else:
string += ch
if ord(ch) < 32 or ord(ch) >= 127:
raise QAPIParseError(
self, "Funny character in string")
string += ch
elif self.src.startswith('true', self.pos):
self.val = True
self.cursor += 3