/* ======================================================================== * Copyright (c) 2005-2026 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.IO; using System.Text; using System.Xml; namespace Opc.Ua.Fuzzing { /// /// Fuzzing code for individual built-in type decoders. /// public static partial class FuzzableCode { private const string BuiltInFieldName = "Value"; /// /// The NodeId binary decoder fuzz target for afl-fuzz. /// public static void AflfuzzNodeIdBinary(Stream stream) { using MemoryStream memoryStream = PrepareArraySegmentStream(stream); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadNodeId(BuiltInFieldName)); } /// /// The NodeId binary decoder fuzz target for libfuzzer. /// public static void LibfuzzNodeIdBinary(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadNodeId(BuiltInFieldName)); } /// /// The NodeId JSON decoder fuzz target for afl-fuzz. /// public static void AflfuzzNodeIdJson(string input) { FuzzJsonBuiltInType(input, decoder => decoder.ReadNodeId(BuiltInFieldName)); } /// /// The NodeId JSON decoder fuzz target for libfuzzer. /// public static void LibfuzzNodeIdJson(ReadOnlySpan input) { #if NETFRAMEWORK string json = Encoding.UTF8.GetString(input.ToArray()); #else string json = Encoding.UTF8.GetString(input); #endif FuzzJsonBuiltInType(json, decoder => decoder.ReadNodeId(BuiltInFieldName)); } /// /// The NodeId XML decoder fuzz target for afl-fuzz. /// public static void AflfuzzNodeIdXml(Stream stream) { FuzzXmlBuiltInType(stream, decoder => decoder.ReadNodeId(BuiltInFieldName)); } /// /// The NodeId XML decoder fuzz target for libfuzzer. /// public static void LibfuzzNodeIdXml(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzXmlBuiltInType(memoryStream, decoder => decoder.ReadNodeId(BuiltInFieldName)); } /// /// The ExpandedNodeId binary decoder fuzz target for afl-fuzz. /// public static void AflfuzzExpandedNodeIdBinary(Stream stream) { using MemoryStream memoryStream = PrepareArraySegmentStream(stream); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadExpandedNodeId(BuiltInFieldName)); } /// /// The ExpandedNodeId binary decoder fuzz target for libfuzzer. /// public static void LibfuzzExpandedNodeIdBinary(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadExpandedNodeId(BuiltInFieldName)); } /// /// The ExpandedNodeId JSON decoder fuzz target for afl-fuzz. /// public static void AflfuzzExpandedNodeIdJson(string input) { FuzzJsonBuiltInType(input, decoder => decoder.ReadExpandedNodeId(BuiltInFieldName)); } /// /// The ExpandedNodeId JSON decoder fuzz target for libfuzzer. /// public static void LibfuzzExpandedNodeIdJson(ReadOnlySpan input) { #if NETFRAMEWORK string json = Encoding.UTF8.GetString(input.ToArray()); #else string json = Encoding.UTF8.GetString(input); #endif FuzzJsonBuiltInType(json, decoder => decoder.ReadExpandedNodeId(BuiltInFieldName)); } /// /// The ExpandedNodeId XML decoder fuzz target for afl-fuzz. /// public static void AflfuzzExpandedNodeIdXml(Stream stream) { FuzzXmlBuiltInType(stream, decoder => decoder.ReadExpandedNodeId(BuiltInFieldName)); } /// /// The ExpandedNodeId XML decoder fuzz target for libfuzzer. /// public static void LibfuzzExpandedNodeIdXml(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzXmlBuiltInType(memoryStream, decoder => decoder.ReadExpandedNodeId(BuiltInFieldName)); } /// /// The Variant binary decoder fuzz target for afl-fuzz. /// public static void AflfuzzVariantBinary(Stream stream) { using MemoryStream memoryStream = PrepareArraySegmentStream(stream); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadVariant(BuiltInFieldName)); } /// /// The Variant binary decoder fuzz target for libfuzzer. /// public static void LibfuzzVariantBinary(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadVariant(BuiltInFieldName)); } /// /// The Variant JSON decoder fuzz target for afl-fuzz. /// public static void AflfuzzVariantJson(string input) { FuzzJsonBuiltInType(input, decoder => decoder.ReadVariant(BuiltInFieldName)); } /// /// The Variant JSON decoder fuzz target for libfuzzer. /// public static void LibfuzzVariantJson(ReadOnlySpan input) { #if NETFRAMEWORK string json = Encoding.UTF8.GetString(input.ToArray()); #else string json = Encoding.UTF8.GetString(input); #endif FuzzJsonBuiltInType(json, decoder => decoder.ReadVariant(BuiltInFieldName)); } /// /// The Variant XML decoder fuzz target for afl-fuzz. /// public static void AflfuzzVariantXml(Stream stream) { FuzzXmlBuiltInType(stream, decoder => decoder.ReadVariant(BuiltInFieldName)); } /// /// The Variant XML decoder fuzz target for libfuzzer. /// public static void LibfuzzVariantXml(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzXmlBuiltInType(memoryStream, decoder => decoder.ReadVariant(BuiltInFieldName)); } /// /// The ExtensionObject binary decoder fuzz target for afl-fuzz. /// public static void AflfuzzExtensionObjectBinary(Stream stream) { using MemoryStream memoryStream = PrepareArraySegmentStream(stream); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadExtensionObject(BuiltInFieldName)); } /// /// The ExtensionObject binary decoder fuzz target for libfuzzer. /// public static void LibfuzzExtensionObjectBinary(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadExtensionObject(BuiltInFieldName)); } /// /// The ExtensionObject JSON decoder fuzz target for afl-fuzz. /// public static void AflfuzzExtensionObjectJson(string input) { FuzzJsonBuiltInType(input, decoder => decoder.ReadExtensionObject(BuiltInFieldName)); } /// /// The ExtensionObject JSON decoder fuzz target for libfuzzer. /// public static void LibfuzzExtensionObjectJson(ReadOnlySpan input) { #if NETFRAMEWORK string json = Encoding.UTF8.GetString(input.ToArray()); #else string json = Encoding.UTF8.GetString(input); #endif FuzzJsonBuiltInType(json, decoder => decoder.ReadExtensionObject(BuiltInFieldName)); } /// /// The ExtensionObject XML decoder fuzz target for afl-fuzz. /// public static void AflfuzzExtensionObjectXml(Stream stream) { FuzzXmlBuiltInType(stream, decoder => decoder.ReadExtensionObject(BuiltInFieldName)); } /// /// The ExtensionObject XML decoder fuzz target for libfuzzer. /// public static void LibfuzzExtensionObjectXml(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzXmlBuiltInType(memoryStream, decoder => decoder.ReadExtensionObject(BuiltInFieldName)); } /// /// The DataValue binary decoder fuzz target for afl-fuzz. /// public static void AflfuzzDataValueBinary(Stream stream) { using MemoryStream memoryStream = PrepareArraySegmentStream(stream); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadDataValue(BuiltInFieldName)); } /// /// The DataValue binary decoder fuzz target for libfuzzer. /// public static void LibfuzzDataValueBinary(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadDataValue(BuiltInFieldName)); } /// /// The DataValue JSON decoder fuzz target for afl-fuzz. /// public static void AflfuzzDataValueJson(string input) { FuzzJsonBuiltInType(input, decoder => decoder.ReadDataValue(BuiltInFieldName)); } /// /// The DataValue JSON decoder fuzz target for libfuzzer. /// public static void LibfuzzDataValueJson(ReadOnlySpan input) { #if NETFRAMEWORK string json = Encoding.UTF8.GetString(input.ToArray()); #else string json = Encoding.UTF8.GetString(input); #endif FuzzJsonBuiltInType(json, decoder => decoder.ReadDataValue(BuiltInFieldName)); } /// /// The DataValue XML decoder fuzz target for afl-fuzz. /// public static void AflfuzzDataValueXml(Stream stream) { FuzzXmlBuiltInType(stream, decoder => decoder.ReadDataValue(BuiltInFieldName)); } /// /// The DataValue XML decoder fuzz target for libfuzzer. /// public static void LibfuzzDataValueXml(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzXmlBuiltInType(memoryStream, decoder => decoder.ReadDataValue(BuiltInFieldName)); } /// /// The DiagnosticInfo binary decoder fuzz target for afl-fuzz. /// public static void AflfuzzDiagnosticInfoBinary(Stream stream) { using MemoryStream memoryStream = PrepareArraySegmentStream(stream); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadDiagnosticInfo(BuiltInFieldName)!); } /// /// The DiagnosticInfo binary decoder fuzz target for libfuzzer. /// public static void LibfuzzDiagnosticInfoBinary(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadDiagnosticInfo(BuiltInFieldName)!); } /// /// The DiagnosticInfo JSON decoder fuzz target for afl-fuzz. /// public static void AflfuzzDiagnosticInfoJson(string input) { FuzzJsonBuiltInType(input, decoder => decoder.ReadDiagnosticInfo(BuiltInFieldName)!); } /// /// The DiagnosticInfo JSON decoder fuzz target for libfuzzer. /// public static void LibfuzzDiagnosticInfoJson(ReadOnlySpan input) { #if NETFRAMEWORK string json = Encoding.UTF8.GetString(input.ToArray()); #else string json = Encoding.UTF8.GetString(input); #endif FuzzJsonBuiltInType(json, decoder => decoder.ReadDiagnosticInfo(BuiltInFieldName)!); } /// /// The DiagnosticInfo XML decoder fuzz target for afl-fuzz. /// public static void AflfuzzDiagnosticInfoXml(Stream stream) { FuzzXmlBuiltInType(stream, decoder => decoder.ReadDiagnosticInfo(BuiltInFieldName)!); } /// /// The DiagnosticInfo XML decoder fuzz target for libfuzzer. /// public static void LibfuzzDiagnosticInfoXml(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzXmlBuiltInType(memoryStream, decoder => decoder.ReadDiagnosticInfo(BuiltInFieldName)!); } /// /// The QualifiedName binary decoder fuzz target for afl-fuzz. /// public static void AflfuzzQualifiedNameBinary(Stream stream) { using MemoryStream memoryStream = PrepareArraySegmentStream(stream); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadQualifiedName(BuiltInFieldName)); } /// /// The QualifiedName binary decoder fuzz target for libfuzzer. /// public static void LibfuzzQualifiedNameBinary(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadQualifiedName(BuiltInFieldName)); } /// /// The QualifiedName JSON decoder fuzz target for afl-fuzz. /// public static void AflfuzzQualifiedNameJson(string input) { FuzzJsonBuiltInType(input, decoder => decoder.ReadQualifiedName(BuiltInFieldName)); } /// /// The QualifiedName JSON decoder fuzz target for libfuzzer. /// public static void LibfuzzQualifiedNameJson(ReadOnlySpan input) { #if NETFRAMEWORK string json = Encoding.UTF8.GetString(input.ToArray()); #else string json = Encoding.UTF8.GetString(input); #endif FuzzJsonBuiltInType(json, decoder => decoder.ReadQualifiedName(BuiltInFieldName)); } /// /// The QualifiedName XML decoder fuzz target for afl-fuzz. /// public static void AflfuzzQualifiedNameXml(Stream stream) { FuzzXmlBuiltInType(stream, decoder => decoder.ReadQualifiedName(BuiltInFieldName)); } /// /// The QualifiedName XML decoder fuzz target for libfuzzer. /// public static void LibfuzzQualifiedNameXml(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzXmlBuiltInType(memoryStream, decoder => decoder.ReadQualifiedName(BuiltInFieldName)); } /// /// The LocalizedText binary decoder fuzz target for afl-fuzz. /// public static void AflfuzzLocalizedTextBinary(Stream stream) { using MemoryStream memoryStream = PrepareArraySegmentStream(stream); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadLocalizedText(BuiltInFieldName)); } /// /// The LocalizedText binary decoder fuzz target for libfuzzer. /// public static void LibfuzzLocalizedTextBinary(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzBinaryBuiltInType(memoryStream, decoder => decoder.ReadLocalizedText(BuiltInFieldName)); } /// /// The LocalizedText JSON decoder fuzz target for afl-fuzz. /// public static void AflfuzzLocalizedTextJson(string input) { FuzzJsonBuiltInType(input, decoder => decoder.ReadLocalizedText(BuiltInFieldName)); } /// /// The LocalizedText JSON decoder fuzz target for libfuzzer. /// public static void LibfuzzLocalizedTextJson(ReadOnlySpan input) { #if NETFRAMEWORK string json = Encoding.UTF8.GetString(input.ToArray()); #else string json = Encoding.UTF8.GetString(input); #endif FuzzJsonBuiltInType(json, decoder => decoder.ReadLocalizedText(BuiltInFieldName)); } /// /// The LocalizedText XML decoder fuzz target for afl-fuzz. /// public static void AflfuzzLocalizedTextXml(Stream stream) { FuzzXmlBuiltInType(stream, decoder => decoder.ReadLocalizedText(BuiltInFieldName)); } /// /// The LocalizedText XML decoder fuzz target for libfuzzer. /// public static void LibfuzzLocalizedTextXml(ReadOnlySpan input) { using var memoryStream = new MemoryStream(input.ToArray()); FuzzXmlBuiltInType(memoryStream, decoder => decoder.ReadLocalizedText(BuiltInFieldName)); } private static void FuzzBinaryBuiltInType(MemoryStream stream, Func decode) { try { _ = DecodeWithOracles(nameof(BinaryDecoder), GetRemainingLength(stream), () => { using var decoder = new BinaryDecoder(stream, MessageContext); return decode(decoder); }); } catch (ServiceResultException sre) when (IsExpectedDecodingException(sre)) { } } private static void FuzzJsonBuiltInType(string json, Func decode) { try { _ = DecodeWithOracles(nameof(JsonDecoder), json?.Length ?? 0, () => { using var decoder = new JsonDecoder(json!, MessageContext); return decode(decoder); }); } catch (ServiceResultException sre) when (IsExpectedDecodingException(sre)) { } } private static void FuzzXmlBuiltInType(Stream stream, Func decode) { try { _ = DecodeWithOracles(nameof(XmlDecoder), GetRemainingLength(stream), () => { using var reader = XmlReader.Create(stream, Utils.DefaultXmlReaderSettings()); reader.MoveToContent(); using var decoder = new XmlDecoder(reader, MessageContext); // Built-in values are read inside the namespace of their encodeable, // which the caller pushes, as BinaryDecoder does for an XML body. decoder.PushNamespace(Namespaces.OpcUaXsd); return decode(decoder); }); } catch (XmlException) { } catch (ServiceResultException sre) when (IsExpectedDecodingException(sre)) { } } private static bool IsExpectedDecodingException(ServiceResultException sre) { return sre.StatusCode == StatusCodes.BadDecodingError || sre.StatusCode == StatusCodes.BadEncodingLimitsExceeded || sre.StatusCode == StatusCodes.BadNodeIdInvalid; } } }