From d11cc040fdbc241a633cb23da1f3b17084cf42fb Mon Sep 17 00:00:00 2001 From: 0xDragon Date: Thu, 9 Jul 2026 01:33:14 +0700 Subject: [PATCH] [spinel] validate DNSSD host address count (#13283) Handle empty DNS-SD host address lists and consume all encoded IPv6 addresses when the address count is greater than one. Add unit coverage for empty lists, multiple addresses, and malformed counts. Co-authored-by: huynhtrungcip --- src/lib/spinel/spinel_prop_codec.cpp | 18 +++++++- tests/unit/test_spinel_prop_codec.cpp | 65 ++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/lib/spinel/spinel_prop_codec.cpp b/src/lib/spinel/spinel_prop_codec.cpp index 9751d3030..3e6e79041 100644 --- a/src/lib/spinel/spinel_prop_codec.cpp +++ b/src/lib/spinel/spinel_prop_codec.cpp @@ -124,7 +124,23 @@ otError DecodeDnssdHost(Decoder &aDecoder, SuccessOrExit(error = aDecoder.ReadUtf8(aHost.mHostName)); SuccessOrExit(error = aDecoder.ReadUint16(aHost.mAddressesLength)); - SuccessOrExit(error = aDecoder.ReadIp6Address(aHost.mAddresses)); + + if (aHost.mAddressesLength == 0) + { + aHost.mAddresses = nullptr; + } + else + { + SuccessOrExit(error = aDecoder.ReadIp6Address(aHost.mAddresses)); + + for (uint16_t i = 1; i < aHost.mAddressesLength; i++) + { + const otIp6Address *address; + + SuccessOrExit(error = aDecoder.ReadIp6Address(address)); + } + } + SuccessOrExit(error = aDecoder.ReadUint32(aRequestId)); SuccessOrExit(error = aDecoder.ReadData(aCallbackData, aCallbackDataLen)); diff --git a/tests/unit/test_spinel_prop_codec.cpp b/tests/unit/test_spinel_prop_codec.cpp index 458d3e75f..becb9569f 100644 --- a/tests/unit/test_spinel_prop_codec.cpp +++ b/tests/unit/test_spinel_prop_codec.cpp @@ -72,13 +72,15 @@ void TestDnssd(void) otPlatDnssdHost dnssdHostDecode; otIp6Address dnssdHostAddrs[] = { {0xfd, 0x2a, 0xc3, 0x0c, 0x87, 0xd3, 0x00, 0x01, 0xed, 0x1c, 0x0c, 0x91, 0xcc, 0xb6, 0x57, 0x8b}, + {0xfd, 0x2a, 0xc3, 0x0c, 0x87, 0xd3, 0x00, 0x01, 0xed, 0x1c, 0x0c, 0x91, 0xcc, 0xb6, 0x57, 0x8c}, + {0xfd, 0x2a, 0xc3, 0x0c, 0x87, 0xd3, 0x00, 0x01, 0xed, 0x1c, 0x0c, 0x91, 0xcc, 0xb6, 0x57, 0x8d}, }; otPlatDnssdRequestId requestId; const uint8_t *callbackData; uint16_t callbackDataLen; dnssdHostEncode.mHostName = "ot-host1"; dnssdHostEncode.mAddresses = dnssdHostAddrs; - dnssdHostEncode.mAddressesLength = 1; + dnssdHostEncode.mAddressesLength = sizeof(dnssdHostAddrs) / sizeof(dnssdHostAddrs[0]); SuccessOrQuit(error = encoder.BeginFrame(SPINEL_HEADER_FLAG, SPINEL_CMD_PROP_VALUE_INSERTED)); SuccessOrQuit(error = EncodeDnssd(encoder, dnssdHostEncode, 1 /* aRequestId */, DnssdFakeCallback)); @@ -103,6 +105,67 @@ void TestDnssd(void) VerifyOrQuit(callbackDataLen == sizeof(otPlatDnssdRegisterCallback)); VerifyOrQuit(*reinterpret_cast(callbackData) == DnssdFakeCallback); + ncpBuffer.Clear(); + dnssdHostEncode.mHostName = "ot-host-empty"; + dnssdHostEncode.mAddresses = nullptr; + dnssdHostEncode.mAddressesLength = 0; + + SuccessOrQuit(error = encoder.BeginFrame(SPINEL_HEADER_FLAG, SPINEL_CMD_PROP_VALUE_INSERTED)); + SuccessOrQuit(error = EncodeDnssd(encoder, dnssdHostEncode, 10 /* aRequestId */, DnssdFakeCallback)); + SuccessOrQuit(error = encoder.EndFrame()); + SuccessOrQuit(ncpBuffer.OutFrameBegin()); + len = ncpBuffer.OutFrameGetLength(); + VerifyOrQuit(ncpBuffer.OutFrameRead(len, buf) == len); + + decoder.Init(buf, len); + SuccessOrQuit(error = decoder.ReadUint8(header)); + VerifyOrQuit(header == SPINEL_HEADER_FLAG); + SuccessOrQuit(error = decoder.ReadUintPacked(command)); + VerifyOrQuit(command == SPINEL_CMD_PROP_VALUE_INSERTED); + SuccessOrQuit(error = decoder.ReadUintPacked(propKey)); + VerifyOrQuit(static_cast(propKey) == SPINEL_PROP_DNSSD_HOST); + SuccessOrQuit(error = DecodeDnssdHost(decoder, dnssdHostDecode, requestId, callbackData, callbackDataLen)); + VerifyOrQuit(strcmp(dnssdHostDecode.mHostName, dnssdHostEncode.mHostName) == 0); + VerifyOrQuit(dnssdHostDecode.mAddressesLength == 0); + VerifyOrQuit(dnssdHostDecode.mAddresses == nullptr); + VerifyOrQuit(requestId == 10); + VerifyOrQuit(callbackDataLen == sizeof(otPlatDnssdRegisterCallback)); + VerifyOrQuit(*reinterpret_cast(callbackData) == DnssdFakeCallback); + + ncpBuffer.Clear(); + dnssdHostEncode.mHostName = "ot-host-short"; + dnssdHostEncode.mAddresses = dnssdHostAddrs; + dnssdHostEncode.mAddressesLength = 1; + + SuccessOrQuit(error = encoder.BeginFrame(SPINEL_HEADER_FLAG, SPINEL_CMD_PROP_VALUE_INSERTED)); + SuccessOrQuit(error = EncodeDnssd(encoder, dnssdHostEncode, 11 /* aRequestId */, DnssdFakeCallback)); + SuccessOrQuit(error = encoder.EndFrame()); + SuccessOrQuit(ncpBuffer.OutFrameBegin()); + len = ncpBuffer.OutFrameGetLength(); + VerifyOrQuit(ncpBuffer.OutFrameRead(len, buf) == len); + + decoder.Init(buf, len); + SuccessOrQuit(error = decoder.ReadUint8(header)); + SuccessOrQuit(error = decoder.ReadUintPacked(command)); + SuccessOrQuit(error = decoder.ReadUintPacked(propKey)); + { + const char *hostName; + + SuccessOrQuit(error = decoder.ReadUtf8(hostName)); + } + + buf[decoder.GetReadLength()] = 2; + buf[decoder.GetReadLength() + 1] = 0; + + decoder.Init(buf, len); + SuccessOrQuit(error = decoder.ReadUint8(header)); + VerifyOrQuit(header == SPINEL_HEADER_FLAG); + SuccessOrQuit(error = decoder.ReadUintPacked(command)); + VerifyOrQuit(command == SPINEL_CMD_PROP_VALUE_INSERTED); + SuccessOrQuit(error = decoder.ReadUintPacked(propKey)); + VerifyOrQuit(static_cast(propKey) == SPINEL_PROP_DNSSD_HOST); + VerifyOrQuit(DecodeDnssdHost(decoder, dnssdHostDecode, requestId, callbackData, callbackDataLen) == OT_ERROR_PARSE); + // Test DnssdService encoding and decoding otPlatDnssdService dnssdServiceEncode; otPlatDnssdService dnssdServiceDecode;