Explorar o código

Nodeset Compiler: Check memory allocation success in generated code

Credit to oss-fuzz

Fixes issues:
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11430
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11438
Stefan Profanter %!s(int64=5) %!d(string=hai) anos
pai
achega
9b837c1ba6

+ 3 - 0
src/ua_types_encoding_binary.c

@@ -1445,6 +1445,9 @@ UA_encodeBinary(const void *src, const UA_DataType *type,
     ctx.exchangeBufferCallback = exchangeCallback;
     ctx.exchangeBufferCallbackHandle = exchangeHandle;
 
+    if (!ctx.pos)
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+
     /* Encode */
     status ret = encodeBinaryInternal(src, type, &ctx);
 

+ 13 - 4
tools/nodeset_compiler/backend_open62541_nodes.py

@@ -90,6 +90,7 @@ def generateVariableNodeCode(node, nodeset, encode_binary_size):
     if node.valueRank > 0:
         code.append("attr.arrayDimensionsSize = %d;" % node.valueRank)
         code.append("attr.arrayDimensions = (UA_UInt32 *)UA_Array_new({}, &UA_TYPES[UA_TYPES_UINT32]);".format(node.valueRank))
+        code.append("if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY;")
         codeCleanup.append("UA_Array_delete(attr.arrayDimensions, {}, &UA_TYPES[UA_TYPES_UINT32]);".format(node.valueRank))
         if len(node.arrayDimensions) == node.valueRank:
             for idx, v in enumerate(node.arrayDimensions):
@@ -183,6 +184,11 @@ def generateExtensionObjectSubtypeCode(node, parent, nodeset, global_var_code, r
             code.append("  UA_ExtensionObject " + " " + ptrSym + str(field[0]) + ";")
     code.append("} " + instanceName + "_struct;")
 
+    # Allocate some memory
+    code.append("UA_ExtensionObject *" + instanceName + " =  UA_ExtensionObject_new();")
+    code.append("if (!" + instanceName + ") return UA_STATUSCODE_BADOUTOFMEMORY;")
+    codeCleanup.append("UA_ExtensionObject_delete(" + instanceName + ");")
+
     # Assign data to the struct contents
     # Track the encoding rule definition to detect arrays and/or ExtensionObjects
     encFieldIdx = 0
@@ -203,6 +209,8 @@ def generateExtensionObjectSubtypeCode(node, parent, nodeset, global_var_code, r
                 code.append(
                      "{0}_struct.{1} = (UA_{2}*) UA_malloc(sizeof(UA_{2})*{3});".format(
                          instanceName, subv.alias, subv.__class__.__name__, str(len(subv))))
+                code.append("if (!{0}_struct.{1}) return UA_STATUSCODE_BADOUTOFMEMORY;".format(
+                    instanceName, subv.alias))
                 codeCleanup.append("UA_free({0}_struct.{1});".format(instanceName, subv.alias))
                 logger.debug("Encoding included array of " + str(len(subv)) + " values.")
                 for subvidx in range(0, len(subv)):
@@ -217,14 +225,13 @@ def generateExtensionObjectSubtypeCode(node, parent, nodeset, global_var_code, r
                 code.append(
                     "{0}_struct.{1} = (UA_{2}*) UA_malloc(sizeof(UA_{2}));".format(
                         instanceName, subv.alias, subv.__class__.__name__))
+                code.append("if (!{0}_struct.{1}) return UA_STATUSCODE_BADOUTOFMEMORY;".format(
+                    instanceName, subv.alias))
                 codeCleanup.append("UA_free({0}_struct.{1});".format(instanceName, subv.alias))
                 valueName = instanceName + "_struct." + subv.alias + "[0]"
                 code.append(generateNodeValueCode(valueName + " = ",
                             subv, instanceName, valueName, global_var_code, asIndirect=True))
 
-    # Allocate some memory
-    code.append("UA_ExtensionObject *" + instanceName + " =  UA_ExtensionObject_new();")
-    codeCleanup.append("UA_ExtensionObject_delete(" + instanceName + ");")
     code.append(instanceName + "->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;")
     #if parent.dataType.ns == 0:
 
@@ -233,7 +240,7 @@ def generateExtensionObjectSubtypeCode(node, parent, nodeset, global_var_code, r
         instanceName + "->content.encoded.typeId = UA_NODEID_NUMERIC(" + str(binaryEncodingId.ns) + ", " +
         str(binaryEncodingId.i) + ");")
     code.append(
-        "UA_ByteString_allocBuffer(&" + instanceName + "->content.encoded.body, " + str(encode_binary_size) + ");")
+        "retVal |= UA_ByteString_allocBuffer(&" + instanceName + "->content.encoded.body, " + str(encode_binary_size) + ");")
 
     # Encode each value as a bytestring separately.
     code.append("UA_Byte *pos" + instanceName + " = " + instanceName + "->content.encoded.body.data;")
@@ -264,6 +271,7 @@ def generateExtensionObjectSubtypeCode(node, parent, nodeset, global_var_code, r
                 "pos" + instanceName + "-" + instanceName + "->content.encoded.body.data);")
     code.append(instanceName + "->content.encoded.body.length = " + instanceName + "_encOffset;")
     code.append("UA_Byte *" + instanceName + "_newBody = (UA_Byte *) UA_malloc(" + instanceName + "_encOffset);")
+    code.append("if (!" + instanceName + "_newBody) return UA_STATUSCODE_BADOUTOFMEMORY;")
     code.append("memcpy(" + instanceName + "_newBody, " + instanceName + "->content.encoded.body.data, " +
                 instanceName + "_encOffset);")
     code.append("UA_Byte *" + instanceName + "_oldBody = " + instanceName + "->content.encoded.body.data;")
@@ -390,6 +398,7 @@ def generateValueCode(node, parentNode, nodeset, bootstrapping=True, encode_bina
             else:
                 code.append("UA_" + node.value[0].__class__.__name__ + " *" + valueName + " =  UA_" + node.value[
                     0].__class__.__name__ + "_new();")
+                code.append("if (!" + valueName + ") return UA_STATUSCODE_BADOUTOFMEMORY;")
                 code.append(generateNodeValueCode("*" + valueName + " = " , node.value[0], instanceName, valueName, codeGlobal, asIndirect=True))
                 code.append(
                         "UA_Variant_setScalar(&attr.value, " + valueName + ", " +