diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..942913b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Build system generated files +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +compile +config.guess +config.log +config.status +config.sub +configure +configure~ +depcomp +install-sh +libtool +ltmain.sh +missing +m4/ + +# Build artifacts +*.o +*.lo +*.la +*.a +*.so +*.bin +*.deps/ +*.dirstamp +.deps/ +.libs/ + +# Source subdirectory build files +source/**/Makefile +source/**/Makefile.in +source/**/*.deps/ +source/**/.libs/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 94130170..6a08e351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,17 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.8.4](https://github.com/rdkcentral/telemetry/compare/1.8.3...1.8.4) + +- RDKEMW-15233 [SERXIONE-8445/XIONE-18418] Develop Support Branch Integration [`#295`](https://github.com/rdkcentral/telemetry/pull/295) +- RDKB-63834: Reject and Remove Corrupted Config Files In Persistance [`#284`](https://github.com/rdkcentral/telemetry/pull/284) + #### [1.8.3](https://github.com/rdkcentral/telemetry/compare/1.8.2...1.8.3) +> 19 March 2026 + - RDKB-63722: Build fix for ssl crypto error in platforms with lower ssl version [`#291`](https://github.com/rdkcentral/telemetry/pull/291) +- Changelog updates for 1.8.3 release [`cac6d7f`](https://github.com/rdkcentral/telemetry/commit/cac6d7f0182481bb1d1664bd0bc1afce9e429e25) #### [1.8.2](https://github.com/rdkcentral/telemetry/compare/1.8.1...1.8.2) diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index fc7b1205..c53abd19 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -428,7 +428,6 @@ static void* reportOnDemand(void *input) if(!strncmp(action, ON_DEMAND_ACTION_UPLOAD, MAX_PROFILENAMES_LENGTH)) { T2Info("Upload XCONF report on demand \n"); - set_logdemand(true); generateDcaReport(false, true); } else if(!strncmp(action, ON_DEMAND_ACTION_ABORT, MAX_PROFILENAMES_LENGTH)) diff --git a/source/scheduler/scheduler.c b/source/scheduler/scheduler.c index c6fdbf78..5c9d3195 100644 --- a/source/scheduler/scheduler.c +++ b/source/scheduler/scheduler.c @@ -44,21 +44,21 @@ static ActivationTimeoutCB activationTimeoutCb; static Vector *profileList = NULL; static pthread_mutex_t scMutex; static bool sc_initialized = false; -static bool islogdemand = false; +static bool isretainSeekmap = true; static bool signalrecived_and_executing = true; static bool is_activation_time_out = false; -bool get_logdemand () +bool get_retainseekmap () { - T2Info(("get_logdemand ++in\n")); - return islogdemand; + T2Info(("get_retainseekmap ++in\n")); + return isretainSeekmap; } -void set_logdemand (bool value) +void set_retainseekmap (bool value) { - T2Info(("set_logdemand ++in\n")); - islogdemand = value; + T2Info(("set_retainseekmap ++in\n")); + isretainSeekmap = value; } void freeSchedulerProfile(void *data) @@ -297,14 +297,14 @@ void* TimeoutThread(void *arg) if(minThresholdTime == 0) { - if (get_logdemand() == true) + if (get_retainseekmap() == true) { - set_logdemand(false); - timeoutNotificationCb(tProfile->name, false); + timeoutNotificationCb(tProfile->name, false); // Passing clearseekvalue as false } else { - timeoutNotificationCb(tProfile->name, true); + set_retainseekmap(true); //After triggering LOG upload resetting the retainseekmap value to true so the next report generation doesn't affect + timeoutNotificationCb(tProfile->name, true); //Passing clearseek value as true } if(tProfile->terminated) { diff --git a/source/scheduler/scheduler.h b/source/scheduler/scheduler.h index 5bee6b9d..356cf398 100644 --- a/source/scheduler/scheduler.h +++ b/source/scheduler/scheduler.h @@ -60,8 +60,8 @@ T2ERROR unregisterProfileFromScheduler(const char* profileName); T2ERROR SendInterruptToTimeoutThread(char* profileName); -bool get_logdemand(); +bool get_retainseekmap(); -void set_logdemand(bool value); +void set_retainseekmap(bool value); #endif /* _SCHEDULER_H_ */ diff --git a/source/telemetry2_0.c b/source/telemetry2_0.c index 9acd53ee..bb92e5a6 100644 --- a/source/telemetry2_0.c +++ b/source/telemetry2_0.c @@ -181,13 +181,12 @@ void sig_handler(int sig, siginfo_t* info, void* uc) else if ( sig == SIGUSR1 || sig == LOG_UPLOAD ) { T2Info(("LOG_UPLOAD received!\n")); - set_logdemand(false); + set_retainseekmap(false); ReportProfiles_Interrupt(); } else if (sig == LOG_UPLOAD_ONDEMAND || sig == SIGIO) { T2Info(("LOG_UPLOAD_ONDEMAND received!\n")); - set_logdemand(true); ReportProfiles_Interrupt(); } else if(sig == SIGUSR2 || sig == EXEC_RELOAD) diff --git a/source/test/bulkdata/SchedulerMock.cpp b/source/test/bulkdata/SchedulerMock.cpp index 49af8bfa..0611b642 100755 --- a/source/test/bulkdata/SchedulerMock.cpp +++ b/source/test/bulkdata/SchedulerMock.cpp @@ -85,22 +85,22 @@ T2ERROR SendInterruptToTimeoutThread(char* profileName) return T2ERROR_SUCCESS; } -bool get_logdemand() +bool get_retainseekmap() { if (g_schedulerMock) { - return g_schedulerMock->get_logdemand(); + return g_schedulerMock->get_retainseekmap(); } // Fallback implementation for when mock is not set return false; } -void set_logdemand(bool value) +void set_retainseekmap(bool value) { if (g_schedulerMock) { - g_schedulerMock->set_logdemand(value); + g_schedulerMock->set_retainseekmap(value); return; } diff --git a/source/test/bulkdata/SchedulerMock.h b/source/test/bulkdata/SchedulerMock.h index 42bd26b7..ad1c6d30 100755 --- a/source/test/bulkdata/SchedulerMock.h +++ b/source/test/bulkdata/SchedulerMock.h @@ -35,8 +35,8 @@ class SchedulerMock MOCK_METHOD(T2ERROR, registerProfileWithScheduler, (const char* profileName, unsigned int timeInterval, unsigned int activationTimeout, bool deleteonTimout, bool repeat, bool reportOnUpdate, unsigned int firstReportingInterval, char *timeRef), ()); MOCK_METHOD(T2ERROR, unregisterProfileFromScheduler, (const char* profileName), ()); MOCK_METHOD(T2ERROR, SendInterruptToTimeoutThread, (char* profileName), ()); - MOCK_METHOD(bool, get_logdemand, (), ()); - MOCK_METHOD(void, set_logdemand, (bool value), ()); + MOCK_METHOD(bool, get_retainseekmap, (), ()); + MOCK_METHOD(void, set_retainseekmap, (bool value), ()); MOCK_METHOD(int, getLapsedTime, (struct timespec *result, struct timespec *x, struct timespec *y), ()); }; diff --git a/source/test/bulkdata/profileTest.cpp b/source/test/bulkdata/profileTest.cpp index 09108f6d..f2b43205 100644 --- a/source/test/bulkdata/profileTest.cpp +++ b/source/test/bulkdata/profileTest.cpp @@ -823,8 +823,8 @@ TEST_F(ProfileTest, privacymode_do_not_share) { } TEST_F(ProfileTest, generateDcaReport) { - // generateDcaReport may call set_logdemand - EXPECT_CALL(*g_schedulerMock, set_logdemand(_)) + // generateDcaReport may call set_retainseekmap + EXPECT_CALL(*g_schedulerMock, set_retainseekmap(_)) .Times(::testing::AtMost(2)); // Allow up to 2 calls generateDcaReport(false, true); diff --git a/source/test/mocks/FileioMock.cpp b/source/test/mocks/FileioMock.cpp index 60e19aaf..59f33257 100644 --- a/source/test/mocks/FileioMock.cpp +++ b/source/test/mocks/FileioMock.cpp @@ -473,6 +473,22 @@ extern "C" int fprintf(FILE* stream, const char* format, ...) { va_end(args); return result; } + +/* Intercept the FORTIFY_SOURCE-hardened variant of fprintf */ +extern "C" int __fprintf_chk(FILE* stream, int /*flag*/, const char* format, ...) { + va_list args; + va_start(args, format); + int result = -1; + + if (g_fileIOMock) { + result = g_fileIOMock->fprintf(stream, format, args); + } + else { + result = vfprintf(stream, format, args); + } + va_end(args); + return result; +} /* extern "C" CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...) { diff --git a/source/test/scheduler/schedulerTest.cpp b/source/test/scheduler/schedulerTest.cpp index 3f44961a..53ec7ada 100644 --- a/source/test/scheduler/schedulerTest.cpp +++ b/source/test/scheduler/schedulerTest.cpp @@ -123,14 +123,14 @@ class rdklogTestFixture : public ::testing::Test { }; -TEST(GET_LOGDEMAND, TEST1) +TEST(GET_RETAINSEEKMAP, TEST1) { - EXPECT_EQ( false, get_logdemand()); + EXPECT_EQ( true, get_retainseekmap()); } -TEST(SET_LOGDEMAND, TEST1) +TEST(SET_RETAINSEEKMAP, TEST1) { - set_logdemand(true); + set_retainseekmap(true); } TEST(GETLAPSEDTIME, T1_GT_T2) diff --git a/source/test/utils/UtilsTest.cpp b/source/test/utils/UtilsTest.cpp index 2327539a..71d5a834 100644 --- a/source/test/utils/UtilsTest.cpp +++ b/source/test/utils/UtilsTest.cpp @@ -50,6 +50,7 @@ using namespace std; using ::testing::_; using ::testing::Return; using ::testing::StrEq; +using ::testing::Invoke; //Testing t2MtlsUtils TEST(GET_CERTS, MTLS_UTILS_NULL) @@ -770,6 +771,49 @@ TEST_F(utilsTestFixture, FETCHLOCALCONFIGS_FUNC4) Vector_Destroy(configlist, free); } +TEST_F(utilsTestFixture, FETCHLOCALCONFIGS_EMPTY_FILE) +{ + const char* path = "/opt/.t2persistentFolder/"; + DIR *dir = (DIR*)0xffffffff; + Vector* configlist = NULL; + Vector_Create(&configlist); + struct dirent *entry = NULL; + entry = (struct dirent *)malloc(sizeof(struct dirent)); + entry->d_type = DT_REG; + std::strncpy(entry->d_name, "TestProfile.json", sizeof(entry->d_name) - 1); + entry->d_name[sizeof(entry->d_name) - 1] = '\0'; + EXPECT_CALL(*g_fileIOMock, opendir(_)) + .Times(1) + .WillOnce(Return(dir)); + EXPECT_CALL(*g_fileIOMock, readdir(_)) + .Times(2) + .WillOnce(Return(entry)) + .WillOnce(Return((struct dirent *)NULL)); + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_fileIOMock, fstat(_,_)) + .Times(1) + .WillOnce(Invoke([](int /*fd*/, struct stat* buf) -> int { + memset(buf, 0, sizeof(struct stat)); + buf->st_size = 0; + return 0; + })); + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, closedir(_)) + .Times(1) + .WillOnce(Return(0)); + ASSERT_EQ(T2ERROR_SUCCESS, fetchLocalConfigs(path, configlist)); + EXPECT_EQ(0, (int)Vector_Size(configlist)); + Vector_Destroy(configlist, free); + free(entry); +} + #if defined (MTLS_FROM_ENV) TEST(GetMtlsCertsTest, ReturnsDynamicCertsWhenEnvSet) { setenv("XPKI", "1", 1); @@ -915,28 +959,44 @@ TEST_F(utilsTestFixture, SAVECONFITOFILE1) .WillOnce(Return(mockfp)); ASSERT_EQ(T2ERROR_FAILURE, saveConfigToFile(filepath, profilename, config)); } -/* -TEST_F(utilsTestFixture, SAVECONFITOFILE2) +TEST_F(utilsTestFixture, SAVECONFITOFILE_FPRINTF_FAILURE) { - const char* filepath = "/nvram/.t2reportprofiles"; - const char* profilename = "Profile_1"; - const char* config = "This is a config string"; - FILE* mockfp = (FILE *)0xffffffff; - + const char* filepath = "/nvram/.t2reportprofiles/"; + const char* profilename = "Profile_1"; + const char* config = "This is a config string"; + FILE* mockfp = (FILE *)0xffffffff; EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(mockfp)); + .Times(1) + .WillOnce(Return(mockfp)); EXPECT_CALL(*g_fileIOMock, fprintf(_,_,_)) - .Times(1) - .WillOnce(Return(-1)); + .Times(1) + .WillOnce(Return(-1)); EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(saveConfigToFile(filepath, profilename, config), T2ERROR_SUCCESS); + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(1) + .WillOnce(Return(0)); + ASSERT_EQ(T2ERROR_FAILURE, saveConfigToFile(filepath, profilename, config)); +} +TEST_F(utilsTestFixture, SAVECONFITOFILE_SUCCESS) +{ + const char* filepath = "/nvram/.t2reportprofiles/"; + const char* profilename = "Profile_1"; + const char* config = "This is a config string"; + FILE* mockfp = (FILE *)0xffffffff; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(mockfp)); + EXPECT_CALL(*g_fileIOMock, fprintf(_,_,_)) + .Times(1) + .WillOnce(Return((int)strlen(config))); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(1) + .WillOnce(Return(0)); + ASSERT_EQ(T2ERROR_SUCCESS, saveConfigToFile(filepath, profilename, config)); } -*/ TEST_F(utilsTestFixture, getDevicePropertyData) { diff --git a/source/utils/persistence.c b/source/utils/persistence.c index 253ec412..065983fa 100644 --- a/source/utils/persistence.c +++ b/source/utils/persistence.c @@ -112,6 +112,14 @@ T2ERROR fetchLocalConfigs(const char* path, Vector *configList) if(status == 0) { T2Info("Filename : %s Size : %ld\n", entry->d_name, (long int)filestat.st_size); + // Skip empty profile files + if(filestat.st_size == 0) + { + T2Warning("Skipping empty config file : %s\n", entry->d_name); + close(fp); + removeProfileFromDisk(path, entry->d_name); + continue; + } Config *config = (Config *)malloc(sizeof(Config)); memset(config, 0, sizeof(Config)); @@ -168,7 +176,13 @@ T2ERROR saveConfigToFile(const char* path, const char *profileName, const char* T2Error("Unable to write to file : %s\n", filePath); return T2ERROR_FAILURE; } - fprintf(fp, "%s", configuration); + if(fprintf(fp, "%s", configuration) < 0) + { + T2Error("Failed to write to file : %s\n", filePath); + fclose(fp); + removeProfileFromDisk(path, profileName); + return T2ERROR_FAILURE; + } if(fclose(fp) != 0) { T2Error("Unable to close file : %s\n", filePath);