fuzz_binary_decode.cc 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright 2019 (c) fortiss (Author: Stefan Profanter)
  6. */
  7. #include "custom_memory_manager.h"
  8. #include <open62541/plugin/log_stdout.h>
  9. #include <open62541/server_config_default.h>
  10. #include <open62541/types.h>
  11. #include "ua_server_internal.h"
  12. #include "ua_types_encoding_binary.h"
  13. static UA_Boolean tortureEncoding(const uint8_t *data, size_t size, size_t *newOffset) {
  14. *newOffset = 0;
  15. if (size <= 2)
  16. return UA_FALSE;
  17. // get some random type
  18. uint16_t typeIndex = (uint16_t)(data[0] | data[1] << 8);
  19. data += 2;
  20. size -= 2;
  21. if (typeIndex >= UA_TYPES_COUNT)
  22. return UA_FALSE;
  23. void *dst = UA_new(&UA_TYPES[typeIndex]);
  24. if (!dst)
  25. return UA_FALSE;
  26. const UA_ByteString binary = {
  27. size, //length
  28. (UA_Byte *) (void *) data
  29. };
  30. UA_StatusCode ret = UA_decodeBinary(&binary, newOffset, dst, &UA_TYPES[typeIndex], NULL);
  31. if (ret == UA_STATUSCODE_GOOD) {
  32. // copy the datatype to test
  33. void *dstCopy = UA_new(&UA_TYPES[typeIndex]);
  34. if (!dstCopy)
  35. return UA_FALSE;
  36. UA_copy(dst, dstCopy, &UA_TYPES[typeIndex]);
  37. UA_delete(dstCopy, &UA_TYPES[typeIndex]);
  38. // now also test encoding
  39. UA_ByteString encoded;
  40. UA_ByteString_allocBuffer(&encoded, *newOffset);
  41. const UA_Byte *end = &encoded.data[*newOffset];
  42. UA_Byte *pos = encoded.data;
  43. ret = UA_encodeBinary(dst, &UA_TYPES[typeIndex], &pos, &end, NULL, NULL);
  44. if (ret == UA_STATUSCODE_GOOD) {
  45. // do nothing
  46. }
  47. UA_ByteString_deleteMembers(&encoded);
  48. }
  49. UA_delete(dst, &UA_TYPES[typeIndex]);
  50. return UA_TRUE;
  51. }
  52. static UA_Boolean tortureExtensionObject(const uint8_t *data, size_t size, size_t *newOffset) {
  53. *newOffset = 0;
  54. // check if there is still enough data to create an extension object
  55. // we need at least a nodeid.numeric which equals to 4 bytes
  56. if (size < 4)
  57. return UA_FALSE;
  58. UA_UInt32 identifier = (UA_UInt32)(data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24);
  59. size-= 4;
  60. UA_NodeId objectId = UA_NODEID_NUMERIC(0, identifier);
  61. UA_ExtensionObject obj;
  62. UA_ExtensionObject_init(&obj);
  63. obj.encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
  64. obj.content.encoded.typeId = objectId;
  65. obj.content.encoded.body.length = size;
  66. obj.content.encoded.body.data = (UA_Byte*)(void*)data; // discard const. We are sure that we don't change it
  67. const UA_DataType *type = UA_findDataTypeByBinary(&obj.content.encoded.typeId);
  68. UA_StatusCode ret = UA_STATUSCODE_GOOD;
  69. if (type) {
  70. void *dstCopy = UA_new(type);
  71. if (!dstCopy)
  72. return UA_FALSE;
  73. ret = UA_decodeBinary(&obj.content.encoded.body, newOffset, dstCopy, type, NULL);
  74. if (ret == UA_STATUSCODE_GOOD) {
  75. UA_Variant var;
  76. UA_Variant_init(&var);
  77. UA_Variant_setScalar(&var, dstCopy, type);
  78. }
  79. UA_delete(dstCopy, type);
  80. }
  81. return ret==UA_STATUSCODE_GOOD;
  82. }
  83. /*
  84. ** Main entry point. The fuzzer invokes this function with each
  85. ** fuzzed input.
  86. */
  87. extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  88. if (!UA_memoryManager_setLimitFromLast4Bytes(data, size))
  89. return 0;
  90. size -= 4;
  91. size_t offset;
  92. if (!tortureEncoding(data, size, &offset)) {
  93. return 0;
  94. }
  95. if (offset >= size)
  96. return 0;
  97. tortureExtensionObject(&data[offset], size-offset, &offset);
  98. return 0;
  99. }