From ed6235304b4380eccc483d962e425370ae4cabcc Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 26 Dec 2025 20:10:12 -0800 Subject: [PATCH] [joiner] enhance string TLV input validation (#12245) This commit introduces a new generic method `Tlv::ValidateStringValue()` to provide a unified way of validating string values intended for use in string-valued TLVs. This new method checks that a given C string is a valid UTF-8 string and that its length does not exceed the maximum length defined by the `StringTlvType`. The `Joiner::Start()` method is updated to use this new validation method, which simplifies the code by replacing several explicit and repetitive checks. This improves code clarity and maintainability by centralizing the string validation logic. This commit also adds missing validation for `aVendorModel` in `Joiner::Start()` --- src/core/common/tlvs.cpp | 13 +++++++++++++ src/core/common/tlvs.hpp | 23 +++++++++++++++++++++++ src/core/meshcop/joiner.cpp | 7 ++++--- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/core/common/tlvs.cpp b/src/core/common/tlvs.cpp index a91db29fe..2fe410ba1 100644 --- a/src/core/common/tlvs.cpp +++ b/src/core/common/tlvs.cpp @@ -257,6 +257,19 @@ Error Tlv::AppendStringTlv(Message &aMessage, uint8_t aType, uint8_t aMaxStringL return AppendTlv(aMessage, aType, aValue, static_cast(length)); } +Error Tlv::ValidateStringTlvValue(uint8_t aMaxStringLength, const char *aStringValue) +{ + Error error = kErrorNone; + + VerifyOrExit(aStringValue != nullptr); + + VerifyOrExit(StringLength(aStringValue, aMaxStringLength + 1) <= aMaxStringLength, error = kErrorInvalidArgs); + VerifyOrExit(IsValidUtf8String(aStringValue), error = kErrorInvalidArgs); + +exit: + return error; +} + template Error Tlv::AppendUintTlv(Message &aMessage, uint8_t aType, UintType aValue) { UintType value = BigEndian::HostSwap(aValue); diff --git a/src/core/common/tlvs.hpp b/src/core/common/tlvs.hpp index 56261538e..89014d5a0 100644 --- a/src/core/common/tlvs.hpp +++ b/src/core/common/tlvs.hpp @@ -42,6 +42,7 @@ #include "common/const_cast.hpp" #include "common/encoding.hpp" #include "common/error.hpp" +#include "common/numeric_limits.hpp" #include "common/offset_range.hpp" #include "common/type_traits.hpp" @@ -633,6 +634,27 @@ public: return AppendStringTlv(aMessage, StringTlvType::kType, StringTlvType::kMaxStringLength, aValue); } + /** + * Validates a given string value for a simple TLV with a UTF-8 string value. + * + * The @p aValue can be `nullptr` in which case it is treated as an empty string. + * + * @tparam StringTlvType The simple TLV type for which to validate the value (must be a sub-class of + * `StringTlvInfo`). + * + * @param[in] aValue A pointer to a C string to validate. + * + * @retval kErrorNone The string value is valid for the given `StringTlvType`. + * @retval kErrorInvalidArgs The string is not a valid UTF-8 string or its length is longer than the max allowed + * length specified by `StringTlvType::kMaxStringLength`. + */ + template static Error ValidateStringValue(const char *aValue) + { + static_assert(StringTlvType::kMaxStringLength < NumericLimits::kMax, "String TLV length is invalid"); + + return ValidateStringTlvValue(StringTlvType::kMaxStringLength, aValue); + } + //------------------------------------------------------------------------------------------------------------------ // Static methods for finding TLVs within a sequence of TLVs. @@ -699,6 +721,7 @@ private: static Error ReadStringTlv(const Message &aMessage, uint16_t aOffset, uint8_t aMaxStringLength, char *aValue); static Error FindStringTlv(const Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, char *aValue); static Error AppendStringTlv(Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, const char *aValue); + static Error ValidateStringTlvValue(uint8_t aMaxStringLength, const char *aStringValue); template static Error ReadUintTlv(const Message &aMessage, uint16_t aOffset, UintType &aValue); template static Error FindUintTlv(const Message &aMessage, uint8_t aType, UintType &aValue); template static Error AppendUintTlv(Message &aMessage, uint8_t aType, UintType aValue); diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index ae60510ef..557583b9a 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -120,9 +120,10 @@ Error Joiner::Start(const char *aPskd, LogInfo("Joiner starting"); - VerifyOrExit(aProvisioningUrl == nullptr || IsValidUtf8String(aProvisioningUrl), error = kErrorInvalidArgs); - VerifyOrExit(aVendorName == nullptr || IsValidUtf8String(aVendorName), error = kErrorInvalidArgs); - VerifyOrExit(aVendorSwVersion == nullptr || IsValidUtf8String(aVendorSwVersion), error = kErrorInvalidArgs); + SuccessOrExit(error = Tlv::ValidateStringValue(aProvisioningUrl)); + SuccessOrExit(error = Tlv::ValidateStringValue(aVendorName)); + SuccessOrExit(error = Tlv::ValidateStringValue(aVendorModel)); + SuccessOrExit(error = Tlv::ValidateStringValue(aVendorSwVersion)); VerifyOrExit(mState == kStateIdle, error = kErrorBusy); VerifyOrExit(Get().IsUp() && Get().GetRole() == Mle::kRoleDisabled,