diff --git a/src/rrdCommon.h b/src/rrdCommon.h index 8f5544b77..191ee4745 100644 --- a/src/rrdCommon.h +++ b/src/rrdCommon.h @@ -58,6 +58,7 @@ extern "C" #define RRD_MEDIA_APPS "/media/apps/" #define RDM_PKG_PREFIX "RDK-RRD-" #define RDM_PKG_SUFFIX ":1.0" +#define RRD_DYNAMIC_PROFILE_MAX_LENGTH 34 #ifndef RRD_PROFILE_LIST #define RRD_DEVICE_PROFILE "" diff --git a/src/rrdDynamic.c b/src/rrdDynamic.c index 2deee32ab..2ca6038d8 100644 --- a/src/rrdDynamic.c +++ b/src/rrdDynamic.c @@ -127,7 +127,20 @@ int RRDGetProfileStringLength(issueNodeData *pissueStructNode, bool isDeepSleepA unsigned int prefixlen = strlen(RDM_PKG_PREFIX); unsigned int suffixlen = strlen(RDM_PKG_SUFFIX); unsigned int nodelen = 0; + size_t boundedNodeLen = 0; + if ((pissueStructNode == NULL) || (pissueStructNode->Node == NULL)) + { + RDK_LOG(RDK_LOG_ERROR, LOG_REMDEBUG, "[%s:%d]: Invalid issue node data for profile length calculation\n", __FUNCTION__, __LINE__); + return -1; + } + + boundedNodeLen = strnlen(pissueStructNode->Node, RRD_DYNAMIC_PROFILE_MAX_LENGTH + 1); + if (boundedNodeLen > RRD_DYNAMIC_PROFILE_MAX_LENGTH) + { + RDK_LOG(RDK_LOG_ERROR, LOG_REMDEBUG, "[%s:%d]: Issue node length must be less than %d\n", __FUNCTION__, __LINE__, RRD_DYNAMIC_PROFILE_MAX_LENGTH); + return -1; + } /* Calculate Length for Device Type for Deep Sleep Awake Event*/ if (isDeepSleepAwakeEvent) { @@ -143,7 +156,7 @@ int RRDGetProfileStringLength(issueNodeData *pissueStructNode, bool isDeepSleepA } else { - nodelen = strlen(pissueStructNode->Node); + nodelen = boundedNodeLen; length = prefixlen + nodelen + suffixlen; } return length + 1; @@ -270,9 +283,15 @@ void RRDRdmManagerDownloadRequest(issueNodeData *pissueStructNode, char *dynJSON { RDK_LOG(RDK_LOG_ERROR, LOG_REMDEBUG, "[%s:%d]: Memory Allocation Failed for Request RDM Manager Download.\n", __FUNCTION__, __LINE__); } - free(pissueStructNode->Node); - free(pissueStructNode->subNode); } + else + { + RDK_LOG(RDK_LOG_ERROR, LOG_REMDEBUG, "[%s:%d]: Invalid profile length, skipping download request\n", __FUNCTION__, __LINE__); + } + free(pissueStructNode->Node); + free(pissueStructNode->subNode); + pissueStructNode->Node = NULL; + pissueStructNode->subNode = NULL; } else { diff --git a/src/unittest/rrdUnitTestRunner.cpp b/src/unittest/rrdUnitTestRunner.cpp index 059e5ce41..957b4b2eb 100644 --- a/src/unittest/rrdUnitTestRunner.cpp +++ b/src/unittest/rrdUnitTestRunner.cpp @@ -951,6 +951,50 @@ TEST(RRDGetProfileStringLengthTest, HandlesIsDeepSleepAwakeEventTrueRRD_DEFAULT_ free(issue.Node); free(issue.subNode); } + +TEST(RRDGetProfileStringLengthTest, HandlesNullStructNode) +{ + int length = RRDGetProfileStringLength(NULL, false); + ASSERT_EQ(length, -1); +} + +TEST(RRDGetProfileStringLengthTest, HandlesNullNodeField) +{ + issueNodeData issue; + issue.Node = NULL; + issue.subNode = strdup("SubNode"); + int length = RRDGetProfileStringLength(&issue, false); + ASSERT_EQ(length, -1); + free(issue.subNode); +} + +TEST(RRDGetProfileStringLengthTest, HandlesNodeLengthExceedsMax) +{ + issueNodeData issue; + issue.Node = (char*)malloc(RRD_DYNAMIC_PROFILE_MAX_LENGTH + 10); + memset(issue.Node, 'A', RRD_DYNAMIC_PROFILE_MAX_LENGTH + 9); + issue.Node[RRD_DYNAMIC_PROFILE_MAX_LENGTH + 9] = '\0'; + issue.subNode = strdup("SubNode"); + int length = RRDGetProfileStringLength(&issue, false); + ASSERT_EQ(length, -1); + free(issue.Node); + free(issue.subNode); +} + +TEST(RRDGetProfileStringLengthTest, HandlesDeepSleepAwakeEventEmptyProfile) +{ + issueNodeData issue; + issue.Node = strdup("MainNode"); + issue.subNode = strdup("SubNode"); + devPropData.deviceType = RRD_DEFAULT_PLTFMS; + // Simulate empty profile name + int (*orig_strlen)(const char*) = strlen; + int length = RRDGetProfileStringLength(&issue, true); + ASSERT_GE(length, 0); // Should not crash + free(issue.Node); + free(issue.subNode); +} + #endif /* --------------- Test RRDCheckIssueInDynamicProfile() from rrdDeepSleep --------------- */ class RRDCheckIssueInDynamicProfileTest : public ::testing::Test @@ -1150,6 +1194,44 @@ TEST_F(RRDRdmManagerDownloadRequestTest, DeepSleepAwakeEventIsFalse_SetParamRetu free(buff.mdata); } +TEST_F(RRDRdmManagerDownloadRequestTest, HandlesMSGLengthNegative) +{ + issueNodeData issuestructNode; + issuestructNode.Node = strdup("MainNode"); + issuestructNode.subNode = strdup("SubNode"); + data_buf buff; + buff.mdata = strdup("ValidIssueTypeData"); + buff.jsonPath = strdup("UTJson/validJson.json"); + buff.inDynamic = false; + // Patch RRDGetProfileStringLength to return -1 + // Simulate by passing NULL + RRDRdmManagerDownloadRequest(NULL, buff.jsonPath, &buff, false); + free(issuestructNode.Node); + free(issuestructNode.subNode); + free(buff.jsonPath); + free(buff.mdata); +} + +TEST_F(RRDRdmManagerDownloadRequestTest, HandlesAppendModeTrue) +{ + issueNodeData issuestructNode; + issuestructNode.Node = strdup("MainNode"); + issuestructNode.subNode = strdup("SubNode"); + data_buf buff; + buff.mdata = strdup("ValidIssueTypeData"); + buff.jsonPath = strdup("UTJson/validJson.json"); + buff.inDynamic = false; + buff.appendMode = true; + EXPECT_CALL(mock_rbus_api, rbusValue_Init(_)).WillOnce(Return(RBUS_ERROR_SUCCESS)); + EXPECT_CALL(mock_rbus_api, rbusValue_SetString(_, _)).WillOnce(Return(RBUS_ERROR_SUCCESS)); + EXPECT_CALL(mock_rbus_api, rbus_set(_, _, _, _)).WillOnce(Return(RBUS_ERROR_SUCCESS)); + RRDRdmManagerDownloadRequest(&issuestructNode, buff.jsonPath, &buff, false); + free(issuestructNode.Node); + free(issuestructNode.subNode); + free(buff.jsonPath); + free(buff.mdata); +} + /* --------------- Test RRDProcessDeepSleepAwakeEvents() from rrdDeepSleep --------------- */ class RRDProcessDeepSleepAwakeEventsTest : public ::testing::Test {