/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2019 (c) fortiss (Author: Stefan Profanter) */ #include "custom_memory_manager.h" #include #include #include /* ** 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 <= 6) return 0; // set the available memory if(!UA_memoryManager_setLimitFromLast4Bytes(data, size)) return 0; data += 4; size -= 4; // 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; // For DataValue types, consume 2 extra bytes to construct a // NumericRange for testing UA_DataValue_copyRange uint8_t rangeMin = 0, rangeMax = 0; if(typeIndex == UA_TYPES_DATAVALUE && size >= 2) { rangeMin = data[0]; rangeMax = data[1]; data += 2; size -= 2; } void *dst = UA_new(&UA_TYPES[typeIndex]); if(!dst) return 0; const UA_ByteString binary = { size, //length (UA_Byte *) (void *) data }; UA_StatusCode ret = UA_decodeBinary(&binary, dst, &UA_TYPES[typeIndex], NULL); if(ret != UA_STATUSCODE_GOOD) { UA_delete(dst, &UA_TYPES[typeIndex]); return 0; } // copy the datatype to test void *dstCopy = UA_new(&UA_TYPES[typeIndex]); if(!dstCopy) { UA_delete(dst, &UA_TYPES[typeIndex]); return 0; } ret = UA_copy(dst, dstCopy, &UA_TYPES[typeIndex]); if(ret != UA_STATUSCODE_GOOD) { UA_delete(dst, &UA_TYPES[typeIndex]); UA_delete(dstCopy, &UA_TYPES[typeIndex]); return 0; } // compare with copy UA_assert(UA_order(dst, dstCopy, &UA_TYPES[typeIndex]) == UA_ORDER_EQ); UA_delete(dstCopy, &UA_TYPES[typeIndex]); // now also test encoding size_t encSize = UA_calcSizeBinary(dst, &UA_TYPES[typeIndex], NULL); UA_ByteString encoded; ret = UA_ByteString_allocBuffer(&encoded, encSize); if(ret != UA_STATUSCODE_GOOD) { UA_delete(dst, &UA_TYPES[typeIndex]); return 0; } ret = UA_encodeBinary(dst, &UA_TYPES[typeIndex], &encoded, NULL); UA_assert(ret == UA_STATUSCODE_GOOD); UA_ByteString_clear(&encoded); // Test UA_DataValue_copyRange with fuzz-derived range parameters. // This exercises array sub-range copying where mismatched range // dimensions can cause out-of-bounds access. if(typeIndex == UA_TYPES_DATAVALUE) { UA_NumericRangeDimension dim; dim.min = rangeMin; dim.max = rangeMax; UA_NumericRange range; range.dimensionsSize = 1; range.dimensions = &dim; UA_DataValue dstRange; UA_DataValue_init(&dstRange); UA_DataValue_copyRange((UA_DataValue*)dst, &dstRange, range); UA_DataValue_clear(&dstRange); } UA_delete(dst, &UA_TYPES[typeIndex]); return 0; }