From c0844b601adb3c3575aadc0edc1b6cd222890107 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Wed, 14 Oct 2026 05:25:55 +0000 Subject: [PATCH 01/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/reportgen/reportgen.c | 24 +++++++++++++++++++++--- source/t2parser/t2parserxconf.c | 9 ++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/source/reportgen/reportgen.c b/source/reportgen/reportgen.c index 98834b1f..55310a0a 100644 --- a/source/reportgen/reportgen.c +++ b/source/reportgen/reportgen.c @@ -249,7 +249,13 @@ static T2ERROR applyRegexToValue(char** inputValue, const char* regexPattern) { T2Debug("regexec successful, Match is found %.*s\n", pmatch[0].rm_eo - pmatch[0].rm_so, &(*inputValue)[pmatch[0].rm_so]); - sprintf(string, "%.*s", pmatch[0].rm_eo - pmatch[0].rm_so, &(*inputValue)[pmatch[0].rm_so]); + // Bounds check: ensure match length doesn't exceed buffer + int matchLen = pmatch[0].rm_eo - pmatch[0].rm_so; + if (matchLen >= (int)sizeof(string)) { + T2Warning("Regex match too long: %d bytes, truncating to %zu\n", matchLen, sizeof(string) - 1); + matchLen = sizeof(string) - 1; + } + snprintf(string, sizeof(string), "%.*s", matchLen, &(*inputValue)[pmatch[0].rm_so]); free(*inputValue); *inputValue = strdup(string); if (*inputValue == NULL) @@ -1031,7 +1037,13 @@ T2ERROR encodeGrepResultInJSON(cJSON *valArray, Vector *grepMarkerList) else { T2Debug("regexec successful, Match is found %.*s\n", pmatch[0].rm_eo - pmatch[0].rm_so, &stringValue[pmatch[0].rm_so]); - sprintf(string[i], "%.*s", pmatch[0].rm_eo - pmatch[0].rm_so, &stringValue[pmatch[0].rm_so]); + // Bounds check: ensure match length doesn't exceed buffer + int matchLen = pmatch[0].rm_eo - pmatch[0].rm_so; + if (matchLen >= (int)sizeof(string[0])) { + T2Warning("Regex match too long: %d bytes, truncating to %zu\n", matchLen, sizeof(string[0]) - 1); + matchLen = sizeof(string[0]) - 1; + } + snprintf(string[i], sizeof(string[i]), "%.*s", matchLen, &stringValue[pmatch[0].rm_so]); } Vector_PushBack(regaccumulateValues, string[i]); } @@ -1402,7 +1414,13 @@ T2ERROR encodeEventMarkersInJSON(cJSON *valArray, Vector *eventMarkerList) else { T2Debug("regexec successful, Match is found %.*s\n", pmatch[0].rm_eo - pmatch[0].rm_so, &stringValue[pmatch[0].rm_so]); - sprintf(string, "%.*s", pmatch[0].rm_eo - pmatch[0].rm_so, &stringValue[pmatch[0].rm_so]); + // Bounds check: ensure match length doesn't exceed buffer + int matchLen = pmatch[0].rm_eo - pmatch[0].rm_so; + if (matchLen >= (int)sizeof(string)) { + T2Warning("Regex match too long: %d bytes, truncating to %zu\n", matchLen, sizeof(string) - 1); + matchLen = sizeof(string) - 1; + } + snprintf(string, sizeof(string), "%.*s", matchLen, &stringValue[pmatch[0].rm_so]); strncpy(stringValue, string, strlen(string) + 1); } regfree(®pattern); diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index 8e39cbe5..0b2ef344 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -65,7 +65,14 @@ static int getScheduleInSeconds(const char* cronPattern) discardPatternLen = strlen(discardPattern); int timeInMinDataLen = inputMatchSize - discardPatternLen; char scheduleString[10] = { '\0' }; - strncpy(scheduleString, inputMatchPattern, timeInMinDataLen); + // Bounds check: ensure the schedule string doesn't exceed buffer + if (timeInMinDataLen >= sizeof(scheduleString)) { + T2Error("Schedule string too long: %d bytes, max %zu\n", timeInMinDataLen, sizeof(scheduleString) - 1); + free(input); + return -1; + } + strncpy(scheduleString, inputMatchPattern, sizeof(scheduleString) - 1); + scheduleString[sizeof(scheduleString) - 1] = '\0'; scheduleIntervalInMin = atoi(scheduleString); } From a06d38a73f0a1cea9572e5b6ad0788b6543d8b18 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Wed, 14 Oct 2026 11:54:38 +0000 Subject: [PATCH 02/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/protocol/http/multicurlinterface.c | 1 - source/t2parser/t2parserxconf.c | 172 +++++++++++++++++++++ source/test/t2parser/t2parserxconfTest.cpp | 29 +++- 3 files changed, 197 insertions(+), 5 deletions(-) diff --git a/source/protocol/http/multicurlinterface.c b/source/protocol/http/multicurlinterface.c index 47baa89c..3e76905f 100644 --- a/source/protocol/http/multicurlinterface.c +++ b/source/protocol/http/multicurlinterface.c @@ -626,7 +626,6 @@ static void configure_wan_interface(CURL *easy) } #endif - T2ERROR http_pool_get(const char *url, char **response_data, bool enable_file_output) { T2Debug("%s ++in\n", __FUNCTION__); diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index 0b2ef344..fc9b4847 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "t2parserxconf.h" #include "xconfclient.h" @@ -45,6 +47,169 @@ #define ACCUMULATE_MARKER_SUFFIX "_accum" #define MAX_PARAM_LEN 15 +static bool is_valid_https_upload_url(const char *url) +{ + if (url == NULL || *url == '\0') + { + return false; + } + + char url_copy[2048]; + size_t url_len = strlen(url); + if (url_len == 0 || url_len >= sizeof(url_copy)) + { + return false; + } + + snprintf(url_copy, sizeof(url_copy), "%s", url); + char *scheme_end = strstr(url_copy, "://"); + if (scheme_end == NULL) + { + return false; + } + + *scheme_end = '\0'; + if (strcasecmp(url_copy, "https") != 0) + { + return false; + } + + char *authority = scheme_end + 3; + if (*authority == '\0') + { + return false; + } + + if (strchr(authority, '@') != NULL) + { + return false; + } + + char *path_start = strchr(authority, '/'); + if (path_start != NULL) + { + *path_start = '\0'; + } + + char *query_start = strchr(authority, '?'); + if (query_start != NULL) + { + *query_start = '\0'; + } + + char *fragment_start = strchr(authority, '#'); + if (fragment_start != NULL) + { + *fragment_start = '\0'; + } + + char host[256]; + memset(host, 0, sizeof(host)); + if (authority[0] == '[') + { + char *close_bracket = strchr(authority, ']'); + if (close_bracket == NULL) + { + return false; + } + size_t host_len = (size_t)(close_bracket - authority - 1); + if (host_len == 0 || host_len >= sizeof(host)) + { + return false; + } + memcpy(host, authority + 1, host_len); + host[host_len] = '\0'; + } + else + { + char *port_sep = strrchr(authority, ':'); + if (port_sep != NULL) + { + char *first_colon = strchr(authority, ':'); + if (first_colon != NULL && first_colon != port_sep) + { + return false; + } + + size_t host_len = (size_t)(port_sep - authority); + if (host_len == 0 || host_len >= sizeof(host)) + { + return false; + } + memcpy(host, authority, host_len); + host[host_len] = '\0'; + + char *port_value = port_sep + 1; + if (*port_value == '\0') + { + return false; + } + for (char *p = port_value; *p != '\0'; ++p) + { + if (*p < '0' || *p > '9') + { + return false; + } + } + } + else + { + size_t hostname_len = strlen(authority); + if (hostname_len == 0 || hostname_len >= sizeof(host)) + { + return false; + } + snprintf(host, sizeof(host), "%s", authority); + } + } + + if (host[0] == '\0') + { + return false; + } + + char lower_host[256]; + size_t host_len = strlen(host); + if (host_len >= sizeof(lower_host)) + { + return false; + } + for (size_t i = 0; i < host_len; ++i) + { + lower_host[i] = (char)tolower((unsigned char)host[i]); + } + lower_host[host_len] = '\0'; + + if (strcmp(lower_host, "localhost") == 0 || + strcmp(lower_host, "localhost.localdomain") == 0 || + (host_len >= 10 && strncmp(lower_host, "localhost.", 10) == 0) || + (host_len >= 6 && strcmp(lower_host + host_len - 6, ".local") == 0) || + (host_len >= 9 && strcmp(lower_host + host_len - 9, ".internal") == 0)) + { + return false; + } + + struct in_addr addr; + if (inet_pton(AF_INET, host, &addr) == 1) + { + uint32_t ip = ntohl(addr.s_addr); + if ((ip & 0xFF000000u) == 0x7F000000u || + (ip & 0xFF000000u) == 0x00000000u || + (ip & 0xFF000000u) == 0x0A000000u || + (ip & 0xFFF00000u) == 0xAC100000u || + (ip & 0xFFFF0000u) == 0xC0A80000u || + (ip & 0xFFFF0000u) == 0xA9FE0000u || + (ip & 0xFFC00000u) == 0x64400000u || + (ip & 0xFF000000u) == 0xE0000000u || + (ip & 0xFF000000u) == 0xF0000000u) + { + return false; + } + } + + return true; +} + static int getScheduleInSeconds(const char* cronPattern) { unsigned int scheduleIntervalInMin = 15; // Default value from field settings @@ -259,6 +424,13 @@ T2ERROR processConfigurationXConf(char* configData, ProfileXConf **localProfile) return T2ERROR_FAILURE; } + if (!is_valid_https_upload_url(juploadUrl->valuestring)) + { + T2Error("Rejected invalid upload URL in XCONF profile: %s\n", juploadUrl->valuestring ? juploadUrl->valuestring : "(null)"); + cJSON_Delete(json_root); + return T2ERROR_FAILURE; + } + int reportIntervalInSec = getScheduleInSeconds(jschedule->valuestring); T2Info("Received profile name : %s with interval of : %d secs and upload url : %s \n", jprofileName->valuestring, reportIntervalInSec, juploadUrl->valuestring); diff --git a/source/test/t2parser/t2parserxconfTest.cpp b/source/test/t2parser/t2parserxconfTest.cpp index 9f6b2864..d29f5abf 100644 --- a/source/test/t2parser/t2parserxconfTest.cpp +++ b/source/test/t2parser/t2parserxconfTest.cpp @@ -29,7 +29,7 @@ TEST(T2ParserXConf, DefaultScheduleUsed) "{" " \"urn:settings:TelemetryProfile\": {" " \"telemetryProfile:name\": \"DefaultSched\"," - " \"uploadRepository:URL\": \"http://example.com/upload\"," + " \"uploadRepository:URL\": \"https://example.com/upload\"," " \"schedule\": \"11 4 * * *\"," " \"telemetryProfile\": [ {" " \"header\": \"param1\"," @@ -44,7 +44,7 @@ TEST(T2ParserXConf, DefaultScheduleUsed) // default should be 15 minutes -> 900 seconds EXPECT_EQ(900, profile->reportingInterval); ASSERT_NE(profile->t2HTTPDest, nullptr); - EXPECT_STREQ("http://example.com/upload", profile->t2HTTPDest->URL ? profile->t2HTTPDest->URL : ""); + EXPECT_STREQ("https://example.com/upload", profile->t2HTTPDest->URL ? profile->t2HTTPDest->URL : ""); // minimal cleanup (full deep-free is not attempted here) // tests rely on process teardown to reclaim memory in CI runs } @@ -61,7 +61,7 @@ TEST(T2ParserXConf, SlashScheduleAndTopLogHandling) "{" " \"urn:settings:TelemetryProfile\": {" " \"telemetryProfile:name\": \"SlashSched\"," - " \"uploadRepository:URL\": \"http://example.com/upload2\"," + " \"uploadRepository:URL\": \"https://example.com/upload2\"," " \"schedule\": \"0/5 * * * *\"," " \"telemetryProfile\": [" " {" @@ -84,8 +84,29 @@ TEST(T2ParserXConf, SlashScheduleAndTopLogHandling) // schedule "0/5 * * * *" should parse to 5 minutes => 300 sec EXPECT_EQ(300, profile->reportingInterval); ASSERT_NE(profile->t2HTTPDest, nullptr); - EXPECT_STREQ("http://example.com/upload2", profile->t2HTTPDest->URL ? profile->t2HTTPDest->URL : ""); + EXPECT_STREQ("https://example.com/upload2", profile->t2HTTPDest->URL ? profile->t2HTTPDest->URL : ""); // Ensure the profile name got set EXPECT_STREQ("SlashSched", profile->name ? profile->name : ""); } +TEST(T2ParserXConf, RejectsInvalidUploadUrl) +{ + ProfileXConf *profile = NULL; + const char *json_invalid_url = + "{" + " \"urn:settings:TelemetryProfile\": {" + " \"telemetryProfile:name\": \"BadUrl\"," + " \"uploadRepository:URL\": \"http://localhost/test\"," + " \"schedule\": \"0/5 * * * *\"," + " \"telemetryProfile\": [ {" + " \"header\": \"param1\"," + " \"content\": \"alias1\"," + " \"type\": \"/var/log/some.log\"," + " \"pollingFrequency\": \"0\"" + " } ]" + " }" + "}"; + EXPECT_EQ(T2ERROR_FAILURE, processConfigurationXConf((char*)json_invalid_url, &profile)); + EXPECT_EQ((ProfileXConf*)NULL, profile); +} + From 788051b2944471233ad8e4081a1e264297b364a7 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Wed, 21 Oct 2026 10:51:55 +0000 Subject: [PATCH 03/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/bulkdata/reportprofiles.c | 27 ++++--- source/bulkdata/t2eventreceiver.c | 7 +- source/protocol/http/multicurlinterface.c | 7 +- source/utils/t2common.c | 98 +++++++++++++++++++++++ source/utils/t2common.h | 5 ++ 5 files changed, 128 insertions(+), 16 deletions(-) diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index 080b4197..cf07f3e7 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "reportprofiles.h" #include "xconfclient.h" @@ -50,6 +51,7 @@ #include "t2parser.h" #include "telemetry2_0.h" #include "t2MtlsUtils.h" +#include "t2common.h" #include "persistence.h" #ifdef LIBRDKCERTSEL_BUILD #include "curlinterface.h" @@ -622,8 +624,14 @@ T2ERROR initReportProfiles() check_component_crash(TELEMETRY_INIT_FILE_BOOTUP); //Touching TELEMETRY_INIT_FILE_BOOTUP during Bootup - system("touch /tmp/telemetry_initialized_bootup"); - T2Debug(" %s Touched \n", TELEMETRY_INIT_FILE_BOOTUP); + if (!createSecureTempFlag(TELEMETRY_INIT_FILE_BOOTUP)) + { + T2Error("Failed to create secure boot flag %s\n", TELEMETRY_INIT_FILE_BOOTUP); + } + else + { + T2Debug(" %s Touched \n", TELEMETRY_INIT_FILE_BOOTUP); + } } #endif //Web Config Framework init ends @@ -642,11 +650,9 @@ T2ERROR initReportProfiles() { unregisterDEforCompEventList(); createComponentDataElements(); - FILE* cfgReadyFlag = NULL ; - cfgReadyFlag = fopen(T2_CONFIG_READY, "w+"); - if(cfgReadyFlag) + if (!createSecureTempFlag(T2_CONFIG_READY)) { - fclose(cfgReadyFlag); + T2Error("Failed to create secure config ready flag %s\n", T2_CONFIG_READY); } setT2EventReceiveState(T2_STATE_CONFIG_READY); T2Info("T2 is now Ready to be configured for report profiles\n"); @@ -658,16 +664,13 @@ T2ERROR initReportProfiles() // This indicates telemetry has started - FILE* bootFlag = NULL ; - bootFlag = fopen(BOOTFLAG, "w+"); - if(bootFlag) + if (!createSecureTempFlag(BOOTFLAG)) { - T2Debug("%s Touched \n", BOOTFLAG); - fclose(bootFlag); + T2Error("Failed to create secure T2 bootflag %s \n", BOOTFLAG); } else { - T2Error("Failed to create T2 bootflag %s \n", BOOTFLAG); + T2Debug("%s Touched \n", BOOTFLAG); } T2Debug("%s --out\n", __FUNCTION__); diff --git a/source/bulkdata/t2eventreceiver.c b/source/bulkdata/t2eventreceiver.c index 426dfc2a..d130aed9 100644 --- a/source/bulkdata/t2eventreceiver.c +++ b/source/bulkdata/t2eventreceiver.c @@ -19,9 +19,14 @@ #include #include +#include +#include +#include +#include #include "t2eventreceiver.h" +#include "t2common.h" #include "t2collection.h" #include "t2markers.h" #include "telemetry2_0.h" @@ -404,7 +409,7 @@ T2ERROR T2ER_Init() registerForTelemetryEvents(T2ER_PushDataWithDelim); } - if (system("touch /tmp/.t2ReadyToReceiveEvents") != 0) + if (!createSecureTempFlag("/tmp/.t2ReadyToReceiveEvents")) { T2Error("Failed to create /tmp/.t2ReadyToReceiveEvents flag file\n"); } diff --git a/source/protocol/http/multicurlinterface.c b/source/protocol/http/multicurlinterface.c index 3e76905f..57874844 100644 --- a/source/protocol/http/multicurlinterface.c +++ b/source/protocol/http/multicurlinterface.c @@ -41,6 +41,7 @@ #include "t2log_wrapper.h" #include "reportprofiles.h" #include "t2MtlsUtils.h" +#include "t2common.h" #ifdef LIBRDKCERTSEL_BUILD #include "rdkcertselector.h" #define FILESCHEME "file://" @@ -843,7 +844,7 @@ T2ERROR http_pool_get(const char *url, char **response_data, bool enable_file_ou // Handle file output for GET requests if (enable_file_output) { - int fd = open(HTTP_RESPONSE_FILE, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + int fd = openSecureTempFile(HTTP_RESPONSE_FILE, true); if (fd >= 0) { FILE *httpOutput = fdopen(fd, "w"); @@ -998,7 +999,7 @@ T2ERROR http_pool_post(const char *url, const char *payload) // For now, we will set up file output for POST requests to ensure stability. // Set up file output for POST requests // If file opens successfully, override the default stdout with the file pointer - int curl_output_fd = open("/tmp/curlOutput.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + int curl_output_fd = openSecureTempFile("/tmp/curlOutput.txt", true); FILE *fp = NULL; if (curl_output_fd >= 0) { @@ -1036,7 +1037,7 @@ T2ERROR http_pool_post(const char *url, const char *payload) bool state_red_enable = false; #if defined(ENABLE_RED_RECOVERY_SUPPORT) - state_red_enable = (access("/tmp/stateRedEnabled", F_OK) == 0); + state_red_enable = isStateRedEnabled(); T2Info("%s: state_red_enable: %d\n", __func__, state_red_enable); #endif diff --git a/source/utils/t2common.c b/source/utils/t2common.c index 8296a48f..2bfe1a95 100644 --- a/source/utils/t2common.c +++ b/source/utils/t2common.c @@ -19,12 +19,110 @@ #include #include +#include +#include +#include #include "t2common.h" #include "t2log_wrapper.h" #include "dcautil.h" bool whoami_support = false; +bool isSafeTempFilePath(const char *path) +{ + struct stat st; + + if (path == NULL || *path == '\0') + { + return false; + } + + if (lstat(path, &st) == 0) + { + if (S_ISLNK(st.st_mode) || !S_ISREG(st.st_mode)) + { + T2Error("Refusing to use non-regular or symlinked temp file: %s\n", path); + return false; + } + + if (st.st_uid != geteuid()) + { + T2Error("Refusing to use temp file with unexpected owner: %s\n", path); + return false; + } + } + + return true; +} + +int openSecureTempFile(const char *path, bool truncateExisting) +{ + int fd = -1; + + if (!isSafeTempFilePath(path)) + { + return -1; + } + + if (access(path, F_OK) == 0) + { + fd = open(path, O_WRONLY | (truncateExisting ? O_TRUNC : O_EXCL), S_IRUSR | S_IWUSR); + } + else + { + fd = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + } + + if (fd < 0) + { + T2Error("Unable to safely open %s: %s\n", path, strerror(errno)); + return -1; + } + + if (fchmod(fd, S_IRUSR | S_IWUSR) != 0) + { + T2Error("Unable to set 0600 permissions on %s: %s\n", path, strerror(errno)); + close(fd); + return -1; + } + + return fd; +} + +bool createSecureTempFlag(const char *path) +{ + if (path == NULL || *path == '\0') + { + return false; + } + + if (!isSafeTempFilePath(path)) + { + T2Error("Refusing to use unsafe flag path %s\n", path); + return false; + } + + int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + if (fd < 0) + { + if (errno != EEXIST) + { + T2Error("Unable to create secure flag %s: %s\n", path, strerror(errno)); + } + return false; + } + + if (fchmod(fd, S_IRUSR | S_IWUSR) != 0) + { + T2Error("Unable to set 0600 permissions on %s: %s\n", path, strerror(errno)); + close(fd); + return false; + } + + close(fd); + return true; +} + void freeParam(void *data) { if(data != NULL) diff --git a/source/utils/t2common.h b/source/utils/t2common.h index d4496a40..8e2df7ce 100644 --- a/source/utils/t2common.h +++ b/source/utils/t2common.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "vector.h" #define MAX_ACCUMULATE 20 @@ -185,6 +186,10 @@ int compareLogFileNames(const void *g1, const void *g2); bool getDevicePropertyData(const char *dev_prop_name, char *out_data, unsigned int buff_size); +bool isSafeTempFilePath(const char *path); +int openSecureTempFile(const char *path, bool truncateExisting); +bool createSecureTempFlag(const char *path); + void initWhoamiSupport(void); bool isWhoAmiEnabled(void); From 7dcc6550ef5915d32046d78811c04be9efe7ae46 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Wed, 21 Oct 2026 12:51:50 +0000 Subject: [PATCH 04/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/ccspinterface/rbusInterface.c | 4 ++++ source/t2parser/t2parser.c | 10 ++++++++++ source/t2parser/t2parserxconf.c | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/source/ccspinterface/rbusInterface.c b/source/ccspinterface/rbusInterface.c index 2fd73fdd..b34a0b9f 100644 --- a/source/ccspinterface/rbusInterface.c +++ b/source/ccspinterface/rbusInterface.c @@ -1038,6 +1038,10 @@ static rbusError_t dcmOnDemandMethodHandler(rbusHandle_t handle, char const* met if(pthread_create(&rpOnDemandTh, &rpOnDemandAttr, reportOnDemandCallBack, ON_DEMAND_ACTION_UPLOAD) != 0) { T2Error("Failed to create thread for report on demand.\n"); + onDemandReportCallBackHandler = NULL; + pthread_mutex_unlock(&asyncMutex); + pthread_attr_destroy(&rpOnDemandAttr); + return RBUS_ERROR_FAILURE; } pthread_attr_destroy(&rpOnDemandAttr); diff --git a/source/t2parser/t2parser.c b/source/t2parser/t2parser.c index 0a42d264..0f2dc6e1 100644 --- a/source/t2parser/t2parser.c +++ b/source/t2parser/t2parser.c @@ -1859,10 +1859,18 @@ T2ERROR processConfiguration(char** configData, char *profileName, char* profile if((strcmp(jprofileProtocol->valuestring, "HTTP") == 0)) { profile->t2HTTPDest = (T2HTTP *) malloc(sizeof(T2HTTP)); + if(profile->t2HTTPDest) + { + memset(profile->t2HTTPDest, 0, sizeof(*profile->t2HTTPDest)); + } } else if ((strcmp(jprofileProtocol->valuestring, "RBUS_METHOD") == 0)) { profile->t2RBUSDest = malloc(sizeof(T2RBUS)); + if(profile->t2RBUSDest) + { + memset(profile->t2RBUSDest, 0, sizeof(*profile->t2RBUSDest)); + } } if ( (profile->t2HTTPDest == NULL) && (profile->t2RBUSDest == NULL) ) @@ -3406,6 +3414,7 @@ T2ERROR processMsgPackConfiguration(msgpack_object *profiles_array_map, Profile T2Error("Malloc error exiting: can not allocate memory to create profile->t2HTTPDest \n"); return T2ERROR_MEMALLOC_FAILED; } + memset(profile->t2HTTPDest, 0, sizeof(*profile->t2HTTPDest)); msgpack_object *HTTP_map = msgpack_get_map_value(value_map, "HTTP"); msgpack_object *URL_str = msgpack_get_map_value(HTTP_map, "URL"); msgpack_object *Compression_str = msgpack_get_map_value(HTTP_map, "Compression"); @@ -3444,6 +3453,7 @@ T2ERROR processMsgPackConfiguration(msgpack_object *profiles_array_map, Profile T2Error("Malloc error exiting: can not allocate memory to create profile->t2RBUSDest \n"); return T2ERROR_MEMALLOC_FAILED; } + memset(profile->t2RBUSDest, 0, sizeof(*profile->t2RBUSDest)); RbusMethod_map = msgpack_get_map_value(value_map, "RBUS_METHOD"); RbusMethod_str = msgpack_get_map_value(RbusMethod_map, "Method"); msgpack_print(RbusMethod_str, msgpack_get_obj_name(RbusMethod_str)); diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index fc9b4847..b101ddae 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -446,6 +446,13 @@ T2ERROR processConfigurationXConf(char* configData, ProfileXConf **localProfile) profile->protocol = strdup("HTTP"); profile->t2HTTPDest = (T2HTTP *)malloc(sizeof(T2HTTP)); + if(profile->t2HTTPDest == NULL) + { + T2Error("Malloc error exiting: can not allocate memory to create profile->t2HTTPDest \n"); + cJSON_Delete(json_root); + return T2ERROR_MEMALLOC_FAILED; + } + memset(profile->t2HTTPDest, 0, sizeof(*profile->t2HTTPDest)); profile->t2HTTPDest->URL = strdup(juploadUrl->valuestring); profile->encodingType = strdup("JSON"); From ec55b15b25dc513972bc31223d79b3955052dcdf Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Thu, 22 Oct 2026 09:03:06 +0000 Subject: [PATCH 05/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/t2parser/t2parserxconf.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index b101ddae..e9f16719 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -233,12 +233,13 @@ static int getScheduleInSeconds(const char* cronPattern) // Bounds check: ensure the schedule string doesn't exceed buffer if (timeInMinDataLen >= sizeof(scheduleString)) { T2Error("Schedule string too long: %d bytes, max %zu\n", timeInMinDataLen, sizeof(scheduleString) - 1); - free(input); - return -1; } - strncpy(scheduleString, inputMatchPattern, sizeof(scheduleString) - 1); - scheduleString[sizeof(scheduleString) - 1] = '\0'; - scheduleIntervalInMin = atoi(scheduleString); + else + { + strncpy(scheduleString, inputMatchPattern, sizeof(scheduleString) - 1); + scheduleString[sizeof(scheduleString) - 1] = '\0'; + scheduleIntervalInMin = atoi(scheduleString); + } } } From 07cbfc5cdf430282335bcd388c510778cac497f1 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Thu, 22 Oct 2026 10:41:07 +0000 Subject: [PATCH 06/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/t2parser/t2parserxconf.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index e9f16719..b6ecb29f 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -47,7 +47,7 @@ #define ACCUMULATE_MARKER_SUFFIX "_accum" #define MAX_PARAM_LEN 15 -static bool is_valid_https_upload_url(const char *url) +static bool isValidHttpsUploadUrl(const char *url) { if (url == NULL || *url == '\0') { @@ -85,22 +85,10 @@ static bool is_valid_https_upload_url(const char *url) return false; } - char *path_start = strchr(authority, '/'); - if (path_start != NULL) + char *host_end = strpbrk(authority, "/?#"); + if (host_end != NULL) { - *path_start = '\0'; - } - - char *query_start = strchr(authority, '?'); - if (query_start != NULL) - { - *query_start = '\0'; - } - - char *fragment_start = strchr(authority, '#'); - if (fragment_start != NULL) - { - *fragment_start = '\0'; + *host_end = '\0'; } char host[256]; @@ -231,7 +219,7 @@ static int getScheduleInSeconds(const char* cronPattern) int timeInMinDataLen = inputMatchSize - discardPatternLen; char scheduleString[10] = { '\0' }; // Bounds check: ensure the schedule string doesn't exceed buffer - if (timeInMinDataLen >= sizeof(scheduleString)) { + if (timeInMinDataLen >= (int)sizeof(scheduleString)) { T2Error("Schedule string too long: %d bytes, max %zu\n", timeInMinDataLen, sizeof(scheduleString) - 1); } else @@ -425,7 +413,7 @@ T2ERROR processConfigurationXConf(char* configData, ProfileXConf **localProfile) return T2ERROR_FAILURE; } - if (!is_valid_https_upload_url(juploadUrl->valuestring)) + if (!isValidHttpsUploadUrl(juploadUrl->valuestring)) { T2Error("Rejected invalid upload URL in XCONF profile: %s\n", juploadUrl->valuestring ? juploadUrl->valuestring : "(null)"); cJSON_Delete(json_root); From 35faae44da3297b69da8a6443550ac49a22728c6 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Thu, 22 Oct 2026 11:57:30 +0000 Subject: [PATCH 07/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/ccspinterface/rbusInterface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ccspinterface/rbusInterface.c b/source/ccspinterface/rbusInterface.c index b34a0b9f..4895434f 100644 --- a/source/ccspinterface/rbusInterface.c +++ b/source/ccspinterface/rbusInterface.c @@ -1041,7 +1041,7 @@ static rbusError_t dcmOnDemandMethodHandler(rbusHandle_t handle, char const* met onDemandReportCallBackHandler = NULL; pthread_mutex_unlock(&asyncMutex); pthread_attr_destroy(&rpOnDemandAttr); - return RBUS_ERROR_FAILURE; + return RBUS_ERROR_BUS_ERROR; } pthread_attr_destroy(&rpOnDemandAttr); From 8a8f4f842bf66573bff0912465181447e519384e Mon Sep 17 00:00:00 2001 From: Monavpriya097 Date: Thu, 22 Oct 2026 11:57:26 +0000 Subject: [PATCH 08/27] Validation check for profile->name --- source/bulkdata/reportprofiles.c | 45 ++++++++++++++++++++++++++++++++ source/t2parser/t2parser.c | 33 +++++++++++++++++++++++ source/t2parser/t2parserxconf.c | 5 ++++ 3 files changed, 83 insertions(+) diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index cf07f3e7..d1e38d86 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -935,6 +935,12 @@ void ReportProfiles_ProcessReportProfilesBlob(cJSON *profiles_root, bool rprofil } cJSON* nameObj = cJSON_GetObjectItem(singleProfile, "name"); + if (!cJSON_IsString(nameObj) || !nameObj->valuestring || !nameObj->valuestring[0] || + strspn(nameObj->valuestring, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != strlen(nameObj->valuestring)) + { + T2Error("Invalid profile name in JSON configuration\n"); + continue; + } cJSON* hashObj = cJSON_GetObjectItem(singleProfile, "hash"); if(hashObj == NULL) { @@ -949,7 +955,18 @@ void ReportProfiles_ProcessReportProfilesBlob(cJSON *profiles_root, bool rprofil } ReportProfile *profileEntry = (ReportProfile *)malloc(sizeof(ReportProfile)); + if (profileEntry == NULL) + { + T2Error("Failed to allocate report profile entry\n"); + continue; + } profileName = strdup(nameObj->valuestring); + if (profileName == NULL) + { + T2Error("Failed to copy profile name from JSON configuration\n"); + free(profileEntry); + continue; + } profileEntry->hash = strdup(hashObj->valuestring); profileEntry->config = cJSON_PrintUnformatted(profileObj); hash_map_put(receivedProfileHashMap, profileName, profileEntry, freeReportProfileHashMap); @@ -1403,6 +1420,29 @@ int __ReportProfiles_ProcessReportProfilesMsgPackBlob(void *msgpack, bool checkP continue; } msgpack_object* nameObj = msgpack_get_map_value(singleProfile, "name"); + size_t nameIndex; + if (nameObj == NULL || nameObj->type != MSGPACK_OBJECT_STR || + nameObj->via.str.ptr == NULL || nameObj->via.str.size == 0) + { + T2Error("Invalid profile name in MsgPack configuration\n"); + continue; + } + for (nameIndex = 0; nameIndex < nameObj->via.str.size; nameIndex++) + { + unsigned char character = (unsigned char)nameObj->via.str.ptr[nameIndex]; + if (!((character >= 'a' && character <= 'z') || + (character >= 'A' && character <= 'Z') || + (character >= '0' && character <= '9') || + character == '_' || character == '-')) + { + T2Error("Invalid profile name in MsgPack configuration\n"); + break; + } + } + if (nameIndex != nameObj->via.str.size) + { + continue; + } msgpack_object* hashObj = msgpack_get_map_value(singleProfile, "hash"); if (hashObj == NULL) { @@ -1420,6 +1460,11 @@ int __ReportProfiles_ProcessReportProfilesMsgPackBlob(void *msgpack, bool checkP char *existingProfileHash = NULL; Profile *profile = NULL; profileName = msgpack_strdup(nameObj); + if (profileName == NULL) + { + T2Error("Failed to copy profile name from MsgPack configuration\n"); + continue; + } existingProfileHash = hash_map_remove(profileHashMap, profileName); if(NULL == existingProfileHash) { diff --git a/source/t2parser/t2parser.c b/source/t2parser/t2parser.c index 0f2dc6e1..933cce11 100644 --- a/source/t2parser/t2parser.c +++ b/source/t2parser/t2parser.c @@ -1659,6 +1659,12 @@ T2ERROR processConfiguration(char** configData, char *profileName, char* profile cJSON_Delete(json_root); return T2ERROR_FAILURE; } + if (!profileName || !profileName[0] || + strspn(profileName, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != strlen(profileName)) { + T2Error("ERROR: Profile name vulnerability, security threat on profile name \n"); + cJSON_Delete(json_root); + return T2ERROR_FAILURE; + } if(jprofileReportingInterval && jprofilemaxUploadLatency && ((jprofileReportingInterval->valueint * 1000) < jprofilemaxUploadLatency->valueint)) { T2Error("MaxUploadLatency is greater than reporting interval. Invalid Profile\n"); @@ -3158,6 +3164,7 @@ T2ERROR processMsgPackConfiguration(msgpack_object *profiles_array_map, Profile msgpack_object *FirstReportInterval_u64 = NULL; msgpack_object *MaxUploadLatency_u64 = NULL; msgpack_object *RbusMethod_map; + size_t nameIndex; int ret = 0; T2Debug("%s --in\n", __FUNCTION__); @@ -3171,8 +3178,34 @@ T2ERROR processMsgPackConfiguration(msgpack_object *profiles_array_map, Profile name_str = msgpack_get_map_value(profiles_array_map, "name"); + if (name_str == NULL || name_str->type != MSGPACK_OBJECT_STR || + name_str->via.str.ptr == NULL || name_str->via.str.size == 0) + { + T2Error("Invalid profile name in MsgPack configuration\n"); + free(profile); + return T2ERROR_FAILURE; + } + for (nameIndex = 0; nameIndex < name_str->via.str.size; nameIndex++) + { + unsigned char character = (unsigned char)name_str->via.str.ptr[nameIndex]; + if (!((character >= 'a' && character <= 'z') || + (character >= 'A' && character <= 'Z') || + (character >= '0' && character <= '9') || + character == '_' || character == '-')) + { + T2Error("Invalid profile name in MsgPack configuration\n"); + free(profile); + return T2ERROR_FAILURE; + } + } msgpack_print(name_str, msgpack_get_obj_name(name_str)); profile->name = msgpack_strdup(name_str); + if (profile->name == NULL) + { + T2Error("Failed to copy profile name from MsgPack configuration\n"); + free(profile); + return T2ERROR_MEMALLOC_FAILED; + } hash_str = msgpack_get_map_value(profiles_array_map, "hash"); if(NULL == hash_str) diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index b6ecb29f..8fe81db2 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -392,6 +392,11 @@ T2ERROR processConfigurationXConf(char* configData, ProfileXConf **localProfile) } // if(jprofileID) // T2Debug("profile id = %s\n", jprofileID->valuestring); + if (!cJSON_IsString(jprofileName) || !jprofileName->valuestring || !jprofileName->valuestring[0] || strspn(jprofileName->valuestring, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != strlen(jprofileName->valuestring)) { + T2Error("ERROR: Profile name vulnerability, security threat on profile name \n"); + cJSON_Delete(json_root); + return T2ERROR_FAILURE; + } if(jprofileName) { T2Debug("profile name = %s\n", jprofileName->valuestring); From 1ccacda723d2ff42705bee30b54a858ed5f9621f Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Thu, 22 Oct 2026 12:09:06 +0000 Subject: [PATCH 09/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/bulkdata/reportprofiles.c | 10 +++++----- source/reportgen/reportgen.c | 9 ++++++--- source/t2parser/t2parser.c | 11 ++++++----- source/t2parser/t2parserxconf.c | 30 ++++++++++++++++-------------- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index d1e38d86..3a0a12f0 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -936,7 +936,7 @@ void ReportProfiles_ProcessReportProfilesBlob(cJSON *profiles_root, bool rprofil cJSON* nameObj = cJSON_GetObjectItem(singleProfile, "name"); if (!cJSON_IsString(nameObj) || !nameObj->valuestring || !nameObj->valuestring[0] || - strspn(nameObj->valuestring, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != strlen(nameObj->valuestring)) + strspn(nameObj->valuestring, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != strlen(nameObj->valuestring)) { T2Error("Invalid profile name in JSON configuration\n"); continue; @@ -1422,7 +1422,7 @@ int __ReportProfiles_ProcessReportProfilesMsgPackBlob(void *msgpack, bool checkP msgpack_object* nameObj = msgpack_get_map_value(singleProfile, "name"); size_t nameIndex; if (nameObj == NULL || nameObj->type != MSGPACK_OBJECT_STR || - nameObj->via.str.ptr == NULL || nameObj->via.str.size == 0) + nameObj->via.str.ptr == NULL || nameObj->via.str.size == 0) { T2Error("Invalid profile name in MsgPack configuration\n"); continue; @@ -1431,9 +1431,9 @@ int __ReportProfiles_ProcessReportProfilesMsgPackBlob(void *msgpack, bool checkP { unsigned char character = (unsigned char)nameObj->via.str.ptr[nameIndex]; if (!((character >= 'a' && character <= 'z') || - (character >= 'A' && character <= 'Z') || - (character >= '0' && character <= '9') || - character == '_' || character == '-')) + (character >= 'A' && character <= 'Z') || + (character >= '0' && character <= '9') || + character == '_' || character == '-')) { T2Error("Invalid profile name in MsgPack configuration\n"); break; diff --git a/source/reportgen/reportgen.c b/source/reportgen/reportgen.c index 55310a0a..de8354a7 100644 --- a/source/reportgen/reportgen.c +++ b/source/reportgen/reportgen.c @@ -251,7 +251,8 @@ static T2ERROR applyRegexToValue(char** inputValue, const char* regexPattern) pmatch[0].rm_eo - pmatch[0].rm_so, &(*inputValue)[pmatch[0].rm_so]); // Bounds check: ensure match length doesn't exceed buffer int matchLen = pmatch[0].rm_eo - pmatch[0].rm_so; - if (matchLen >= (int)sizeof(string)) { + if (matchLen >= (int)sizeof(string)) + { T2Warning("Regex match too long: %d bytes, truncating to %zu\n", matchLen, sizeof(string) - 1); matchLen = sizeof(string) - 1; } @@ -1039,7 +1040,8 @@ T2ERROR encodeGrepResultInJSON(cJSON *valArray, Vector *grepMarkerList) T2Debug("regexec successful, Match is found %.*s\n", pmatch[0].rm_eo - pmatch[0].rm_so, &stringValue[pmatch[0].rm_so]); // Bounds check: ensure match length doesn't exceed buffer int matchLen = pmatch[0].rm_eo - pmatch[0].rm_so; - if (matchLen >= (int)sizeof(string[0])) { + if (matchLen >= (int)sizeof(string[0])) + { T2Warning("Regex match too long: %d bytes, truncating to %zu\n", matchLen, sizeof(string[0]) - 1); matchLen = sizeof(string[0]) - 1; } @@ -1416,7 +1418,8 @@ T2ERROR encodeEventMarkersInJSON(cJSON *valArray, Vector *eventMarkerList) T2Debug("regexec successful, Match is found %.*s\n", pmatch[0].rm_eo - pmatch[0].rm_so, &stringValue[pmatch[0].rm_so]); // Bounds check: ensure match length doesn't exceed buffer int matchLen = pmatch[0].rm_eo - pmatch[0].rm_so; - if (matchLen >= (int)sizeof(string)) { + if (matchLen >= (int)sizeof(string)) + { T2Warning("Regex match too long: %d bytes, truncating to %zu\n", matchLen, sizeof(string) - 1); matchLen = sizeof(string) - 1; } diff --git a/source/t2parser/t2parser.c b/source/t2parser/t2parser.c index 933cce11..e909049e 100644 --- a/source/t2parser/t2parser.c +++ b/source/t2parser/t2parser.c @@ -1660,7 +1660,8 @@ T2ERROR processConfiguration(char** configData, char *profileName, char* profile return T2ERROR_FAILURE; } if (!profileName || !profileName[0] || - strspn(profileName, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != strlen(profileName)) { + strspn(profileName, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != strlen(profileName)) + { T2Error("ERROR: Profile name vulnerability, security threat on profile name \n"); cJSON_Delete(json_root); return T2ERROR_FAILURE; @@ -3179,7 +3180,7 @@ T2ERROR processMsgPackConfiguration(msgpack_object *profiles_array_map, Profile name_str = msgpack_get_map_value(profiles_array_map, "name"); if (name_str == NULL || name_str->type != MSGPACK_OBJECT_STR || - name_str->via.str.ptr == NULL || name_str->via.str.size == 0) + name_str->via.str.ptr == NULL || name_str->via.str.size == 0) { T2Error("Invalid profile name in MsgPack configuration\n"); free(profile); @@ -3189,9 +3190,9 @@ T2ERROR processMsgPackConfiguration(msgpack_object *profiles_array_map, Profile { unsigned char character = (unsigned char)name_str->via.str.ptr[nameIndex]; if (!((character >= 'a' && character <= 'z') || - (character >= 'A' && character <= 'Z') || - (character >= '0' && character <= '9') || - character == '_' || character == '-')) + (character >= 'A' && character <= 'Z') || + (character >= '0' && character <= '9') || + character == '_' || character == '-')) { T2Error("Invalid profile name in MsgPack configuration\n"); free(profile); diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index 8fe81db2..54f2137f 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -169,10 +169,10 @@ static bool isValidHttpsUploadUrl(const char *url) lower_host[host_len] = '\0'; if (strcmp(lower_host, "localhost") == 0 || - strcmp(lower_host, "localhost.localdomain") == 0 || - (host_len >= 10 && strncmp(lower_host, "localhost.", 10) == 0) || - (host_len >= 6 && strcmp(lower_host + host_len - 6, ".local") == 0) || - (host_len >= 9 && strcmp(lower_host + host_len - 9, ".internal") == 0)) + strcmp(lower_host, "localhost.localdomain") == 0 || + (host_len >= 10 && strncmp(lower_host, "localhost.", 10) == 0) || + (host_len >= 6 && strcmp(lower_host + host_len - 6, ".local") == 0) || + (host_len >= 9 && strcmp(lower_host + host_len - 9, ".internal") == 0)) { return false; } @@ -182,14 +182,14 @@ static bool isValidHttpsUploadUrl(const char *url) { uint32_t ip = ntohl(addr.s_addr); if ((ip & 0xFF000000u) == 0x7F000000u || - (ip & 0xFF000000u) == 0x00000000u || - (ip & 0xFF000000u) == 0x0A000000u || - (ip & 0xFFF00000u) == 0xAC100000u || - (ip & 0xFFFF0000u) == 0xC0A80000u || - (ip & 0xFFFF0000u) == 0xA9FE0000u || - (ip & 0xFFC00000u) == 0x64400000u || - (ip & 0xFF000000u) == 0xE0000000u || - (ip & 0xFF000000u) == 0xF0000000u) + (ip & 0xFF000000u) == 0x00000000u || + (ip & 0xFF000000u) == 0x0A000000u || + (ip & 0xFFF00000u) == 0xAC100000u || + (ip & 0xFFFF0000u) == 0xC0A80000u || + (ip & 0xFFFF0000u) == 0xA9FE0000u || + (ip & 0xFFC00000u) == 0x64400000u || + (ip & 0xFF000000u) == 0xE0000000u || + (ip & 0xFF000000u) == 0xF0000000u) { return false; } @@ -219,7 +219,8 @@ static int getScheduleInSeconds(const char* cronPattern) int timeInMinDataLen = inputMatchSize - discardPatternLen; char scheduleString[10] = { '\0' }; // Bounds check: ensure the schedule string doesn't exceed buffer - if (timeInMinDataLen >= (int)sizeof(scheduleString)) { + if (timeInMinDataLen >= (int)sizeof(scheduleString)) + { T2Error("Schedule string too long: %d bytes, max %zu\n", timeInMinDataLen, sizeof(scheduleString) - 1); } else @@ -392,7 +393,8 @@ T2ERROR processConfigurationXConf(char* configData, ProfileXConf **localProfile) } // if(jprofileID) // T2Debug("profile id = %s\n", jprofileID->valuestring); - if (!cJSON_IsString(jprofileName) || !jprofileName->valuestring || !jprofileName->valuestring[0] || strspn(jprofileName->valuestring, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != strlen(jprofileName->valuestring)) { + if (!cJSON_IsString(jprofileName) || !jprofileName->valuestring || !jprofileName->valuestring[0] || strspn(jprofileName->valuestring, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != strlen(jprofileName->valuestring)) + { T2Error("ERROR: Profile name vulnerability, security threat on profile name \n"); cJSON_Delete(json_root); return T2ERROR_FAILURE; From ffb6f47c39793aebfb0fb31ae2446f2efde64cfb Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Thu, 22 Oct 2026 16:24:03 +0000 Subject: [PATCH 10/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/bulkdata/t2eventreceiver.c | 117 ++++++++++++++++++--------- source/ccspinterface/rbusInterface.c | 13 +-- 2 files changed, 80 insertions(+), 50 deletions(-) diff --git a/source/bulkdata/t2eventreceiver.c b/source/bulkdata/t2eventreceiver.c index d130aed9..22aaf389 100644 --- a/source/bulkdata/t2eventreceiver.c +++ b/source/bulkdata/t2eventreceiver.c @@ -37,6 +37,8 @@ #define T2EVENTQUEUE_MAX_LIMIT 200 #define MESSAGE_DELIMITER "<#=#>" +#define MAX_EVENT_NAME_LEN 256 +#define MAX_EVENT_VALUE_LEN 4096 static queue_t *eQueue = NULL; static bool EREnabled = false; @@ -85,6 +87,24 @@ static char *strSplit(char *str, char *delim) return ret; } +static bool isValidEventLength(const char *name, const char *value) +{ + if(name == NULL || value == NULL) + { + return false; + } + + size_t nameLen = strlen(name); + size_t valueLen = strlen(value); + if(nameLen == 0 || valueLen == 0 || nameLen > MAX_EVENT_NAME_LEN || valueLen > MAX_EVENT_VALUE_LEN) + { + T2Warning("Dropping oversized telemetry event: nameLen=%zu valueLen=%zu\n", nameLen, valueLen); + return false; + } + + return true; +} + void freeT2Event(void *data) { if(data != NULL) @@ -119,51 +139,59 @@ void T2ER_PushDataWithDelim(char* eventInfo, char* user_data) char* token = strSplit(eventInfo, MESSAGE_DELIMITER); if(token != NULL) { - T2Event *event = (T2Event *) malloc(sizeof(T2Event)); - if(event) + char* valueToken = strSplit(NULL, MESSAGE_DELIMITER); + if(valueToken != NULL) { - event->name = strdup(token); - token = strSplit(NULL, MESSAGE_DELIMITER); - if(token != NULL) + if(!isValidEventLength(token, valueToken)) { - event->value = strdup(token); - if(t2_queue_count(eQueue) > T2EVENTQUEUE_MAX_LIMIT) - { - T2Warning("T2EventQueue max limit : %d reached, dropping packet for eventName : %s eventValue : %s\n", - T2EVENTQUEUE_MAX_LIMIT, event->name, event->value); - free(event->value); - free(event->name); - free(event); - } - else + T2Warning("Dropping event with invalid length for eventName : %s eventValue : %s\n", token, valueToken); + } + else if(t2_queue_count(eQueue) > T2EVENTQUEUE_MAX_LIMIT) + { + T2Warning("T2EventQueue max limit : %d reached, dropping packet for eventName : %s eventValue : %s\n", + T2EVENTQUEUE_MAX_LIMIT, token, valueToken); + } + else + { + T2Event *event = (T2Event *) malloc(sizeof(T2Event)); + if(event != NULL) { - T2Debug("Adding eventName : %s eventValue : %s to t2event queue\n", event->name, event->value); - t2_queue_push(eQueue, (void *) event); - // Check stopDispatchThread with proper lock to avoid stale reads from compiler - // optimizations or CPU caching. We hold sTDMutex while reading stopDispatchThread - // to ensure proper synchronization with the thread that sets this flag. - if(pthread_mutex_lock(&sTDMutex) == 0) + event->name = strdup(token); + event->value = strdup(valueToken); + if(event->name != NULL && event->value != NULL) { - bool shouldSignal = !stopDispatchThread; - pthread_mutex_unlock(&sTDMutex); - if(shouldSignal) + T2Debug("Adding eventName : %s eventValue : %s to t2event queue\n", event->name, event->value); + t2_queue_push(eQueue, (void *) event); + // Check stopDispatchThread with proper lock to avoid stale reads from compiler + // optimizations or CPU caching. We hold sTDMutex while reading stopDispatchThread + // to ensure proper synchronization with the thread that sets this flag. + if(pthread_mutex_lock(&sTDMutex) == 0) { - ret = pthread_cond_signal(&erCond); - if(ret != 0) // pthread cond signal failed so return after unlocking the mutex + bool shouldSignal = !stopDispatchThread; + pthread_mutex_unlock(&sTDMutex); + if(shouldSignal) { - T2Error("%s pthread_cond_signal for erCond failed with error code : %d\n", __FUNCTION__, ret); + ret = pthread_cond_signal(&erCond); + if(ret != 0) // pthread cond signal failed so return after unlocking the mutex + { + T2Error("%s pthread_cond_signal for erCond failed with error code : %d\n", __FUNCTION__, ret); + } } } - + } + else + { + free(event->name); + free(event->value); + free(event); + T2Error("Failed to duplicate event memory\n"); } } } - else - { - free(event->name); - free(event); - T2Error("Missing event value\n"); - } + } + else + { + T2Error("Missing event value\n"); } } else @@ -202,7 +230,11 @@ void T2ER_Push(char* eventName, char* eventValue) T2Error("%s pthread_mutex_lock for erMutex failed\n", __FUNCTION__); return; } - if(t2_queue_count(eQueue) > T2EVENTQUEUE_MAX_LIMIT) + if(!isValidEventLength(eventName, eventValue)) + { + T2Warning("Dropping event with invalid length for eventName : %s eventValue : %s\n", eventName, eventValue); + } + else if(t2_queue_count(eQueue) > T2EVENTQUEUE_MAX_LIMIT) { T2Warning("T2EventQueue max limit : %d reached, dropping packet for eventName : %s eventValue : %s\n", T2EVENTQUEUE_MAX_LIMIT, eventName, eventValue); @@ -215,9 +247,18 @@ void T2ER_Push(char* eventName, char* eventValue) { event->name = strdup(eventName); event->value = strdup(eventValue); - T2Debug("Adding eventName : %s eventValue : %s to t2event queue\n", event->name, event->value); - t2_queue_push(eQueue, (void *) event); - + if(event->name != NULL && event->value != NULL) + { + T2Debug("Adding eventName : %s eventValue : %s to t2event queue\n", event->name, event->value); + t2_queue_push(eQueue, (void *) event); + } + else + { + free(event->name); + free(event->value); + free(event); + T2Error("Failed to duplicate event memory\n"); + } } } diff --git a/source/ccspinterface/rbusInterface.c b/source/ccspinterface/rbusInterface.c index 4895434f..15530bf7 100644 --- a/source/ccspinterface/rbusInterface.c +++ b/source/ccspinterface/rbusInterface.c @@ -1083,20 +1083,9 @@ static rbusError_t dcmOnDemandMethodHandler(rbusHandle_t handle, char const* met } else if(!strncmp(methodName, T2_ABORT_ON_DEMAND_REPORT, maxParamLen)) { - T2Info("%s Aborting previous ondemand report upload %s \n", __FUNCTION__, methodName); + T2Info("%s Abort is no longer supported; request is accepted without creating a detached worker thread to avoid thread-flood DoS\n", __FUNCTION__); - pthread_t rpOnDemandTh; - pthread_attr_t rpOnDemandAttr; - pthread_attr_init(&rpOnDemandAttr); - pthread_attr_setdetachstate(&rpOnDemandAttr, PTHREAD_CREATE_DETACHED); - // Calls within reportOnDemandCallBack are thread safe, thread synchronization is not required - if(pthread_create(&rpOnDemandTh, &rpOnDemandAttr, reportOnDemandCallBack, ON_DEMAND_ACTION_ABORT) != 0) - { - T2Error("Failed to create thread for report on demand.\n"); - } - - pthread_attr_destroy(&rpOnDemandAttr); if(NULL != asyncCallBackHandle) { rbusObject_t outputParams; From 3d0cd769012e82bbb8b83fc02d1abcf3724efd75 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Thu, 22 Oct 2026 17:16:32 +0000 Subject: [PATCH 11/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/t2parser/t2parserxconf.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index 54f2137f..64f04207 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -177,24 +177,6 @@ static bool isValidHttpsUploadUrl(const char *url) return false; } - struct in_addr addr; - if (inet_pton(AF_INET, host, &addr) == 1) - { - uint32_t ip = ntohl(addr.s_addr); - if ((ip & 0xFF000000u) == 0x7F000000u || - (ip & 0xFF000000u) == 0x00000000u || - (ip & 0xFF000000u) == 0x0A000000u || - (ip & 0xFFF00000u) == 0xAC100000u || - (ip & 0xFFFF0000u) == 0xC0A80000u || - (ip & 0xFFFF0000u) == 0xA9FE0000u || - (ip & 0xFFC00000u) == 0x64400000u || - (ip & 0xFF000000u) == 0xE0000000u || - (ip & 0xFF000000u) == 0xF0000000u) - { - return false; - } - } - return true; } From 961ef09b4256fce91ddab4bc614b0e2abd0cb55e Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Fri, 23 Oct 2026 09:42:11 +0530 Subject: [PATCH 12/27] Potential fix for pull request finding 'Allow empty values for marker-specific handling' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- source/bulkdata/t2eventreceiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/bulkdata/t2eventreceiver.c b/source/bulkdata/t2eventreceiver.c index 22aaf389..3c51610e 100644 --- a/source/bulkdata/t2eventreceiver.c +++ b/source/bulkdata/t2eventreceiver.c @@ -96,7 +96,7 @@ static bool isValidEventLength(const char *name, const char *value) size_t nameLen = strlen(name); size_t valueLen = strlen(value); - if(nameLen == 0 || valueLen == 0 || nameLen > MAX_EVENT_NAME_LEN || valueLen > MAX_EVENT_VALUE_LEN) + if(nameLen == 0 || nameLen > MAX_EVENT_NAME_LEN || valueLen > MAX_EVENT_VALUE_LEN) { T2Warning("Dropping oversized telemetry event: nameLen=%zu valueLen=%zu\n", nameLen, valueLen); return false; From ecd15c43e479bbe89044bae685ac8540a35daf59 Mon Sep 17 00:00:00 2001 From: Monavpriya097 Date: Fri, 23 Oct 2026 11:22:13 +0530 Subject: [PATCH 13/27] Fix include formatting for errno.h --- source/bulkdata/reportprofiles.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index 3a0a12f0..3991ea1e 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "reportprofiles.h" #include "xconfclient.h" From 781d4306ce67795e6f56efe71cbeb1a2bd7a4553 Mon Sep 17 00:00:00 2001 From: Monavpriya097 Date: Fri, 23 Oct 2026 08:58:39 +0000 Subject: [PATCH 14/27] format correct via astyle --- source/bulkdata/reportprofiles.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index 3991ea1e..3a0a12f0 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "reportprofiles.h" #include "xconfclient.h" From 50f92b5e65e36b4600804440a6f1ed57ef43e581 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Fri, 23 Oct 2026 09:12:41 +0000 Subject: [PATCH 15/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/t2parser/t2parserxconf.c | 39 +++++++++++++++ source/test/t2parser/t2parserxconfTest.cpp | 58 ++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index 64f04207..15824a0e 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -47,6 +47,40 @@ #define ACCUMULATE_MARKER_SUFFIX "_accum" #define MAX_PARAM_LEN 15 +static bool isLocalNumericAddress(const char *host) +{ + if (host == NULL || *host == '\0') + { + return false; + } + + struct in_addr addr4; + if (inet_pton(AF_INET, host, &addr4) == 1) + { + uint32_t ip = ntohl(addr4.s_addr); + return (ip == 0x7F000001u) || (ip == 0x00000000u); + } + + struct in6_addr addr6; + if (inet_pton(AF_INET6, host, &addr6) == 1) + { + if (IN6_IS_ADDR_LOOPBACK(&addr6) || IN6_IS_ADDR_UNSPECIFIED(&addr6)) + { + return true; + } + + if (IN6_IS_ADDR_V4MAPPED(&addr6)) + { + struct in_addr mapped_v4; + memcpy(&mapped_v4, &addr6.s6_addr[12], sizeof(mapped_v4)); + uint32_t mapped_ip = ntohl(mapped_v4.s_addr); + return (mapped_ip == 0x7F000001u) || (mapped_ip == 0x00000000u); + } + } + + return false; +} + static bool isValidHttpsUploadUrl(const char *url) { if (url == NULL || *url == '\0') @@ -156,6 +190,11 @@ static bool isValidHttpsUploadUrl(const char *url) return false; } + if (isLocalNumericAddress(host)) + { + return false; + } + char lower_host[256]; size_t host_len = strlen(host); if (host_len >= sizeof(lower_host)) diff --git a/source/test/t2parser/t2parserxconfTest.cpp b/source/test/t2parser/t2parserxconfTest.cpp index d29f5abf..3be6e351 100644 --- a/source/test/t2parser/t2parserxconfTest.cpp +++ b/source/test/t2parser/t2parserxconfTest.cpp @@ -110,3 +110,61 @@ TEST(T2ParserXConf, RejectsInvalidUploadUrl) EXPECT_EQ((ProfileXConf*)NULL, profile); } +TEST(T2ParserXConf, RejectsNumericLoopbackUploadUrls) +{ + ProfileXConf *profile = NULL; + + const char *json_v4_loopback = + "{" + " \"urn:settings:TelemetryProfile\": {" + " \"telemetryProfile:name\": \"LoopbackV4\"," + " \"uploadRepository:URL\": \"https://127.0.0.1/upload\"," + " \"schedule\": \"0/5 * * * *\"," + " \"telemetryProfile\": [ {" + " \"header\": \"param1\"," + " \"content\": \"alias1\"," + " \"type\": \"/var/log/some.log\"," + " \"pollingFrequency\": \"0\"" + " } ]" + " }" + "}"; + EXPECT_EQ(T2ERROR_FAILURE, processConfigurationXConf((char*)json_v4_loopback, &profile)); + EXPECT_EQ((ProfileXConf*)NULL, profile); + + profile = NULL; + const char *json_v6_loopback = + "{" + " \"urn:settings:TelemetryProfile\": {" + " \"telemetryProfile:name\": \"LoopbackV6\"," + " \"uploadRepository:URL\": \"https://[::1]/upload\"," + " \"schedule\": \"0/5 * * * *\"," + " \"telemetryProfile\": [ {" + " \"header\": \"param1\"," + " \"content\": \"alias1\"," + " \"type\": \"/var/log/some.log\"," + " \"pollingFrequency\": \"0\"" + " } ]" + " }" + "}"; + EXPECT_EQ(T2ERROR_FAILURE, processConfigurationXConf((char*)json_v6_loopback, &profile)); + EXPECT_EQ((ProfileXConf*)NULL, profile); + + profile = NULL; + const char *json_v4_mapped_loopback = + "{" + " \"urn:settings:TelemetryProfile\": {" + " \"telemetryProfile:name\": \"LoopbackMapped\"," + " \"uploadRepository:URL\": \"https://[::ffff:127.0.0.1]/upload\"," + " \"schedule\": \"0/5 * * * *\"," + " \"telemetryProfile\": [ {" + " \"header\": \"param1\"," + " \"content\": \"alias1\"," + " \"type\": \"/var/log/some.log\"," + " \"pollingFrequency\": \"0\"" + " } ]" + " }" + "}"; + EXPECT_EQ(T2ERROR_FAILURE, processConfigurationXConf((char*)json_v4_mapped_loopback, &profile)); + EXPECT_EQ((ProfileXConf*)NULL, profile); +} + From 1f210ee08a7f6148f8862f35bd896d8dfccc3160 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Fri, 23 Oct 2026 14:44:07 +0530 Subject: [PATCH 16/27] Potential fix for pull request finding 'Path checks race with destructive open, enabling symlink target modification' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- source/utils/t2common.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/source/utils/t2common.c b/source/utils/t2common.c index 2bfe1a95..e3c4b31c 100644 --- a/source/utils/t2common.c +++ b/source/utils/t2common.c @@ -64,18 +64,19 @@ int openSecureTempFile(const char *path, bool truncateExisting) return -1; } - if (access(path, F_OK) == 0) - { - fd = open(path, O_WRONLY | (truncateExisting ? O_TRUNC : O_EXCL), S_IRUSR | S_IWUSR); - } - else + fd = open(path, O_WRONLY | O_CREAT | O_NOFOLLOW | O_NONBLOCK, + S_IRUSR | S_IWUSR); + if (fd < 0) { - fd = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + T2Error("Unable to safely open %s: %s\n", path, strerror(errno)); + return -1; } - if (fd < 0) + struct stat st; + if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode) || st.st_uid != geteuid()) { - T2Error("Unable to safely open %s: %s\n", path, strerror(errno)); + T2Error("Refusing to use unsafe temp file: %s\n", path); + close(fd); return -1; } @@ -86,6 +87,13 @@ int openSecureTempFile(const char *path, bool truncateExisting) return -1; } + if (truncateExisting && ftruncate(fd, 0) != 0) + { + T2Error("Unable to truncate %s: %s\n", path, strerror(errno)); + close(fd); + return -1; + } + return fd; } From f4f2019e4ed1f7a371ab00c40d19d03ac5a01a69 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Fri, 23 Oct 2026 14:54:00 +0530 Subject: [PATCH 17/27] Potential fix for pull request finding 'Reject the entire IPv4 loopback range' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- source/t2parser/t2parserxconf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index 15824a0e..417a9ffb 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -58,7 +58,7 @@ static bool isLocalNumericAddress(const char *host) if (inet_pton(AF_INET, host, &addr4) == 1) { uint32_t ip = ntohl(addr4.s_addr); - return (ip == 0x7F000001u) || (ip == 0x00000000u); + return ((ip & 0xFF000000u) == 0x7F000000u) || (ip == 0x00000000u); } struct in6_addr addr6; @@ -74,7 +74,7 @@ static bool isLocalNumericAddress(const char *host) struct in_addr mapped_v4; memcpy(&mapped_v4, &addr6.s6_addr[12], sizeof(mapped_v4)); uint32_t mapped_ip = ntohl(mapped_v4.s_addr); - return (mapped_ip == 0x7F000001u) || (mapped_ip == 0x00000000u); + return ((mapped_ip & 0xFF000000u) == 0x7F000000u) || (mapped_ip == 0x00000000u); } } From 5eb121f00eab31898ff1bd3be13b8544e3391a23 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Fri, 23 Oct 2026 09:27:26 +0000 Subject: [PATCH 18/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/t2parser/t2parserxconf.c | 21 +++++++++ source/test/t2parser/t2parserxconfTest.cpp | 54 ++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index 417a9ffb..8f45767f 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,26 @@ static bool isLocalNumericAddress(const char *host) return ((ip & 0xFF000000u) == 0x7F000000u) || (ip == 0x00000000u); } + if (inet_aton(host, &addr4) == 1) + { + uint32_t ip = ntohl(addr4.s_addr); + return ((ip & 0xFF000000u) == 0x7F000000u) || (ip == 0x00000000u); + } + + if (strchr(host, ':') == NULL) + { + errno = 0; + char *end = NULL; + unsigned long long numeric = strtoull(host, &end, 0); + if (errno == 0 && end != host && *end == '\0' && numeric <= 0xFFFFFFFFULL) + { + struct in_addr parsed; + parsed.s_addr = htonl((uint32_t)numeric); + uint32_t ip = ntohl(parsed.s_addr); + return ((ip & 0xFF000000u) == 0x7F000000u) || (ip == 0x00000000u); + } + } + struct in6_addr addr6; if (inet_pton(AF_INET6, host, &addr6) == 1) { diff --git a/source/test/t2parser/t2parserxconfTest.cpp b/source/test/t2parser/t2parserxconfTest.cpp index 3be6e351..dffca759 100644 --- a/source/test/t2parser/t2parserxconfTest.cpp +++ b/source/test/t2parser/t2parserxconfTest.cpp @@ -131,6 +131,60 @@ TEST(T2ParserXConf, RejectsNumericLoopbackUploadUrls) EXPECT_EQ(T2ERROR_FAILURE, processConfigurationXConf((char*)json_v4_loopback, &profile)); EXPECT_EQ((ProfileXConf*)NULL, profile); + profile = NULL; + const char *json_v4_shortform_loopback = + "{" + " \"urn:settings:TelemetryProfile\": {" + " \"telemetryProfile:name\": \"LoopbackV4Short\"," + " \"uploadRepository:URL\": \"https://127.1/upload\"," + " \"schedule\": \"0/5 * * * *\"," + " \"telemetryProfile\": [ {" + " \"header\": \"param1\"," + " \"content\": \"alias1\"," + " \"type\": \"/var/log/some.log\"," + " \"pollingFrequency\": \"0\"" + " } ]" + " }" + "}"; + EXPECT_EQ(T2ERROR_FAILURE, processConfigurationXConf((char*)json_v4_shortform_loopback, &profile)); + EXPECT_EQ((ProfileXConf*)NULL, profile); + + profile = NULL; + const char *json_v4_decimal_loopback = + "{" + " \"urn:settings:TelemetryProfile\": {" + " \"telemetryProfile:name\": \"LoopbackV4Decimal\"," + " \"uploadRepository:URL\": \"https://2130706433/upload\"," + " \"schedule\": \"0/5 * * * *\"," + " \"telemetryProfile\": [ {" + " \"header\": \"param1\"," + " \"content\": \"alias1\"," + " \"type\": \"/var/log/some.log\"," + " \"pollingFrequency\": \"0\"" + " } ]" + " }" + "}"; + EXPECT_EQ(T2ERROR_FAILURE, processConfigurationXConf((char*)json_v4_decimal_loopback, &profile)); + EXPECT_EQ((ProfileXConf*)NULL, profile); + + profile = NULL; + const char *json_v4_hex_loopback = + "{" + " \"urn:settings:TelemetryProfile\": {" + " \"telemetryProfile:name\": \"LoopbackV4Hex\"," + " \"uploadRepository:URL\": \"https://0x7f000001/upload\"," + " \"schedule\": \"0/5 * * * *\"," + " \"telemetryProfile\": [ {" + " \"header\": \"param1\"," + " \"content\": \"alias1\"," + " \"type\": \"/var/log/some.log\"," + " \"pollingFrequency\": \"0\"" + " } ]" + " }" + "}"; + EXPECT_EQ(T2ERROR_FAILURE, processConfigurationXConf((char*)json_v4_hex_loopback, &profile)); + EXPECT_EQ((ProfileXConf*)NULL, profile); + profile = NULL; const char *json_v6_loopback = "{" From ff22b16d8cf23818fb35375325ed5754589df3d6 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Fri, 23 Oct 2026 15:28:20 +0530 Subject: [PATCH 19/27] Potential fix for pull request finding 'Allocation failure leaks profile resources' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- source/t2parser/t2parserxconf.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index 8f45767f..b80d4cba 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -487,6 +487,11 @@ T2ERROR processConfigurationXConf(char* configData, ProfileXConf **localProfile) if(profile->t2HTTPDest == NULL) { T2Error("Malloc error exiting: can not allocate memory to create profile->t2HTTPDest \n"); + free(profile->protocol); + free(profile->name); + pthread_cond_destroy(&profile->reportInProgressCond); + pthread_mutex_destroy(&profile->reportInProgressMutex); + free(profile); cJSON_Delete(json_root); return T2ERROR_MEMALLOC_FAILED; } From fc2aa8d4c9a20157aa6934dbc86709b2f43100c4 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Fri, 23 Oct 2026 15:30:39 +0530 Subject: [PATCH 20/27] Potential fix for pull request finding 'Reject percent-encoded hostnames before loopback validation' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- source/t2parser/t2parserxconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/t2parser/t2parserxconf.c b/source/t2parser/t2parserxconf.c index b80d4cba..0a7c7339 100644 --- a/source/t2parser/t2parserxconf.c +++ b/source/t2parser/t2parserxconf.c @@ -211,7 +211,7 @@ static bool isValidHttpsUploadUrl(const char *url) return false; } - if (isLocalNumericAddress(host)) + if (strchr(host, '%') != NULL || isLocalNumericAddress(host)) { return false; } From 7460f30a4be22afe3e9678c2437731b5270758a5 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Sun, 25 Oct 2026 05:22:45 +0000 Subject: [PATCH 21/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/test/bulkdata/profilexconfTest.cpp | 2 +- .../tests/test_multiprofile_msgpacket.py | 2 +- .../tests/test_xconf_communications.py | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/test/bulkdata/profilexconfTest.cpp b/source/test/bulkdata/profilexconfTest.cpp index e2ad1068..5f3aed5c 100644 --- a/source/test/bulkdata/profilexconfTest.cpp +++ b/source/test/bulkdata/profilexconfTest.cpp @@ -199,7 +199,7 @@ TEST_F(profileXconfTestFixture, InitandUninit) "]," "\"schedule\":\"*/1 * * * *\"," "\"expires\":0," - "\"telemetryProfile:name\":\"NEW TEST PROFILE\"," + "\"telemetryProfile:name\":\"NEW_TEST_PROFILE\"," "\"uploadRepository:URL\":\"https://mock1xconf:50051/dataLakeMockXconf\"," "\"uploadRepository:uploadProtocol\":\"HTTP\"" "}" diff --git a/test/functional-tests/tests/test_multiprofile_msgpacket.py b/test/functional-tests/tests/test_multiprofile_msgpacket.py index 2dd6c24c..757fbdd3 100644 --- a/test/functional-tests/tests/test_multiprofile_msgpacket.py +++ b/test/functional-tests/tests/test_multiprofile_msgpacket.py @@ -273,7 +273,7 @@ def test_for_invalid_activation_timeout(): assert "MODEL_NAME\":\"NULL" in grep_T2logs("cJSON Report ") # 239 - Support for reportEmpty of profiles assert "TR_AC6919" in grep_T2logs("firstreporting interval is given") # 240 - Support for First Reporting Interval -1 assert "5 sec" in grep_T2logs("firstreporting interval is given") # 240 - Support for First Reporting Interval - 2 - assert "NEW TEST PROFILE" in grep_T2logs(LOG_PROFILE_SET) # 101 - Report fetch and parse via HTTP + assert "NEW_TEST_PROFILE" in grep_T2logs(LOG_PROFILE_SET) # 101 - Report fetch and parse via HTTP assert "60 sec" in grep_T2logs("reporting interval is taken - NEW TEST PROFILE") # 107 - Configurable reporting interval # 241 - Support for DCM profile and multiprofile parallel execution assert "AccountId\":\"Platform_Container_Test_DEVICE" in grep_T2logs("cJSON Report ") # 102 - Include data from data source as TR181 Parameter diff --git a/test/functional-tests/tests/test_xconf_communications.py b/test/functional-tests/tests/test_xconf_communications.py index 99a10522..3b706edd 100644 --- a/test/functional-tests/tests/test_xconf_communications.py +++ b/test/functional-tests/tests/test_xconf_communications.py @@ -96,7 +96,7 @@ def test_change_profile(): kill_telemetry(12) sleep(10) assert os.path.exists(XCONF_PERSISTANT_FILE) - assert "NEW TEST PROFILE" in grep_T2logs("NEW TEST PROFILE") + assert "NEW_TEST_PROFILE" in grep_T2logs("NEW_TEST_PROFILE") @pytest.mark.run(order=6) def test_verify_urlencoding(): @@ -118,7 +118,7 @@ def test_verify_schedule(): command = ["echo 'This is Test Log' > /opt/logs/test.log"] run_shell_command(command) sleep(60) - ERROR_MSG = "Waiting for 60 sec for next TIMEOUT for profile as reporting interval is taken - NEW TEST PROFILE" + ERROR_MSG = "Waiting for 60 sec for next TIMEOUT for profile as reporting interval is taken - NEW_TEST_PROFILE" assert ERROR_MSG in grep_T2logs(ERROR_MSG) @pytest.mark.run(order=8) @@ -131,14 +131,14 @@ def test_verify_markers(): @pytest.mark.run(order=9) def test_verify_report(): - ERROR_MSG1 = "CollectAndReportXconf ++in profileName : NEW TEST PROFILE" + ERROR_MSG1 = "CollectAndReportXconf ++in profileName : NEW_TEST_PROFILE" ERROR_MSG2 = "cJSON Report =" assert ERROR_MSG1 in grep_T2logs(ERROR_MSG1) assert ERROR_MSG2 in grep_T2logs(ERROR_MSG2) @pytest.mark.run(order=10) def test_log_upload(): - LOG_MSG1 = "CollectAndReportXconf ++in profileName : NEW TEST PROFILE" + LOG_MSG1 = "CollectAndReportXconf ++in profileName : NEW_TEST_PROFILE" LOG_MSG2 = "cJSON Report =" clear_T2logs() kill_telemetry(10) @@ -148,7 +148,7 @@ def test_log_upload(): @pytest.mark.run(order=11) def test_log_upload_on_demand(): - LOG_MSG1 = "CollectAndReportXconf ++in profileName : NEW TEST PROFILE" + LOG_MSG1 = "CollectAndReportXconf ++in profileName : NEW_TEST_PROFILE" LOG_MSG2 = "cJSON Report =" clear_T2logs() kill_telemetry(29) From 7398225bdafbc250b2cd3037fb55f15a85718395 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Sun, 25 Oct 2026 09:29:57 +0000 Subject: [PATCH 22/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/dcautil/dca.c | 136 ++++++++++++++++++++++++++++++++++------ source/utils/t2common.c | 25 +++++++- 2 files changed, 138 insertions(+), 23 deletions(-) diff --git a/source/dcautil/dca.c b/source/dcautil/dca.c index 19144694..c7d383ba 100644 --- a/source/dcautil/dca.c +++ b/source/dcautil/dca.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -896,6 +897,102 @@ static int processPatternWithOptimizedFunction(GrepMarker* marker, FileDescripto return 0; } +static bool isSimpleLogFilename(const char* logFile) +{ + if (!logFile || *logFile == '\0') + { + return false; + } + + if (logFile[0] == '/' || strchr(logFile, '/') != NULL) + { + return false; + } + + if (strstr(logFile, "..") != NULL) + { + return false; + } + + return true; +} + +static bool resolveApprovedLogPath(const char* logPath, const char* logFile, char* out_path, size_t out_size) +{ + if (!logFile || *logFile == '\0' || !out_path || out_size == 0) + { + return false; + } + + if (isSimpleLogFilename(logFile)) + { + if (!logPath || *logPath == '\0') + { + T2Debug("Rejected log file with no valid base path: %s\n", logFile); + return false; + } + + snprintf(out_path, out_size, "%s/%s", logPath, logFile); + return true; + } + + if (logFile[0] == '/') + { + snprintf(out_path, out_size, "%s", logFile); + } + else if (logPath && *logPath != '\0') + { + snprintf(out_path, out_size, "%s/%s", logPath, logFile); + } + else + { + T2Debug("Rejected log file with no valid base path: %s\n", logFile); + return false; + } + + char resolved[PATH_MAX]; + if (realpath(out_path, resolved) == NULL) + { + T2Debug("Rejected unsafe or unresolved log path %s: %s\n", out_path, strerror(errno)); + return false; + } + + const char* allowed_roots[] = { + LOGPATH, + PREVIOUS_LOGS_PATH, + "/opt/logs", + "/var/log/messages", + NULL + }; + + for (int i = 0; allowed_roots[i] != NULL; ++i) + { + const char* root = allowed_roots[i]; + if (!root || *root == '\0') + { + continue; + } + + char root_path[PATH_MAX]; + snprintf(root_path, sizeof(root_path), "%s", root); + size_t root_len = strlen(root_path); + while (root_len > 1 && root_path[root_len - 1] == '/') + { + root_path[--root_len] = '\0'; + } + + if (strncmp(resolved, root_path, root_len) == 0 && + (resolved[root_len] == '\0' || resolved[root_len] == '/')) + { + snprintf(out_path, out_size, "%s", resolved); + return true; + } + } + + T2Debug("Rejected log path outside approved roots: %s -> %s\n", out_path, resolved); + return false; +} + static int getLogFileDescriptor(GrepSeekProfile* gsProfile, const char* logPath, const char* logFile, int old_fd, off_t* out_seek_value, bool* out_inode_changed, ino_t* out_stored_inode, bool isCustomPath) { long seek_value_from_map = 0; @@ -907,19 +1004,15 @@ static int getLogFileDescriptor(GrepSeekProfile* gsProfile, const char* logPath, } char logFilePath[PATH_MAX]; - if(logFile[0] == '/') - { - // If the logFile is an absolute path, use it directly - T2Info("Log file is an absolute path not prefix in the directory: %s\n", logFile); - snprintf(logFilePath, sizeof(logFilePath), "%s", logFile); - } - else + if (!resolveApprovedLogPath(logPath, logFile, logFilePath, sizeof(logFilePath))) { - snprintf(logFilePath, sizeof(logFilePath), "%s/%s", logPath, logFile); + T2Error("Refusing to open untrusted log path: %s\n", logFile); + return -1; } + T2Info("Log file resolved to approved path: %s\n", logFilePath); T2Debug("Opening log file %s\n", logFilePath); - int fd = open(logFilePath, O_RDONLY); + int fd = open(logFilePath, O_RDONLY | O_NOFOLLOW); if (fd == -1) { T2Debug("Failed to open log file %s\n", logFilePath); @@ -927,9 +1020,9 @@ static int getLogFileDescriptor(GrepSeekProfile* gsProfile, const char* logPath, } struct stat sb; - if (fstat(fd, &sb) == -1) + if (fstat(fd, &sb) == -1 || !S_ISREG(sb.st_mode)) { - T2Debug("Error getting file size for %s\n", logFile); + T2Debug("Error getting file size or invalid file type for %s\n", logFile); close(fd); return -1; } @@ -978,22 +1071,25 @@ static int getLogFileDescriptor(GrepSeekProfile* gsProfile, const char* logPath, static int getRotatedLogFileDescriptor(const char* logPath, const char* logFile) { char logFilePath[PATH_MAX]; - snprintf(logFilePath, sizeof(logFilePath), "%s/%s", logPath, logFile); + if (!resolveApprovedLogPath(logPath, logFile, logFilePath, sizeof(logFilePath))) + { + T2Error("Refusing to open untrusted rotated log path: %s\n", logFile); + return -1; + } + //get the rotated filename char *fileExtn = ".1"; char rotatedlogFilePath[PATH_MAX]; size_t name_len = strlen(logFilePath); if(logFile[0] == '/') { - // If the logFile is an absolute path, use it directly - T2Debug("RotatedLog file is an absolute path not prefix in the directory: %s\n", logFile); - snprintf(rotatedlogFilePath, sizeof(logFilePath), "%s", logFile); + T2Debug("RotatedLog file is an absolute path within an approved root: %s\n", logFile); + snprintf(rotatedlogFilePath, sizeof(rotatedlogFilePath), "%s", logFilePath); } else { - // If the logFile is not an absolute path, prefix it with the logPath T2Debug("RotatedLog file is not an absolute path, prefixing with directory: %s\n", logPath); - snprintf(rotatedlogFilePath, sizeof(rotatedlogFilePath), "%s/%s", logPath, logFile); + snprintf(rotatedlogFilePath, sizeof(rotatedlogFilePath), "%s", logFilePath); } if(name_len > 2 && logFilePath[name_len - 2] == '.' && logFilePath[name_len - 1] == '0') { @@ -1006,7 +1102,7 @@ static int getRotatedLogFileDescriptor(const char* logPath, const char* logFile) T2Debug("Rotated log file name is %s\n", rotatedlogFilePath); } - int rd = open(rotatedlogFilePath, O_RDONLY); + int rd = open(rotatedlogFilePath, O_RDONLY | O_NOFOLLOW); if (rd == -1) { T2Debug("Failed to open log file %s\n", rotatedlogFilePath); @@ -1014,9 +1110,9 @@ static int getRotatedLogFileDescriptor(const char* logPath, const char* logFile) } struct stat rb; - if (fstat(rd, &rb) == -1) + if (fstat(rd, &rb) == -1 || !S_ISREG(rb.st_mode)) { - T2Debug("Error getting file size for %s\n", rotatedlogFilePath); + T2Debug("Error getting file size or invalid file type for %s\n", rotatedlogFilePath); close(rd); return -1; } diff --git a/source/utils/t2common.c b/source/utils/t2common.c index e3c4b31c..0f83f1a7 100644 --- a/source/utils/t2common.c +++ b/source/utils/t2common.c @@ -104,19 +104,38 @@ bool createSecureTempFlag(const char *path) return false; } + if (access(path, F_OK) == 0) + { + if (!isSafeTempFilePath(path)) + { + T2Error("Refusing to use unsafe existing flag path %s\n", path); + return false; + } + T2Debug("Reusing existing secure flag %s\n", path); + return true; + } + if (!isSafeTempFilePath(path)) { T2Error("Refusing to use unsafe flag path %s\n", path); return false; } - int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + int fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR); if (fd < 0) { - if (errno != EEXIST) + if (errno == EEXIST) { - T2Error("Unable to create secure flag %s: %s\n", path, strerror(errno)); + if (isSafeTempFilePath(path)) + { + T2Debug("Existing secure flag already present: %s\n", path); + return true; + } + T2Error("Refusing to use unsafe existing flag path %s\n", path); + return false; } + + T2Error("Unable to create secure flag %s: %s\n", path, strerror(errno)); return false; } From 3c9744f52750981fec07fae89048842f03f9388e Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Sun, 25 Oct 2026 12:06:57 +0000 Subject: [PATCH 23/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/utils/t2common.c | 55 +++-------------------------------------- source/utils/t2common.h | 1 - 2 files changed, 3 insertions(+), 53 deletions(-) diff --git a/source/utils/t2common.c b/source/utils/t2common.c index 0f83f1a7..46f5b1ff 100644 --- a/source/utils/t2common.c +++ b/source/utils/t2common.c @@ -28,38 +28,11 @@ bool whoami_support = false; -bool isSafeTempFilePath(const char *path) -{ - struct stat st; - - if (path == NULL || *path == '\0') - { - return false; - } - - if (lstat(path, &st) == 0) - { - if (S_ISLNK(st.st_mode) || !S_ISREG(st.st_mode)) - { - T2Error("Refusing to use non-regular or symlinked temp file: %s\n", path); - return false; - } - - if (st.st_uid != geteuid()) - { - T2Error("Refusing to use temp file with unexpected owner: %s\n", path); - return false; - } - } - - return true; -} - int openSecureTempFile(const char *path, bool truncateExisting) { int fd = -1; - if (!isSafeTempFilePath(path)) + if (path == NULL || *path == '\0') { return -1; } @@ -104,35 +77,13 @@ bool createSecureTempFlag(const char *path) return false; } - if (access(path, F_OK) == 0) - { - if (!isSafeTempFilePath(path)) - { - T2Error("Refusing to use unsafe existing flag path %s\n", path); - return false; - } - T2Debug("Reusing existing secure flag %s\n", path); - return true; - } - - if (!isSafeTempFilePath(path)) - { - T2Error("Refusing to use unsafe flag path %s\n", path); - return false; - } - int fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR); if (fd < 0) { if (errno == EEXIST) { - if (isSafeTempFilePath(path)) - { - T2Debug("Existing secure flag already present: %s\n", path); - return true; - } - T2Error("Refusing to use unsafe existing flag path %s\n", path); - return false; + T2Debug("Existing secure flag already present: %s\n", path); + return true; } T2Error("Unable to create secure flag %s: %s\n", path, strerror(errno)); diff --git a/source/utils/t2common.h b/source/utils/t2common.h index 8e2df7ce..66b0d5c7 100644 --- a/source/utils/t2common.h +++ b/source/utils/t2common.h @@ -186,7 +186,6 @@ int compareLogFileNames(const void *g1, const void *g2); bool getDevicePropertyData(const char *dev_prop_name, char *out_data, unsigned int buff_size); -bool isSafeTempFilePath(const char *path); int openSecureTempFile(const char *path, bool truncateExisting); bool createSecureTempFlag(const char *path); From 2d941ac9c531d06f439cb26eddd9e0783de097e4 Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Sun, 25 Oct 2026 12:09:43 +0000 Subject: [PATCH 24/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/dcautil/dca.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/dcautil/dca.c b/source/dcautil/dca.c index c7d383ba..9951048a 100644 --- a/source/dcautil/dca.c +++ b/source/dcautil/dca.c @@ -957,7 +957,8 @@ static bool resolveApprovedLogPath(const char* logPath, const char* logFile, cha return false; } - const char* allowed_roots[] = { + const char* allowed_roots[] = + { LOGPATH, PREVIOUS_LOGS_PATH, "/opt/logs", @@ -982,7 +983,7 @@ static bool resolveApprovedLogPath(const char* logPath, const char* logFile, cha } if (strncmp(resolved, root_path, root_len) == 0 && - (resolved[root_len] == '\0' || resolved[root_len] == '/')) + (resolved[root_len] == '\0' || resolved[root_len] == '/')) { snprintf(out_path, out_size, "%s", resolved); return true; From f7834ef93b55f280b2dfa6431c8d11545b813789 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Mon, 26 Oct 2026 09:28:05 +0530 Subject: [PATCH 25/27] Potential fix for pull request finding 'CodeQL / Uncontrolled data used in path expression' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- source/dcautil/legacyutils.c | 41 +++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/source/dcautil/legacyutils.c b/source/dcautil/legacyutils.c index 083d472a..24ccda86 100644 --- a/source/dcautil/legacyutils.c +++ b/source/dcautil/legacyutils.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include "t2log_wrapper.h" #include "legacyutils.h" @@ -34,6 +37,31 @@ static char* PERSISTENT_PATH = NULL; static char* LOG_PATH = NULL; static char* DEVICE_TYPE = NULL; +static bool isValidLogBasePath(const char *path) +{ + if (path == NULL || path[0] != '/') + { + return false; + } + + /* Prevent traversal and Windows-style separators */ + if (strstr(path, "..") != NULL || strchr(path, '\\') != NULL) + { + return false; + } + + /* Reject control characters */ + for (const char *p = path; *p != '\0'; ++p) + { + if (iscntrl((unsigned char)*p)) + { + return false; + } + } + + return true; +} + /** * Start of functions dealing with log seek values */ @@ -224,11 +252,18 @@ void updateIncludeConfVal(char **logpath, char **perspath) if(0 == strncmp(props, "LOG_PATH=", strlen("LOG_PATH="))) { property = property + strlen("LOG_PATH="); - if(LOG_PATH != NULL) + if (isValidLogBasePath(property)) + { + if(LOG_PATH != NULL) + { + free(LOG_PATH); + } + LOG_PATH = strdup(property); + } + else { - free(LOG_PATH); + T2Error("Ignoring invalid LOG_PATH value from include.properties\n"); } - LOG_PATH = strdup(property); } } } From 932ea10d7349a117b4242eb913bec6736f1353cc Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Mon, 26 Oct 2026 06:45:00 +0000 Subject: [PATCH 26/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/dcautil/dca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dcautil/dca.c b/source/dcautil/dca.c index 9951048a..96532dbc 100644 --- a/source/dcautil/dca.c +++ b/source/dcautil/dca.c @@ -1103,7 +1103,7 @@ static int getRotatedLogFileDescriptor(const char* logPath, const char* logFile) T2Debug("Rotated log file name is %s\n", rotatedlogFilePath); } - int rd = open(rotatedlogFilePath, O_RDONLY | O_NOFOLLOW); + int rd = open(rotatedlogFilePath, O_RDONLY); if (rd == -1) { T2Debug("Failed to open log file %s\n", rotatedlogFilePath); From 44964a2873269303c3298ac539f04dd8f97e245f Mon Sep 17 00:00:00 2001 From: Yogeswaran K Date: Mon, 26 Oct 2026 07:01:19 +0000 Subject: [PATCH 27/27] RDKB-66750: Mythos Defect Remediation Signed-off-by: Yogeswaran K --- source/dcautil/dca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dcautil/dca.c b/source/dcautil/dca.c index 96532dbc..758930c7 100644 --- a/source/dcautil/dca.c +++ b/source/dcautil/dca.c @@ -1013,7 +1013,7 @@ static int getLogFileDescriptor(GrepSeekProfile* gsProfile, const char* logPath, T2Info("Log file resolved to approved path: %s\n", logFilePath); T2Debug("Opening log file %s\n", logFilePath); - int fd = open(logFilePath, O_RDONLY | O_NOFOLLOW); + int fd = open(logFilePath, O_RDONLY ); if (fd == -1) { T2Debug("Failed to open log file %s\n", logFilePath);