summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-10-30 15:08:02 +0100
committerAleksander Morgado <aleksander@lanedo.com>2012-10-30 20:42:59 +0100
commit4c98ff41cca3c83498c8f8b6f502fa56e4e31653 (patch)
tree7935c2d8132809eeb74c7cd655d9f87b560f8db3
parent7cce18820ef2142781c334d20e162d814695a409 (diff)
qmi-codegen: validate TLV before really reading it
Try to handle buggy firmware, or just make the library more robust, by validating the read TLV before really reading it. If a TLV is not considered valid, we just skip it for now. E.g.: the "Detailed Service Status" TLV (0x21) in the "NAS Get Serving System" message is supposed to be a sequence of 5 bytes, but some models (e.g. ZTE MF683) end up sending only the first 4 bytes.
-rw-r--r--build-aux/qmi-codegen/Field.py45
-rw-r--r--build-aux/qmi-codegen/FieldResult.py26
-rw-r--r--build-aux/qmi-codegen/Message.py11
-rw-r--r--build-aux/qmi-codegen/TypeFactory.py16
-rw-r--r--build-aux/qmi-codegen/Variable.py7
-rw-r--r--build-aux/qmi-codegen/VariableArray.py57
-rw-r--r--build-aux/qmi-codegen/VariableInteger.py26
-rw-r--r--build-aux/qmi-codegen/VariableSequence.py8
-rw-r--r--build-aux/qmi-codegen/VariableString.py39
-rw-r--r--build-aux/qmi-codegen/VariableStruct.py8
10 files changed, 220 insertions, 23 deletions
diff --git a/build-aux/qmi-codegen/Field.py b/build-aux/qmi-codegen/Field.py
index 31005b3..5bf42bc 100644
--- a/build-aux/qmi-codegen/Field.py
+++ b/build-aux/qmi-codegen/Field.py
@@ -271,6 +271,7 @@ class Field:
def emit_output_tlv_get(self, f, line_prefix):
translations = { 'name' : self.name,
'container_underscore' : utils.build_underscore_name (self.prefix),
+ 'underscore' : utils.build_underscore_name (self.fullname),
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name,
'lp' : line_prefix,
@@ -283,7 +284,7 @@ class Field:
'${lp}buffer = qmi_message_get_raw_tlv (message,\n'
'${lp} ${tlv_id},\n'
'${lp} &buffer_len);\n'
- '${lp} if (buffer) {\n'
+ '${lp}if (buffer && ${underscore}_validate (buffer, buffer_len)) {\n'
'${lp} self->${variable_name}_set = TRUE;\n'
'\n')
f.write(string.Template(template).substitute(translations))
@@ -317,15 +318,49 @@ class Field:
"""
Emit the method responsible for creating a printable representation of the TLV
"""
- def emit_tlv_get_printable(self, f):
- if TypeFactory.is_get_printable_emitted(self.fullname):
+ def emit_tlv_helpers(self, f):
+ if TypeFactory.helpers_emitted(self.fullname):
return
- TypeFactory.set_get_printable_emitted(self.fullname)
+ TypeFactory.set_helpers_emitted(self.fullname)
translations = { 'name' : self.name,
'tlv_id' : self.id_enum_name,
'underscore' : utils.build_underscore_name (self.fullname) }
+
+ template = (
+ '\n'
+ 'static gboolean\n'
+ '${underscore}_validate (\n'
+ ' const guint8 *buffer,\n'
+ ' guint16 buffer_len)\n'
+ '{\n'
+ ' guint expected_len = 0;\n'
+ '\n')
+ f.write(string.Template(template).substitute(translations))
+
+ # Now, read the size of the expected TLV
+ self.variable.emit_size_read(f, ' ', 'expected_len', 'buffer', 'buffer_len')
+
+ template = (
+ '\n'
+ ' if (buffer_len < expected_len) {\n'
+ ' g_warning ("Cannot read the \'${name}\' TLV: expected \'%u\' bytes, but only got \'%u\' bytes",\n'
+ ' expected_len, buffer_len);\n'
+ ' return FALSE;\n'
+ ' }\n'
+ '\n'
+ ' if (buffer_len > expected_len) {\n'
+ ' g_debug ("Reading the \'${name}\' TLV: expected \'%u\' bytes, but got \'%u\' bytes",\n'
+ ' expected_len, buffer_len);\n'
+ ' return TRUE;\n'
+ ' }\n'
+ '\n'
+ ' return TRUE;\n'
+ '}\n'
+ '\n')
+ f.write(string.Template(template).substitute(translations))
+
template = (
'\n'
'static gchar *\n'
@@ -339,7 +374,7 @@ class Field:
' buffer = qmi_message_get_raw_tlv (message,\n'
' ${tlv_id},\n'
' &buffer_len);\n'
- ' if (buffer) {\n'
+ ' if (buffer && ${underscore}_validate (buffer, buffer_len)) {\n'
' GString *printable;\n'
'\n'
' printable = g_string_new ("");\n')
diff --git a/build-aux/qmi-codegen/FieldResult.py b/build-aux/qmi-codegen/FieldResult.py
index cc298ee..6b7b91e 100644
--- a/build-aux/qmi-codegen/FieldResult.py
+++ b/build-aux/qmi-codegen/FieldResult.py
@@ -107,15 +107,35 @@ class FieldResult(Field):
Emit the method responsible for getting a printable representation of this
TLV field.
"""
- def emit_tlv_get_printable(self, f):
- if TypeFactory.is_get_printable_emitted(self.fullname):
+ def emit_tlv_helpers(self, f):
+ if TypeFactory.helpers_emitted(self.fullname):
return
- TypeFactory.set_get_printable_emitted(self.fullname)
+ TypeFactory.set_helpers_emitted(self.fullname)
translations = { 'name' : self.name,
'tlv_id' : self.id_enum_name,
'underscore' : utils.build_underscore_name (self.fullname) }
+
+ template = (
+ '\n'
+ 'static gboolean\n'
+ '${underscore}_validate (\n'
+ ' const guint8 *buffer,\n'
+ ' guint16 buffer_len)\n'
+ '{\n'
+ ' static const guint expected_len = 4;\n'
+ '\n'
+ ' if (buffer_len < expected_len) {\n'
+ ' g_warning ("Cannot read the \'${name}\' TLV: expected \'%u\' bytes, but only got \'%u\' bytes",\n'
+ ' expected_len, buffer_len);\n'
+ ' return FALSE;\n'
+ ' }\n'
+ '\n'
+ ' return TRUE;\n'
+ '}\n')
+ f.write(string.Template(template).substitute(translations))
+
template = (
'\n'
'static gchar *\n'
diff --git a/build-aux/qmi-codegen/Message.py b/build-aux/qmi-codegen/Message.py
index 5b35cf7..04d775e 100644
--- a/build-aux/qmi-codegen/Message.py
+++ b/build-aux/qmi-codegen/Message.py
@@ -224,17 +224,17 @@ class Message:
Emit method responsible for getting a printable representation of the whole
request/response
"""
- def __emit_get_printable(self, hfile, cfile):
+ def __emit_helpers(self, hfile, cfile):
need_tlv_printable = False
if self.input is not None and self.input.fields is not None:
need_tlv_printable = True
for field in self.input.fields:
- field.emit_tlv_get_printable(cfile)
+ field.emit_tlv_helpers(cfile)
if self.output is not None and self.output.fields is not None:
need_tlv_printable = True
for field in self.output.fields:
- field.emit_tlv_get_printable(cfile)
+ field.emit_tlv_helpers(cfile)
translations = { 'name' : self.name,
'service' : self.service,
@@ -394,12 +394,9 @@ class Message:
hfile.write('\n/* --- Output -- */\n');
cfile.write('\n/* --- Output -- */\n');
self.output.emit(hfile, cfile)
+ self.__emit_helpers(hfile, cfile)
self.__emit_response_or_indication_parser(hfile, cfile)
- hfile.write('\n/* --- Printable -- */\n');
- cfile.write('\n/* --- Printable -- */\n');
- self.__emit_get_printable(hfile, cfile)
-
"""
Emit the sections
"""
diff --git a/build-aux/qmi-codegen/TypeFactory.py b/build-aux/qmi-codegen/TypeFactory.py
index da1a185..0e1e0f8 100644
--- a/build-aux/qmi-codegen/TypeFactory.py
+++ b/build-aux/qmi-codegen/TypeFactory.py
@@ -47,16 +47,16 @@ def set_type_emitted(type_name):
"""
-List to keep track of type-specific get_printable() methods already emitted to
+List to keep track of type-specific helper methods already emitted to
the source/header files.
"""
-emitted_get_printable = []
+emitted_helpers = []
"""
-Checks whether a given type-specific get_printable() has already been emitted.
+Checks whether a given type-specific helpers have already been emitted.
"""
-def is_get_printable_emitted(type_name):
- for i in emitted_get_printable:
+def helpers_emitted(type_name):
+ for i in emitted_helpers:
if i == type_name:
return True
else:
@@ -65,11 +65,11 @@ def is_get_printable_emitted(type_name):
"""
Sets the given type-specific get_printable() as already emitted.
"""
-def set_get_printable_emitted(type_name):
- if is_get_printable_emitted(type_name):
+def set_helpers_emitted(type_name):
+ if helpers_emitted(type_name):
return False
else:
- emitted_get_printable.append(type_name)
+ emitted_helpers.append(type_name)
return True
diff --git a/build-aux/qmi-codegen/Variable.py b/build-aux/qmi-codegen/Variable.py
index 3f3fcec..8e4bfc6 100644
--- a/build-aux/qmi-codegen/Variable.py
+++ b/build-aux/qmi-codegen/Variable.py
@@ -86,6 +86,13 @@ class Variable:
"""
+ Emits the code involved in computing the size of the variable.
+ """
+ def emit_size_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
+ pass
+
+
+ """
Emits the code to get the contents of the given variable as a printable string.
"""
def emit_get_printable(self, f, line_prefix, printable, buffer_name, buffer_len):
diff --git a/build-aux/qmi-codegen/VariableArray.py b/build-aux/qmi-codegen/VariableArray.py
index d582a6a..f2b122c 100644
--- a/build-aux/qmi-codegen/VariableArray.py
+++ b/build-aux/qmi-codegen/VariableArray.py
@@ -190,6 +190,63 @@ class VariableArray(Variable):
"""
+ Emits the code involved in computing the size of the variable.
+ """
+ def emit_size_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
+ common_var_prefix = utils.build_underscore_name(self.name)
+ translations = { 'lp' : line_prefix,
+ 'variable_name' : variable_name,
+ 'buffer_name' : buffer_name,
+ 'buffer_len' : buffer_len,
+ 'common_var_prefix' : common_var_prefix }
+
+ template = (
+ '${lp}{\n'
+ '${lp} guint ${common_var_prefix}_i;\n')
+ f.write(string.Template(template).substitute(translations))
+
+ if self.fixed_size:
+ translations['fixed_size'] = self.fixed_size
+
+ template = (
+ '${lp} guint16 ${common_var_prefix}_n_items = ${fixed_size};\n'
+ '\n')
+ f.write(string.Template(template).substitute(translations))
+ else:
+ translations['array_size_element_format'] = self.array_size_element.public_format
+ if self.array_size_element.public_format == 'guint8':
+ translations['array_size_element_size'] = '1'
+ elif self.array_size_element.public_format == 'guint16':
+ translations['array_size_element_size'] = '2'
+ elif self.array_size_element.public_format == 'guint32':
+ translations['array_size_element_size'] = '4'
+ else:
+ translations['array_size_element_size'] = '0'
+
+ template = (
+ '${lp} ${array_size_element_format} ${common_var_prefix}_n_items;\n'
+ '${lp} const guint8 *${common_var_prefix}_aux_buffer = &${buffer_name}[${variable_name}];\n'
+ '${lp} guint16 ${common_var_prefix}_aux_buffer_len = ${buffer_len} - ${variable_name};\n'
+ '\n'
+ '${lp} ${variable_name} += ${array_size_element_size};\n'
+ '\n')
+ f.write(string.Template(template).substitute(translations))
+
+ self.array_size_element.emit_buffer_read(f, line_prefix + ' ', common_var_prefix + '_n_items', common_var_prefix + '_aux_buffer', common_var_prefix + '_aux_buffer_len')
+
+ template = (
+ '${lp} for (${common_var_prefix}_i = 0; ${common_var_prefix}_i < ${common_var_prefix}_n_items; ${common_var_prefix}_i++) {\n'
+ '\n')
+ f.write(string.Template(template).substitute(translations))
+
+ self.array_element.emit_size_read(f, line_prefix + ' ', variable_name, buffer_name, buffer_len)
+
+ template = (
+ '${lp} }\n'
+ '${lp}}\n')
+ f.write(string.Template(template).substitute(translations))
+
+ """
Writing an array to the raw byte buffer is just about providing a loop to
write every array element one by one.
"""
diff --git a/build-aux/qmi-codegen/VariableInteger.py b/build-aux/qmi-codegen/VariableInteger.py
index b891283..63d1d02 100644
--- a/build-aux/qmi-codegen/VariableInteger.py
+++ b/build-aux/qmi-codegen/VariableInteger.py
@@ -101,6 +101,32 @@ class VariableInteger(Variable):
"""
+ Emits the code involved in computing the size of the variable.
+ """
+ def emit_size_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
+ translations = { 'lp' : line_prefix,
+ 'len' : self.guint_sized_size,
+ 'variable_name' : variable_name }
+ template = ''
+ if self.format == 'guint-sized':
+ template += (
+ '${lp}${variable_name} += ${len};\n')
+ elif self.private_format == 'guint8' or self.private_format == 'gint8':
+ template += (
+ '${lp}${variable_name} += 1;\n')
+ elif self.private_format == 'guint16' or self.private_format == 'gint16':
+ template += (
+ '${lp}${variable_name} += 2;\n')
+ elif self.private_format == 'guint32' or self.private_format == 'gint32':
+ template += (
+ '${lp}${variable_name} += 4;\n')
+ elif self.private_format == 'guint64' or self.private_format == 'gint64':
+ template += (
+ '${lp}${variable_name} += 8;\n')
+ f.write(string.Template(template).substitute(translations))
+
+
+ """
Write a single integer to the raw byte buffer
"""
def emit_buffer_write(self, f, line_prefix, variable_name, buffer_name, buffer_len):
diff --git a/build-aux/qmi-codegen/VariableSequence.py b/build-aux/qmi-codegen/VariableSequence.py
index 07b3ba4..a20c6b7 100644
--- a/build-aux/qmi-codegen/VariableSequence.py
+++ b/build-aux/qmi-codegen/VariableSequence.py
@@ -81,6 +81,14 @@ class VariableSequence(Variable):
"""
+ Emits the code involved in computing the size of the variable.
+ """
+ def emit_size_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
+ for member in self.members:
+ member['object'].emit_size_read(f, line_prefix, variable_name, buffer_name, buffer_len)
+
+
+ """
Writing the contents of a sequence is just about writing each of the sequence
fields one by one.
"""
diff --git a/build-aux/qmi-codegen/VariableString.py b/build-aux/qmi-codegen/VariableString.py
index c6acbe0..db4a915 100644
--- a/build-aux/qmi-codegen/VariableString.py
+++ b/build-aux/qmi-codegen/VariableString.py
@@ -102,6 +102,45 @@ class VariableString(Variable):
"""
+ Emits the code involved in computing the size of the variable.
+ """
+ def emit_size_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
+ translations = { 'lp' : line_prefix,
+ 'variable_name' : variable_name,
+ 'buffer_name' : buffer_name,
+ 'buffer_len' : buffer_len }
+
+ if self.is_fixed_size:
+ translations['fixed_size'] = self.fixed_size
+ template = (
+ '${lp}${variable_name} += ${fixed_size};\n')
+ elif self.length_prefix_size == 0:
+ template = (
+ '${lp}${variable_name} += ${buffer_len};\n')
+ elif self.length_prefix_size == 8:
+ template = (
+ '${lp}{\n'
+ '${lp} guint8 size8;\n'
+ '${lp} const guint8 *aux_buffer = &${buffer_name}[${variable_name}];\n'
+ '${lp} guint16 aux_buffer_len = ${buffer_len} - ${variable_name};\n'
+ '\n'
+ '${lp} qmi_utils_read_guint8_from_buffer (&aux_buffer, &aux_buffer_len, &size8);\n'
+ '${lp} ${variable_name} = 1 + size8;\n'
+ '${lp}}\n')
+ elif self.length_prefix_size == 16:
+ template = (
+ '${lp}{\n'
+ '${lp} guint16 size16;\n'
+ '${lp} const guint8 *aux_buffer = &${buffer_name}[${variable_name}];\n'
+ '${lp} guint16 aux_buffer_len = ${buffer_len} - ${variable_name};\n'
+ '\n'
+ '${lp} qmi_utils_read_guint16_from_buffer (&aux_buffer, &aux_buffer_len, QMI_ENDIAN_LITTLE, &size16);\n'
+ '${lp} ${variable_name} = 2 + size16;\n'
+ '${lp}}\n')
+ f.write(string.Template(template).substitute(translations))
+
+
+ """
Write a string to the raw byte buffer.
"""
def emit_buffer_write(self, f, line_prefix, variable_name, buffer_name, buffer_len):
diff --git a/build-aux/qmi-codegen/VariableStruct.py b/build-aux/qmi-codegen/VariableStruct.py
index c22d9c2..522551e 100644
--- a/build-aux/qmi-codegen/VariableStruct.py
+++ b/build-aux/qmi-codegen/VariableStruct.py
@@ -110,6 +110,14 @@ class VariableStruct(Variable):
"""
+ Emits the code involved in computing the size of the variable.
+ """
+ def emit_size_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
+ for member in self.members:
+ member['object'].emit_size_read(f, line_prefix, variable_name, buffer_name, buffer_len)
+
+
+ """
Writing the contents of a struct is just about writing each of the struct
fields one by one.
"""