Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce valid spec-conformant string encoding in TLV #30393

Merged
merged 16 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/chip-tool/args.gni
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ matter_enable_tracing_support = true

matter_log_json_payload_hex = true
matter_log_json_payload_decode_full = true

# make chip-tool very strict by default
chip_tlv_validate_char_string_on_read = true
chip_tlv_validate_char_string_on_write = true
11 changes: 9 additions & 2 deletions src/app/clusters/scenes-server/SceneTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,14 @@ class SceneTable
}
~SceneData(){};

bool operator==(const SceneData &other) const {
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
return (
(CharSpan(mName, mNameLength) == CharSpan(other.mName, other.mNameLength)) &&
(mSceneTransitionTimeMs == other.mSceneTransitionTimeMs) &&
(mExtensionFieldSets == other.mExtensionFieldSets)
);
}

void SetName(const CharSpan & sceneName)
{
if (nullptr == sceneName.data())
Expand All @@ -203,8 +211,7 @@ class SceneTable

void Clear()
{
SetName(CharSpan());

memset(mName, 0, sizeof(mName));
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
mSceneTransitionTimeMs = 0;
mExtensionFieldSets.Clear();
}
Expand Down
3 changes: 2 additions & 1 deletion src/app/clusters/scenes-server/SceneTableImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ struct SceneTableData : public SceneTableEntry, PersistentData<kPersistentSceneB

CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
{
CharSpan nameSpan(mStorageData.mName, mStorageData.mNameLength);
// TODO: if we have mNameLength, should this bin ByteSpan instead?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this comment.

CharSpan nameSpan(mStorageData.mName, strnlen(mStorageData.mName, mStorageData.mNameLength));
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
TLV::TLVType container;
ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ void TimeSynchronizationServer::InitTimeZone()
for (auto & tzStore : mTimeZoneObj.timeZoneList)
{
memset(tzStore.name, 0, sizeof(tzStore.name));
tzStore.timeZone = { .offset = 0, .validAt = 0, .name = MakeOptional(CharSpan(tzStore.name, sizeof(tzStore.name))) };
tzStore.timeZone = { .offset = 0, .validAt = 0, .name = MakeOptional(CharSpan(tzStore.name, 0)) };
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks wrong to me. The right thing to set .name to here is NullOptional, not empty string.

}
}

Expand Down
2 changes: 2 additions & 0 deletions src/lib/core/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ buildconfig_header("chip_buildconfig") {
"CHIP_CONFIG_MINMDNS_MAX_PARALLEL_RESOLVES=${chip_config_minmdns_max_parallel_resolves}",
"CHIP_CONFIG_CANCELABLE_HAS_INFO_STRING_FIELD=${chip_config_cancelable_has_info_string_field}",
"CHIP_CONFIG_BIG_ENDIAN_TARGET=${chip_target_is_big_endian}",
"CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_WRITE=${chip_tlv_validate_char_string_on_write}",
"CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ=${chip_tlv_validate_char_string_on_read}",
]
}

Expand Down
6 changes: 6 additions & 0 deletions src/lib/core/CHIPError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,18 @@ bool FormatCHIPError(char * buf, uint16_t bufSize, CHIP_ERROR err)
case CHIP_ERROR_WRONG_ENCRYPTION_TYPE.AsInteger():
desc = "Wrong encryption type";
break;
case CHIP_ERROR_INVALID_UTF8.AsInteger():
desc = "Character string is not a valid utf-8 encoding";
break;
case CHIP_ERROR_INTEGRITY_CHECK_FAILED.AsInteger():
desc = "Integrity check failed";
break;
case CHIP_ERROR_INVALID_SIGNATURE.AsInteger():
desc = "Invalid signature";
break;
case CHIP_ERROR_INVALID_TLV_CHAR_STRING.AsInteger():
desc = "Invalid TLV Char string encoding.";
break;
case CHIP_ERROR_UNSUPPORTED_SIGNATURE_TYPE.AsInteger():
desc = "Unsupported signature type";
break;
Expand Down
19 changes: 17 additions & 2 deletions src/lib/core/CHIPError.h
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,14 @@ using CHIP_ERROR = ::chip::ChipError;
*/
#define CHIP_ERROR_WRONG_ENCRYPTION_TYPE CHIP_CORE_ERROR(0x11)

// AVAILABLE: 0x12
/**
* @def CHIP_ERROR_INVALID_UTF8
*
* @brief
* Invalid UTF8 string (contains some characters that are invalid)
*
*/
#define CHIP_ERROR_INVALID_UTF8 CHIP_CORE_ERROR(0x12)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please align the indentation with the other errors.


/**
* @def CHIP_ERROR_INTEGRITY_CHECK_FAILED
Expand All @@ -602,7 +609,15 @@ using CHIP_ERROR = ::chip::ChipError;
*/
#define CHIP_ERROR_INVALID_SIGNATURE CHIP_CORE_ERROR(0x14)

// AVAILABLE: 0x15
/**
* @def CHIP_ERROR_INVALID_TLV_CHAR_STRING
*
* @brief
* Invalid TLV character string (e.g. null terminator)
*
*/
#define CHIP_ERROR_INVALID_TLV_CHAR_STRING CHIP_CORE_ERROR(0x15)
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

// AVAILABLE: 0x16

/**
Expand Down
20 changes: 20 additions & 0 deletions src/lib/core/TLVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/SafeInt.h>
#include <lib/support/utf8.h>

namespace chip {
namespace TLV {
Expand Down Expand Up @@ -330,6 +331,25 @@ CHIP_ERROR TLVReader::Get(CharSpan & v) const
}

v = CharSpan(Uint8::to_const_char(bytes), len);
#if CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
// Spec requirement: A.11.2. UTF-8 and Octet Strings
//
// For UTF-8 strings, the value octets SHALL encode a valid
// UTF-8 character (code points) sequence.
//
// Senders SHALL NOT include a terminating null character to
// mark the end of a string.

if (!Utf8::IsValid(v))
{
return CHIP_ERROR_INVALID_UTF8;
}

if ((len > 0) && (v[len - 1] == 0))
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
{
return CHIP_ERROR_INVALID_TLV_CHAR_STRING;
}
#endif // CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
return CHIP_NO_ERROR;
}

Expand Down
23 changes: 22 additions & 1 deletion src/lib/core/TLVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/SafeInt.h>
#include <lib/support/utf8.h>

#include <stdarg.h>
#include <stdint.h>
Expand Down Expand Up @@ -252,10 +253,30 @@ CHIP_ERROR TLVWriter::PutString(Tag tag, const char * buf)

CHIP_ERROR TLVWriter::PutString(Tag tag, const char * buf, uint32_t len)
{
#if CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_WRITE
// Spec requirement: A.11.2. UTF-8 and Octet Strings
//
// For UTF-8 strings, the value octets SHALL encode a valid
// UTF-8 character (code points) sequence.
//
// Senders SHALL NOT include a terminating null character to
// mark the end of a string.

if (!Utf8::IsValid(CharSpan(buf, len)))
{
return CHIP_ERROR_INVALID_UTF8;
}

if ((len > 0) && (buf[len - 1] == 0))
{
return CHIP_ERROR_INVALID_TLV_CHAR_STRING;
}
#endif // CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ

return WriteElementWithData(kTLVType_UTF8String, tag, reinterpret_cast<const uint8_t *>(buf), len);
}

CHIP_ERROR TLVWriter::PutString(Tag tag, Span<const char> str)
CHIP_ERROR TLVWriter::PutString(Tag tag, CharSpan str)
{
if (!CanCastTo<uint32_t>(str.size()))
{
Expand Down
2 changes: 1 addition & 1 deletion src/lib/core/TLVWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ class DLL_EXPORT TLVWriter
* TLVBackingStore.
*
*/
CHIP_ERROR PutString(Tag tag, Span<const char> str);
CHIP_ERROR PutString(Tag tag, CharSpan str);

/**
* @brief
Expand Down
7 changes: 7 additions & 0 deletions src/lib/core/core.gni
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ declare_args() {

# Whether the target architecture is big-endian (true) or little-endian (false).
chip_target_is_big_endian = false

# Validation on TLV encode/decode for string validity of character
# strings:
# - SHALL NOT end with binary 0 (spec still allows embedded 0)
# - SHALL be valid UTF8
chip_tlv_validate_char_string_on_write = true
chip_tlv_validate_char_string_on_read = false
}

if (chip_target_style == "") {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/core/tests/TestCHIPErrorStr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ static const CHIP_ERROR kTestElements[] =
CHIP_ERROR_UNKNOWN_KEY_TYPE,
CHIP_ERROR_KEY_NOT_FOUND,
CHIP_ERROR_WRONG_ENCRYPTION_TYPE,
CHIP_ERROR_INVALID_UTF8,
CHIP_ERROR_INTEGRITY_CHECK_FAILED,
CHIP_ERROR_INVALID_SIGNATURE,
CHIP_ERROR_INVALID_TLV_CHAR_STRING,
CHIP_ERROR_UNSUPPORTED_SIGNATURE_TYPE,
CHIP_ERROR_INVALID_MESSAGE_LENGTH,
CHIP_ERROR_BUFFER_TOO_SMALL,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/support/tests/TestTlvJson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ void TestConverter(nlTestSuite * inSuite, void * inContext)
"}\n");

const char charBuf[] = "hello";
CharSpan charSpan(charBuf);
CharSpan charSpan = CharSpan::fromCharString(charBuf);
EncodeAndValidate(charSpan,
"{\n"
" \"value\" : \"hello\"\n"
Expand Down
Loading