From 8d111937a1ee5926cc74557f2f057602a6db7c12 Mon Sep 17 00:00:00 2001 From: stark256-spec Date: Tue, 2 Jun 2026 14:45:08 -0500 Subject: [PATCH] fix: zero-init struct tm before gmtime_r; replace strcpy with memcpy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two independent static-analysis findings addressed in one commit since they touch disjoint files and carry the same risk category. 1. cfe_time_api.c — CFE_TIME_Print (fixes #2735) gmtime_r() returns NULL when the input time_t is outside the range representable by struct tm (overflow or platform-specific limits). The subsequent strftime() then reads from an uninitialised struct, producing undefined behaviour. Zero-initialise tm with memset before calling gmtime_r() so that a failed conversion yields a deterministic epoch-like formatted string rather than garbage or a crash. 2. cfe_assert_init.c + cfe_tbl_internal.c — strcpy (fixes #2737) Both sites append a known, fixed-length literal ('.tmp' and '(*)') into a buffer where available space has already been verified by the surrounding bounds check. Replace strcpy with memcpy(dst, literal, sizeof(literal)) which copies exactly the required bytes including the NUL terminator without relying on runtime null-termination scanning. --- modules/cfe_assert/src/cfe_assert_init.c | 2 +- modules/tbl/fsw/src/cfe_tbl_internal.c | 2 +- modules/time/fsw/src/cfe_time_api.c | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/cfe_assert/src/cfe_assert_init.c b/modules/cfe_assert/src/cfe_assert_init.c index 901b1d651..971643d93 100644 --- a/modules/cfe_assert/src/cfe_assert_init.c +++ b/modules/cfe_assert/src/cfe_assert_init.c @@ -70,7 +70,7 @@ int32 CFE_Assert_OpenLogFile(const char *Filename) { NameLen = sizeof(CFE_Assert_Global.LogFileTemp) - 5; } - strcpy(&CFE_Assert_Global.LogFileTemp[NameLen], ".tmp"); + memcpy(&CFE_Assert_Global.LogFileTemp[NameLen], ".tmp", sizeof(".tmp")); OsStatus = OS_OpenCreate(&CFE_Assert_Global.LogFileDesc, CFE_Assert_Global.LogFileTemp, diff --git a/modules/tbl/fsw/src/cfe_tbl_internal.c b/modules/tbl/fsw/src/cfe_tbl_internal.c index 4f93bf55b..eaf2a0671 100644 --- a/modules/tbl/fsw/src/cfe_tbl_internal.c +++ b/modules/tbl/fsw/src/cfe_tbl_internal.c @@ -902,7 +902,7 @@ void CFE_TBL_MarkNameAsModified(char *NameBufPtr, size_t NameBufSize) EndPtr = &NameBufPtr[NameBufSize - 4]; } - strcpy(EndPtr, "(*)"); + memcpy(EndPtr, "(*)", sizeof("(*)")); } /*---------------------------------------------------------------- diff --git a/modules/time/fsw/src/cfe_time_api.c b/modules/time/fsw/src/cfe_time_api.c index c9fec340a..a8a3f4bbc 100644 --- a/modules/time/fsw/src/cfe_time_api.c +++ b/modules/time/fsw/src/cfe_time_api.c @@ -577,7 +577,13 @@ CFE_Status_t CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint) } time_t sec = TimeToPrint.Seconds + CFE_MISSION_TIME_EPOCH_SECONDS; // epoch is Jan 1, 1980 + + /* gmtime_r returns NULL for times outside the representable range. + * Zero-initialise tm so strftime produces a defined (epoch) string + * rather than reading uninitialised stack memory. */ + memset(&tm, 0, sizeof(tm)); gmtime_r(&sec, &tm); + FmtLen = strftime(PrintBuffer, CFE_TIME_PRINTED_STRING_SIZE - 6, "%Y-%j-%H:%M:%S", &tm); PrintBuffer += FmtLen; *(PrintBuffer++) = '.';