diff --git a/config/TR181-AdvSecurity.xml b/config/TR181-AdvSecurity.xml index e705ee4..a8d9a4b 100644 --- a/config/TR181-AdvSecurity.xml +++ b/config/TR181-AdvSecurity.xml @@ -66,6 +66,12 @@ uint32 true + + ismodulerestarted + boolean + bool + false + diff --git a/source/AdvSecurityDml/cosa_adv_security_dml.c b/source/AdvSecurityDml/cosa_adv_security_dml.c index 36da4b6..bddd135 100644 --- a/source/AdvSecurityDml/cosa_adv_security_dml.c +++ b/source/AdvSecurityDml/cosa_adv_security_dml.c @@ -141,6 +141,14 @@ DeviceFingerPrint_GetParamBoolValue return TRUE; } + rc = strcmp_s("ismodulerestarted", strlen("ismodulerestarted"), ParamName, &ind); + ERR_CHK(rc); + if((rc == EOK) && (!ind)) + { + *pBool = CosaAdvSecIsModuleRestarted(); + return TRUE; + } + CcspTraceWarning(("%s: Unsupported parameter '%s'\n", __FUNCTION__, ParamName)); return FALSE; } diff --git a/source/AdvSecurityDml/cosa_adv_security_internal.c b/source/AdvSecurityDml/cosa_adv_security_internal.c index e10ddc1..635228b 100644 --- a/source/AdvSecurityDml/cosa_adv_security_internal.c +++ b/source/AdvSecurityDml/cosa_adv_security_internal.c @@ -3521,3 +3521,85 @@ ANSC_STATUS CosaAdvSecAgentRaptrDeInit(ANSC_HANDLE hThisObject) CcspTraceWarning (("AdvSecAgentRaptr_RFCEnable:FALSE\n")); return returnStatus; } + +BOOL CosaAdvSecIsModuleRestarted(void) +{ + struct sysinfo sys_info; + unsigned long uptime; + unsigned long long agent_starttime_ticks = 0; + unsigned long agent_start_secs; + unsigned long agent_runtime; + long hz; + FILE *fp = NULL; + char path[64]; + char line[1024]; + int pid = -1; + char *p = NULL; + + if (sysinfo(&sys_info) != 0) + { + CcspTraceError(("%s: Failed to get sysinfo\n", __FUNCTION__)); + return FALSE; + } + uptime = sys_info.uptime; + + /* Get cujo-agent PID */ + fp = v_secure_popen("r", "pidof cujo-agent"); + if (fp == NULL) + { + CcspTraceError(("%s: Failed to run pidof cujo-agent\n", __FUNCTION__)); + return FALSE; + } + if (fscanf(fp, "%d", &pid) != 1 || pid <= 0) + { + v_secure_pclose(fp); + CcspTraceWarning(("%s: cujo-agent process not found\n", __FUNCTION__)); + return FALSE; + } + v_secure_pclose(fp); + + /* Read starttime from /proc//stat (field 22) */ + snprintf(path, sizeof(path), "/proc/%d/stat", pid); + fp = fopen(path, "r"); + if (fp == NULL) + { + CcspTraceError(("%s: Failed to open %s\n", __FUNCTION__, path)); + return FALSE; + } + + if (fgets(line, sizeof(line), fp) == NULL) + { + fclose(fp); + CcspTraceError(("%s: Failed to read %s\n", __FUNCTION__, path)); + return FALSE; + } + fclose(fp); + + /* Skip past comm field (enclosed in parentheses) */ + p = strrchr(line, ')'); + if (p == NULL) + { + CcspTraceError(("%s: Failed to parse comm field\n", __FUNCTION__)); + return FALSE; + } + p++; + + /* Parse field 22 (starttime): skip fields 3-21 (19 fields) */ + if (sscanf(p, " %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu %*lu %*ld %*ld %*ld %*ld %*ld %*ld %llu", + &agent_starttime_ticks) != 1) + { + CcspTraceError(("%s: Failed to parse starttime\n", __FUNCTION__)); + return FALSE; + } + + hz = sysconf(_SC_CLK_TCK); + if (hz <= 0) + hz = 100; + + agent_start_secs = (unsigned long)(agent_starttime_ticks / (unsigned long long)hz); + agent_runtime = uptime - agent_start_secs; + + CcspTraceInfo(("%s: uptime=%lu agent_runtime=%lu\n", __FUNCTION__, uptime, agent_runtime)); + + return (agent_runtime < uptime); +} diff --git a/source/AdvSecurityDml/cosa_adv_security_internal.h b/source/AdvSecurityDml/cosa_adv_security_internal.h index 9fcce96..0fff629 100644 --- a/source/AdvSecurityDml/cosa_adv_security_internal.h +++ b/source/AdvSecurityDml/cosa_adv_security_internal.h @@ -564,4 +564,10 @@ CosaAdvSecFetchSbConfig ULONG* pUlSize, ULONG* puLong ); + +BOOL +CosaAdvSecIsModuleRestarted + ( + void + ); #endif diff --git a/source/test/CcspAdvSecurityDmlTest/CcspAdvSecurityDmlTest.cpp b/source/test/CcspAdvSecurityDmlTest/CcspAdvSecurityDmlTest.cpp index ab195a1..e6cdef7 100644 --- a/source/test/CcspAdvSecurityDmlTest/CcspAdvSecurityDmlTest.cpp +++ b/source/test/CcspAdvSecurityDmlTest/CcspAdvSecurityDmlTest.cpp @@ -133,6 +133,10 @@ TEST_F(CcspAdvSecurityDmlTestFixture, CheckDeviceFingerPrint_GetParamBoolValue_U .Times(1) .WillOnce(DoAll(SetArgPointee<3>(comparisonResult), Return(EOK))); + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(StrEq("ismodulerestarted"), strlen("ismodulerestarted"), StrEq(ParamName), _, _, _)) + .Times(1) + .WillOnce(DoAll(SetArgPointee<3>(comparisonResult), Return(EOK))); + BOOL result = DeviceFingerPrint_GetParamBoolValue(NULL, (char*)ParamName, &resultBool); EXPECT_FALSE(result); @@ -140,6 +144,35 @@ TEST_F(CcspAdvSecurityDmlTestFixture, CheckDeviceFingerPrint_GetParamBoolValue_U delete pMyObject; } +TEST_F(CcspAdvSecurityDmlTestFixture, CheckDeviceFingerPrint_GetParamBoolValue_IsModuleRestarted) { + BOOL resultBool; + PCOSA_DATAMODEL_AGENT pMyObject = new COSA_DATAMODEL_AGENT; + g_pAdvSecAgent = pMyObject; + + const char* ParamName = "ismodulerestarted"; + int comparisonResultNoMatch = 1; + int comparisonResultMatch = 0; + + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(StrEq("Enable"), strlen("Enable"), StrEq(ParamName), _, _, _)) + .Times(1) + .WillOnce(DoAll(SetArgPointee<3>(comparisonResultNoMatch), Return(EOK))); + + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(StrEq("ismodulerestarted"), strlen("ismodulerestarted"), StrEq(ParamName), _, _, _)) + .Times(1) + .WillOnce(DoAll(SetArgPointee<3>(comparisonResultMatch), Return(EOK))); + + EXPECT_CALL(*g_securewrapperMock, v_secure_popen(StrEq("r"), _)) + .Times(1) + .WillOnce(Return(nullptr)); + + BOOL result = DeviceFingerPrint_GetParamBoolValue(NULL, (char*)ParamName, &resultBool); + + EXPECT_TRUE(result); + EXPECT_FALSE(resultBool); + + delete pMyObject; +} + TEST_F(CcspAdvSecurityDmlTestFixture, CheckDeviceFingerPrint_SetParamBoolValue_Enable) { const char *DeviceFingerPrintEnabled = "Advsecurity_DeviceFingerPrint";