|
@@ -8,55 +8,104 @@
|
|
#include "ua_log_stdout.h"
|
|
#include "ua_log_stdout.h"
|
|
#include "ua_types_encoding_binary.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
|
|
** Main entry point. The fuzzer invokes this function with each
|
|
** fuzzed input.
|
|
** fuzzed input.
|
|
*/
|
|
*/
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
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;
|
|
}
|
|
}
|