Moderate severityNVD Advisory· Published Oct 28, 2025· Updated Oct 28, 2025
Buffer overflow in CodeChecker log command
CVE-2025-40843
Description
CodeChecker is an analyzer tooling, defect database and viewer extension for the Clang Static Analyzer and Clang Tidy.
CodeChecker versions up to 6.26.1 contain a buffer overflow vulnerability in the internal ldlogger library, which is executed by the CodeChecker log command.
This issue affects CodeChecker: through 6.26.1.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
codecheckerPyPI | < 6.26.2 | 6.26.2 |
Affected products
1- Range: 0
Patches
14122eb1b43d0Merge commit from fork
5 files changed · +106 −39
analyzer/tools/build-logger/src/ldlogger-tool.c+1 −1 modified@@ -129,7 +129,7 @@ LoggerFile* loggerFileInitFromPath(LoggerFile* file_, const char* path_) if (!loggerMakePathAbs(path_, file_->path, 0)) { /* fallback to the given path */ - strcpy(file_->path, path_); + safe_strcpy(file_->path, path_, PATH_MAX); } return file_;
analyzer/tools/build-logger/src/ldlogger-tool-gcc.c+12 −10 modified@@ -83,11 +83,12 @@ static void getDefaultArguments(const char* prog_, LoggerVector* args_) ssize_t readSize; int incStarted = 0; - strcpy(command, prog_); + safe_strcpy(command, prog_, PATH_MAX); + /* WARNING: this always gets the C++ compiler include * dirs even if we are compiling C file. * */ - strcat(command, " -xc++ -E -v - < /dev/null 2>&1"); + safe_strcat(command, " -xc++ -E -v - < /dev/null 2>&1", PATH_MAX); cmdOut = popen(command, "r"); if (!cmdOut) @@ -215,9 +216,9 @@ char* findFullPath(const char* executable, char* fullpath) { char* dir; path = strdup(getenv("PATH")); for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) { - strcpy(fullpath, dir); - strcpy(fullpath + strlen(dir), "/"); - strcpy(fullpath + strlen(dir) + 1, executable); + safe_strcpy(fullpath, dir, PATH_MAX); + safe_strcat(fullpath, "/", PATH_MAX); + safe_strcat(fullpath, executable, PATH_MAX); if (access(fullpath, F_OK ) != -1 ) { free(path); return fullpath; @@ -300,17 +301,18 @@ void transformSomePathsAbsolute(LoggerVector* args_) const char* path = (const char*)args_->data[i] + strlen(*flag); if (*path) { - char newPath[PATH_MAX]; - strcpy(newPath, *flag); + // Increased buffer size for flags + char newPath[PATH_MAX + 256]; + safe_strcpy(newPath, *flag, 256); int hasEqual = *path == '='; if (hasEqual) { - strcat(newPath, "="); + safe_strcat(newPath, "=", 256); ++path; } - loggerMakePathAbs(path, newPath + strlen(*flag) + hasEqual, 0); + loggerMakePathAbs(path, newPath + strlen(newPath), 0); loggerVectorReplace(args_, i, loggerStrDup(newPath)); } else @@ -441,7 +443,7 @@ int loggerGccParserCollectActions( } else { - strcpy(newPath, current); + safe_strcpy(newPath, current, PATH_MAX); } loggerVectorAddUnique(&action->sources, loggerStrDup(newPath), (LoggerCmpFuc) &strcmp);
analyzer/tools/build-logger/src/ldlogger-tool-javac.c+17 −17 modified@@ -47,7 +47,7 @@ static void readArgumentsFromFile(const char* file_, LoggerVector* args_) char* line = NULL; size_t lineSize = 0; ssize_t readSize; - + FILE* file = fopen(file_, "r"); if (!file) { @@ -121,18 +121,18 @@ static int handleClassPath( **resCp_ = 0; classPath = (char*) malloc((strlen(cp_) + 1) * sizeof(char)); - strcpy(classPath, cp_); + safe_strcpy(classPath, cp_, strlen(cp_) + 1); for (cpPart = strtok(classPath, ":"); cpPart; cpPart = strtok(NULL, ":")) { size_t i; char** words; wordexp_t we; - + memset(&we, 0, sizeof(wordexp_t)); if (wordexp(cpPart, &we, WRDE_NOCMD | WRDE_UNDEF) != 0) { - strcpy(*resCp_, cp_); + safe_strcpy(*resCp_, cp_, PATH_MAX); free(classPath); return 0; } @@ -155,7 +155,7 @@ static int handleClassPath( if (!newMem) { /* Out of memory */ - strcpy(*resCp_, cp_); + safe_strcpy(*resCp_, cp_, PATH_MAX); free(classPath); wordfree(&we); return 0; @@ -165,8 +165,8 @@ static int handleClassPath( *resCpSize_ = currSize * 2; } - strcat(*resCp_, path); - strcat(*resCp_, ":"); + safe_strcat(*resCp_, path, PATH_MAX); + safe_strcat(*resCp_, ":", PATH_MAX); } wordfree(&we); @@ -202,16 +202,16 @@ static void processArg(const char* arg_, ParserData* data_) return; } - strcpy(argToAdd, arg_); + safe_strcpy(argToAdd, arg_, PATH_MAX); if (data_->state == InClassDir) { if (!loggerMakePathAbs(arg_, data_->classdir, 0)) { - strcpy(data_->classdir, arg_); + safe_strcpy(data_->classdir, arg_, PATH_MAX); } - strcpy(argToAdd, data_->classdir); + safe_strcpy(argToAdd, data_->classdir, PATH_MAX); data_->state = Normal; } else if (data_->state == InClassPath) @@ -287,7 +287,7 @@ int loggerJavacParserCollectActions( LoggerVector fargs; loggerVectorInit(&fargs); - + readArgumentsFromFile(argv_[i] + 1, &fargs); for (j = 0; j < fargs.size; ++j) { @@ -330,17 +330,17 @@ int loggerJavacParserCollectActions( if (data.classdir[0] != 0) { char* fname = loggerGetFileName(src, 1); - strcpy(outputFile, data.classdir); - strcat(outputFile, "/"); - strcat(outputFile, fname); - strcat(outputFile, ".class"); + safe_strcpy(outputFile, data.classdir, PATH_MAX); + safe_strcat(outputFile, "/", PATH_MAX); + safe_strcat(outputFile, fname, PATH_MAX); + safe_strcat(outputFile, ".class", PATH_MAX); free(fname); } else { char* path = loggerGetFilePathWithoutExt(src); - strcpy(outputFile, path); - strcat(outputFile, ".class"); + safe_strcpy(outputFile, path, PATH_MAX); + safe_strcat(outputFile, ".class", PATH_MAX); free(path); }
analyzer/tools/build-logger/src/ldlogger-util.c+49 −8 modified@@ -16,6 +16,7 @@ #include <stdlib.h> #include <stdint.h> #include <stdio.h> +#include <string.h> #include <sys/file.h> #include <sys/stat.h> #include <time.h> @@ -29,12 +30,12 @@ static char* makePathAbsRec(const char* path_, char* resolved_) if (realpath(path_, pathBuff)) { - pathBuff[PATH_MAX - 1] = 0; - return strcpy(resolved_, pathBuff); + safe_strcpy(resolved_, pathBuff, PATH_MAX); + return resolved_; } else { - strcpy(pathBuff, path_); + safe_strcpy(pathBuff, path_, PATH_MAX); } /* cut off the last part */ @@ -54,8 +55,8 @@ static char* makePathAbsRec(const char* path_, char* resolved_) *slashPos = 0; if (makePathAbsRec(pathBuff, resolved_)) { - strcat(resolved_, "/"); - strcat(resolved_, child); + safe_strcat(resolved_, "/", PATH_MAX); + safe_strcat(resolved_, child, PATH_MAX); return resolved_; } @@ -248,8 +249,8 @@ char* loggerMakePathAbs(const char* path_, char* resolved_, int mustExist_) return NULL; } - strcat(newPath, "/"); - strcat(newPath, path_); + safe_strcat(newPath, "/", PATH_MAX); + safe_strcat(newPath, path_, PATH_MAX); return makePathAbsRec(newPath, resolved_); } @@ -590,7 +591,7 @@ int aquireLock(char const* logFile_) return -1; } - strcat(lockFilePath, ".lock"); + safe_strcat(lockFilePath, ".lock", PATH_MAX); lockFile = open(lockFilePath, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (lockFile == -1) { @@ -706,3 +707,43 @@ void logPrint(char* logLevel_, char* fileName_, int line_, char *fmt_,...) fclose(stream); freeLock(lockFd); } + +char* safe_strcpy(char* dest, const char* src, size_t buf_size) +{ + if (buf_size == 0) + { + fprintf(stderr, "ERROR: safe_strcpy failed, buffer size invalid\n"); + exit(1); + } + + strncpy(dest, src, buf_size); + + if (dest[buf_size - 1] != '\0') + { + fprintf(stderr, "ERROR: safe_strcpy failed, string too long\n"); + exit(1); + } + + return dest; +} + +char* safe_strcat(char* dest, const char* src, size_t buf_size) +{ + if (buf_size == 0) + { + fprintf(stderr, "ERROR: safe_strcat failed, buffer size invalid\n"); + exit(1); + } + + size_t n = buf_size - strlen(dest) - 1; + + if (strlen(src) > n) + { + fprintf(stderr, "ERROR: safe_strcat failed, string too long\n"); + exit(1); + } + + strncat(dest, src, n); + + return dest; +}
analyzer/tools/build-logger/src/ldlogger-util.h+27 −3 modified@@ -38,7 +38,7 @@ int predictEscapedSize(const char* str_); * the documentation of predictEscapedSize() for some examples. * * The '\\', '\r' and '\v' characters are also escaped correctly. - * + * * @param str_ a string to escape (non null). * @param buff_ an output buffer (non null). * @return anways returns buff_. @@ -85,7 +85,7 @@ typedef int (*LoggerPredFuc)(const void*); /** * A very simple vector. */ -typedef struct _LoggerVector +typedef struct _LoggerVector { /** * The actual size of the vector. @@ -257,7 +257,7 @@ char* loggerGetFilePathWithoutExt(const char* absPath_); /** * Return the file`s name with or without it`s extension. - * + * * @param absPath_ the absolute file path. * @param withoutExt_ with or without extension. * @return file name or NULL on error.. @@ -297,4 +297,28 @@ void freeLock(int lockFile_); */ void logPrint(char* logLevel_, char* fileName_, int line_, char* fmt_, ...); +/** + * Safe version of strcpy that checks buffer size and exits + * if string truncation would occur. + * + * @param dest destination buffer pointer. + * @param src source buffer pointer. + * @param buf_size size of the destination buffer. + * + * @return returns destination pointer dest. + */ +char* safe_strcpy(char* dest, const char* src, size_t buf_size); + +/** + * Safe version of strcat that checks buffer size and exits + * if string truncation would occur. + * + * @param dest destination buffer pointer. + * @param src source buffer pointer. + * @param buf_size size of the destination buffer. + * + * @return returns destination pointer dest. + */ +char* safe_strcat(char* dest, const char* src, size_t buf_size); + #endif /* __LOGGER_UTIL_H__ */
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.