Skip to content

Commit a887f90

Browse files
authored
Allow ExtensionObjects which are encoded with an unknown size (#2869)
An older OPC UA server returns well known extension object(811) which cannot be decoded by the client because the server doesn't set the length of the extension object. Recently, based on fuzz testing, the length check has been changed to enforce an exact match, according to spec. Workaround: Allow a value of -1 for the length, then allow to decode well known extension objects. Also improve some internal calls to Safe Read functions by calling not via the interface.
1 parent 71a6e69 commit a887f90

File tree

1 file changed

+37
-33
lines changed

1 file changed

+37
-33
lines changed

Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,7 @@ public Int32Collection ReadInt32Array(string fieldName)
901901

902902
for (int ii = 0; ii < length; ii++)
903903
{
904-
values.Add(ReadInt32(null));
904+
values.Add(SafeReadInt32());
905905
}
906906

907907
return values;
@@ -945,7 +945,7 @@ public Int64Collection ReadInt64Array(string fieldName)
945945

946946
for (int ii = 0; ii < length; ii++)
947947
{
948-
values.Add(ReadInt64(null));
948+
values.Add(SafeReadInt64());
949949
}
950950

951951
return values;
@@ -967,7 +967,7 @@ public UInt64Collection ReadUInt64Array(string fieldName)
967967

968968
for (int ii = 0; ii < length; ii++)
969969
{
970-
values.Add(ReadUInt64(null));
970+
values.Add(SafeReadUInt64());
971971
}
972972

973973
return values;
@@ -989,7 +989,7 @@ public FloatCollection ReadFloatArray(string fieldName)
989989

990990
for (int ii = 0; ii < length; ii++)
991991
{
992-
values.Add(ReadFloat(null));
992+
values.Add(SafeReadFloat());
993993
}
994994

995995
return values;
@@ -1011,7 +1011,7 @@ public DoubleCollection ReadDoubleArray(string fieldName)
10111011

10121012
for (int ii = 0; ii < length; ii++)
10131013
{
1014-
values.Add(ReadDouble(null));
1014+
values.Add(SafeReadDouble());
10151015
}
10161016

10171017
return values;
@@ -1547,22 +1547,22 @@ private DiagnosticInfo ReadDiagnosticInfo(string fieldName, int depth)
15471547
// read the fields of the diagnostic info structure.
15481548
if ((encodingByte & (byte)DiagnosticInfoEncodingBits.SymbolicId) != 0)
15491549
{
1550-
value.SymbolicId = ReadInt32(null);
1550+
value.SymbolicId = SafeReadInt32();
15511551
}
15521552

15531553
if ((encodingByte & (byte)DiagnosticInfoEncodingBits.NamespaceUri) != 0)
15541554
{
1555-
value.NamespaceUri = ReadInt32(null);
1555+
value.NamespaceUri = SafeReadInt32();
15561556
}
15571557

15581558
if ((encodingByte & (byte)DiagnosticInfoEncodingBits.Locale) != 0)
15591559
{
1560-
value.Locale = ReadInt32(null);
1560+
value.Locale = SafeReadInt32();
15611561
}
15621562

15631563
if ((encodingByte & (byte)DiagnosticInfoEncodingBits.LocalizedText) != 0)
15641564
{
1565-
value.LocalizedText = ReadInt32(null);
1565+
value.LocalizedText = SafeReadInt32();
15661566
}
15671567

15681568
if ((encodingByte & (byte)DiagnosticInfoEncodingBits.AdditionalInfo) != 0)
@@ -1617,7 +1617,7 @@ private Array ReadArrayElements(int length, BuiltInType builtInType)
16171617

16181618
for (int ii = 0; ii < values.Length; ii++)
16191619
{
1620-
values[ii] = ReadBoolean(null);
1620+
values[ii] = SafeReadBoolean();
16211621
}
16221622

16231623
array = values;
@@ -1656,7 +1656,7 @@ private Array ReadArrayElements(int length, BuiltInType builtInType)
16561656

16571657
for (int ii = 0; ii < values.Length; ii++)
16581658
{
1659-
values[ii] = ReadInt16(null);
1659+
values[ii] = SafeReadInt16();
16601660
}
16611661

16621662
array = values;
@@ -1669,7 +1669,7 @@ private Array ReadArrayElements(int length, BuiltInType builtInType)
16691669

16701670
for (int ii = 0; ii < values.Length; ii++)
16711671
{
1672-
values[ii] = ReadUInt16(null);
1672+
values[ii] = SafeReadUInt16();
16731673
}
16741674

16751675
array = values;
@@ -1683,7 +1683,7 @@ private Array ReadArrayElements(int length, BuiltInType builtInType)
16831683

16841684
for (int ii = 0; ii < values.Length; ii++)
16851685
{
1686-
values[ii] = ReadInt32(null);
1686+
values[ii] = SafeReadInt32();
16871687
}
16881688
array = values;
16891689
break;
@@ -1708,7 +1708,7 @@ private Array ReadArrayElements(int length, BuiltInType builtInType)
17081708

17091709
for (int ii = 0; ii < values.Length; ii++)
17101710
{
1711-
values[ii] = ReadInt64(null);
1711+
values[ii] = SafeReadInt64();
17121712
}
17131713

17141714
array = values;
@@ -1721,7 +1721,7 @@ private Array ReadArrayElements(int length, BuiltInType builtInType)
17211721

17221722
for (int ii = 0; ii < values.Length; ii++)
17231723
{
1724-
values[ii] = ReadUInt64(null);
1724+
values[ii] = SafeReadUInt64();
17251725
}
17261726

17271727
array = values;
@@ -1734,7 +1734,7 @@ private Array ReadArrayElements(int length, BuiltInType builtInType)
17341734

17351735
for (int ii = 0; ii < values.Length; ii++)
17361736
{
1737-
values[ii] = ReadFloat(null);
1737+
values[ii] = SafeReadFloat();
17381738
}
17391739

17401740
array = values;
@@ -1747,7 +1747,7 @@ private Array ReadArrayElements(int length, BuiltInType builtInType)
17471747

17481748
for (int ii = 0; ii < values.Length; ii++)
17491749
{
1750-
values[ii] = ReadDouble(null);
1750+
values[ii] = SafeReadDouble();
17511751
}
17521752

17531753
array = values;
@@ -2096,15 +2096,16 @@ private ExtensionObject ReadExtensionObject()
20962096
return extension;
20972097
}
20982098

2099-
// get the length.
2100-
int length = ReadInt32(null);
2099+
// Get the length.
2100+
// Allow a length of -1 to support legacy devices that don't fill the length correctly
2101+
int length = SafeReadInt32();
21012102

21022103
// save the current position.
21032104
int start = Position;
21042105

21052106
// create instance of type.
21062107
IEncodeable encodeable = null;
2107-
if (systemType != null && length >= 0)
2108+
if (systemType != null && length >= -1)
21082109
{
21092110
encodeable = Activator.CreateInstance(systemType) as IEncodeable;
21102111

@@ -2132,7 +2133,7 @@ private ExtensionObject ReadExtensionObject()
21322133

21332134
// verify the decoder did not exceed the length of the encodeable object
21342135
int used = Position - start;
2135-
if (length != used)
2136+
if (length >= 0 && length != used)
21362137
{
21372138
errorMessage = "Length mismatch";
21382139
exception = null;
@@ -2211,11 +2212,14 @@ private ExtensionObject ReadExtensionObject()
22112212
}
22122213

22132214
// any unread data indicates a decoding error.
2214-
long unused = length - (Position - start);
2215-
if (unused > 0)
2215+
if (length >= 0)
22162216
{
2217-
throw ServiceResultException.Create(StatusCodes.BadDecodingError,
2218-
"Cannot skip {0} bytes of unknown extension object body with type '{1}'.", unused, extension.TypeId);
2217+
long unused = length - (Position - start);
2218+
if (unused > 0)
2219+
{
2220+
throw ServiceResultException.Create(StatusCodes.BadDecodingError,
2221+
"Cannot skip {0} bytes of unknown extension object body with type '{1}'.", unused, extension.TypeId);
2222+
}
22192223
}
22202224

22212225
if (encodeable != null)
@@ -2307,7 +2311,7 @@ private Variant ReadVariantValue(string fieldName)
23072311

23082312
case BuiltInType.Boolean:
23092313
{
2310-
value.Set(ReadBoolean(null));
2314+
value.Set(SafeReadBoolean());
23112315
break;
23122316
}
23132317

@@ -2325,20 +2329,20 @@ private Variant ReadVariantValue(string fieldName)
23252329

23262330
case BuiltInType.Int16:
23272331
{
2328-
value.Set(ReadInt16(null));
2332+
value.Set(SafeReadInt16());
23292333
break;
23302334
}
23312335

23322336
case BuiltInType.UInt16:
23332337
{
2334-
value.Set(ReadUInt16(null));
2338+
value.Set(SafeReadUInt16());
23352339
break;
23362340
}
23372341

23382342
case BuiltInType.Int32:
23392343
case BuiltInType.Enumeration:
23402344
{
2341-
value.Set(ReadInt32(null));
2345+
value.Set(SafeReadInt32());
23422346
break;
23432347
}
23442348

@@ -2350,25 +2354,25 @@ private Variant ReadVariantValue(string fieldName)
23502354

23512355
case BuiltInType.Int64:
23522356
{
2353-
value.Set(ReadInt64(null));
2357+
value.Set(SafeReadInt64());
23542358
break;
23552359
}
23562360

23572361
case BuiltInType.UInt64:
23582362
{
2359-
value.Set(ReadUInt64(null));
2363+
value.Set(SafeReadUInt64());
23602364
break;
23612365
}
23622366

23632367
case BuiltInType.Float:
23642368
{
2365-
value.Set(ReadFloat(null));
2369+
value.Set(SafeReadFloat());
23662370
break;
23672371
}
23682372

23692373
case BuiltInType.Double:
23702374
{
2371-
value.Set(ReadDouble(null));
2375+
value.Set(SafeReadDouble());
23722376
break;
23732377
}
23742378

0 commit comments

Comments
 (0)