Quellcode durchsuchen

Add fuzzing of extension object and variant

Stefan Profanter vor 7 Jahren
Ursprung
Commit
e110f93c36
1 geänderte Dateien mit 94 neuen und 45 gelöschten Zeilen
  1. 94 45
      tests/fuzz/fuzz_binary_decode.cc

+ 94 - 45
tests/fuzz/fuzz_binary_decode.cc

@@ -8,55 +8,104 @@
 #include "ua_log_stdout.h"
 #include "ua_types_encoding_binary.h"
 
+
+static UA_Boolean tortureEncoding(const uint8_t *data, size_t size, size_t *newOffset) {
+    *newOffset = 0;
+    if (size <= 2)
+        return UA_FALSE;
+
+    // get some random type
+    uint16_t typeIndex = (uint16_t)(data[0] | data[1] << 8);
+    data += 2;
+    size -= 2;
+
+    if (typeIndex >= UA_TYPES_COUNT)
+        return UA_FALSE;
+
+    void *dst = UA_new(&UA_TYPES[typeIndex]);
+
+    const UA_ByteString binary = {
+            size, //length
+            (UA_Byte *) (void *) data
+    };
+
+    UA_StatusCode ret = UA_decodeBinary(&binary, newOffset, dst, &UA_TYPES[typeIndex], 0, nullptr);
+
+    if (ret == UA_STATUSCODE_GOOD) {
+        // copy the datatype to test
+        void *dstCopy = UA_new(&UA_TYPES[typeIndex]);
+        UA_copy(dst, dstCopy, &UA_TYPES[typeIndex]);
+        UA_delete(dstCopy, &UA_TYPES[typeIndex]);
+
+        // now also test encoding
+        UA_ByteString encoded;
+        UA_ByteString_allocBuffer(&encoded, *newOffset);
+        const UA_Byte *end = &encoded.data[*newOffset];
+        UA_Byte *pos = encoded.data;
+        ret = UA_encodeBinary(dst, &UA_TYPES[typeIndex], &pos, &end, NULL, NULL);
+        if (ret == UA_STATUSCODE_GOOD) {
+            // do nothing
+        }
+        UA_ByteString_deleteMembers(&encoded);
+    }
+    UA_delete(dst, &UA_TYPES[typeIndex]);
+
+    return UA_TRUE;
+}
+
+static UA_Boolean tortureExtensionObject(const uint8_t *data, size_t size, size_t *newOffset) {
+    *newOffset = 0;
+    // check if there is still enough data to create an extension object
+    // we need at least a nodeid.numeric which equals to 4 bytes
+    if (size < 4)
+        return UA_FALSE;
+
+    UA_UInt32 identifier = (UA_UInt32)(data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24);
+    size-= 4;
+
+
+    UA_NodeId objectId = UA_NODEID_NUMERIC(0, identifier);
+
+    UA_ExtensionObject obj;
+    UA_ExtensionObject_init(&obj);
+    obj.encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
+    obj.content.encoded.typeId = objectId;
+    obj.content.encoded.body.length = size;
+    obj.content.encoded.body.data = (UA_Byte*)(void*)data; // discard const. We are sure that we don't change it
+
+    const UA_DataType *type = UA_findDataTypeByBinary(&obj.content.encoded.typeId);
+
+    UA_StatusCode ret = UA_STATUSCODE_GOOD;
+    if (type) {
+        void *dstCopy = UA_new(type);
+        ret = UA_decodeBinary(&obj.content.encoded.body, newOffset, dstCopy, type, 0, NULL);
+
+        if (ret == UA_STATUSCODE_GOOD) {
+            UA_Variant var;
+            UA_Variant_init(&var);
+            UA_Variant_setScalar(&var, dstCopy, type);
+        }
+        UA_delete(dstCopy, type);
+    }
+    return ret==UA_STATUSCODE_GOOD;
+}
+
 /*
 ** Main entry point.  The fuzzer invokes this function with each
 ** fuzzed input.
 */
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
 
-	if (size == 0)
-		return 0;
-
-	const uint8_t *ptr = data;
-	size_t ptrSize = size;
-
-	// get some random type
-	uint16_t typeIndex = ptr[0];
-	ptr++;
-	ptrSize--;
-
-	if (typeIndex >= UA_TYPES_COUNT)
-		return 0;
-
-	size_t offset = 0;
-	if (ptrSize >= sizeof(size_t)) {
-		offset = (*ptr);
-		ptr += sizeof(size_t);
-		ptrSize -= sizeof(size_t);
-	}
-
-	void *dst = UA_new(&UA_TYPES[typeIndex]);
-
-	const UA_ByteString binary = {
-			ptrSize, //length
-			(UA_Byte *)(void *)ptr //data
-	};
-
-	UA_StatusCode ret = UA_decodeBinary(&binary, &offset, dst, &UA_TYPES[typeIndex], 0, nullptr);
-
-	if (ret == UA_STATUSCODE_GOOD) {
-		// now also test encoding
-		UA_ByteString encoded;
-		UA_ByteString_allocBuffer(&encoded, binary.length);
-		const UA_Byte *end = &encoded.data[binary.length];
-		UA_Byte *pos = encoded.data;
-		ret = UA_encodeBinary(dst, &UA_TYPES[typeIndex], &pos, &end, NULL, NULL);
-		if (ret == UA_STATUSCODE_GOOD) {
-			// do nothing
-		}
-		UA_ByteString_deleteMembers(&encoded);
-	}
-	UA_delete(dst, &UA_TYPES[typeIndex]);
-
-	return 0;
+    size_t offset;
+    if (!tortureEncoding(data, size, &offset)) {
+        return 0;
+    }
+    if (offset >= size)
+        return 0;
+
+
+    tortureExtensionObject(&data[offset], size-offset, &offset);
+
+
+    return 0;
 }