From ee3a35e175f52e9f3b7c79f994e7bc4b6d9886f5 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 06 2019 09:54:42 +0000 Subject: import rsyslog-8.24.0-38.el7 --- diff --git a/SOURCES/rsyslog-8.24.0-doc-rhbz1625935-mmkubernetes-CRI-O.patch b/SOURCES/rsyslog-8.24.0-doc-rhbz1625935-mmkubernetes-CRI-O.patch new file mode 100644 index 0000000..ac5d8bc --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-doc-rhbz1625935-mmkubernetes-CRI-O.patch @@ -0,0 +1,65 @@ +From 7b09e9782c4e6892a8d16fd4e3aa2cca440a41e6 Mon Sep 17 00:00:00 2001 +From: Rich Megginson +Date: Wed, 22 Aug 2018 08:37:03 -0600 +Subject: [PATCH] url not required - add information about CRI-O + +The KubernetesURL parameter is not mandatory since it has +a useful default value. +Add information about CRI-O. +Minor cleanup. +--- + source/configuration/modules/mmkubernetes.rst | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/source/configuration/modules/mmkubernetes.rst b/source/configuration/modules/mmkubernetes.rst +index be9e710f..a3cd4d49 100644 +--- a/source/configuration/modules/mmkubernetes.rst ++++ b/source/configuration/modules/mmkubernetes.rst +@@ -19,14 +19,14 @@ namespace. + + .. note:: + +- This **only** works with log files in `/var/log/containers/*.log` +- (docker `--log-driver=json-file`), or with journald entries with ++ This **only** works with log files in `/var/log/containers/*.log` (docker ++ `--log-driver=json-file`, or CRI-O log files), or with journald entries with + message properties `CONTAINER_NAME` and `CONTAINER_ID_FULL` (docker +- `--log-driver=journald`), and when the application running inside +- the container writes logs to `stdout`/`stderr`. This **does not** +- currently work with other log drivers. ++ `--log-driver=journald`), and when the application running inside the ++ container writes logs to `stdout`/`stderr`. This **does not** currently ++ work with other log drivers. + +-For json-file logs, you must use the `imfile` module with the ++For json-file and CRI-O logs, you must use the `imfile` module with the + `addmetadata="on"` parameter, and the filename must match the + liblognorm rules specified by the `filenamerules` + (:ref:`filenamerules`) or `filenamerulebase` (:ref:`filenamerulebase`) +@@ -70,7 +70,7 @@ KubernetesURL + :widths: auto + :class: parameter-table + +- "word", "https://kubernetes.default.svc.cluster.local:443", "yes", "none" ++ "word", "https://kubernetes.default.svc.cluster.local:443", "no", "none" + + The URL of the Kubernetes API server. Example: `https://localhost:8443`. + +@@ -248,8 +248,6 @@ match the filename and extract metadata. The default value is:: + In the above rules, the slashes ``\`` ending each line indicate + line wrapping - they are not part of the rule. + +-There are two rules because the `container_hash` is optional. +- + .. _filenamerulebase: + + filenamerulebase +@@ -351,6 +349,8 @@ get the basic necessary Kubernetes metadata from the filename: + input(type="imfile" file="/var/log/containers/*.log" + tag="kubernetes" addmetadata="on") + ++(Add `reopenOnTruncate="on"` if using Docker, not required by CRI-O). ++ + and/or an `imjournal` input for docker journald container logs annotated by + Kubernetes: + diff --git a/SOURCES/rsyslog-8.24.0-rhbz1622767-mmkubernetes-stop-on-pod-delete.patch b/SOURCES/rsyslog-8.24.0-rhbz1622767-mmkubernetes-stop-on-pod-delete.patch new file mode 100644 index 0000000..956e27e --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1622767-mmkubernetes-stop-on-pod-delete.patch @@ -0,0 +1,764 @@ +From 3987cd929d859f900318b393133c3bdde8dfffd5 Mon Sep 17 00:00:00 2001 +From: Rich Megginson +Date: Tue, 28 Aug 2018 12:44:23 -0600 +Subject: [PATCH] mmkubertnetes: action fails preparation cycle if kubernetes + API destroys resource during bootup sequence + +The plugin was not handling 404 Not Found correctly when looking +up pods and namespaces. In this case, we assume the pod/namespace +was deleted, annotate the record with whatever metadata we have, +and cache the fact that the pod/namespace is missing so we don't +attempt to look it up again. +In addition, the plugin was not handling error 429 Busy correctly. +In this case, it should also annotate the record with whatever +metadata it has, and _not_ cache anything. By default the plugin +will retry every 5 seconds to connect to Kubernetes. This +behavior is controlled by the new config param `busyretryinterval`. +This commit also adds impstats counters so that admins can +view the state of the plugin to see if the lookups are working +or are returning errors. The stats are reported per-instance +or per-action to facilitate using multiple different actions +for different Kubernetes servers. +This commit also adds support for client cert auth to +Kubernetes via the two new config params `tls.mycert` and +`tls.myprivkey`. +--- + contrib/mmkubernetes/mmkubernetes.c | 296 ++++++++++++++++++++++++---- + 1 files changed, 272 insertions(+), 24 deletions(-) + +diff --git a/contrib/mmkubernetes/mmkubernetes.c b/contrib/mmkubernetes/mmkubernetes.c +index 422cb2577..5bf5b049d 100644 +--- a/contrib/mmkubernetes/mmkubernetes.c ++++ b/contrib/mmkubernetes/mmkubernetes.c +@@ -52,9 +52,12 @@ + #include "syslogd-types.h" + #include "module-template.h" + #include "errmsg.h" ++#include "statsobj.h" + #include "regexp.h" + #include "hashtable.h" + #include "srUtils.h" ++#include "unicode-helper.h" ++#include "datetime.h" + + /* static data */ + MODULE_TYPE_OUTPUT /* this is technically an output plugin */ +@@ -62,6 +65,8 @@ MODULE_TYPE_KEEP /* releasing the module would cause a leak through libcurl */ + DEF_OMOD_STATIC_DATA + DEFobjCurrIf(errmsg) + DEFobjCurrIf(regexp) ++DEFobjCurrIf(statsobj) ++DEFobjCurrIf(datetime) + + #define HAVE_LOADSAMPLESFROMSTRING 1 + #if defined(NO_LOADSAMPLESFROMSTRING) +@@ -95,12 +100,14 @@ DEFobjCurrIf(regexp) + #define DFLT_CONTAINER_NAME "$!CONTAINER_NAME" /* name of variable holding CONTAINER_NAME value */ + #define DFLT_CONTAINER_ID_FULL "$!CONTAINER_ID_FULL" /* name of variable holding CONTAINER_ID_FULL value */ + #define DFLT_KUBERNETES_URL "https://kubernetes.default.svc.cluster.local:443" ++#define DFLT_BUSY_RETRY_INTERVAL 5 /* retry every 5 seconds */ + + static struct cache_s { + const uchar *kbUrl; + struct hashtable *mdHt; + struct hashtable *nsHt; + pthread_mutex_t *cacheMtx; ++ int lastBusyTime; + } **caches; + + typedef struct { +@@ -116,6 +123,8 @@ struct modConfData_s { + uchar *srcMetadataPath; /* where to get data for kubernetes queries */ + uchar *dstMetadataPath; /* where to put metadata obtained from kubernetes */ + uchar *caCertFile; /* File holding the CA cert (+optional chain) of CA that issued the Kubernetes server cert */ ++ uchar *myCertFile; /* File holding cert corresponding to private key used for client cert auth */ ++ uchar *myPrivKeyFile; /* File holding private key corresponding to cert used for client cert auth */ + sbool allowUnsignedCerts; /* For testing/debugging - do not check for CA certs (CURLOPT_SSL_VERIFYPEER FALSE) */ + uchar *token; /* The token value to use to authenticate to Kubernetes - takes precedence over tokenFile */ + uchar *tokenFile; /* The file whose contents is the token value to use to authenticate to Kubernetes */ +@@ -127,6 +136,7 @@ struct modConfData_s { + uchar *fnRulebase; /* lognorm rulebase filename for container log filename match */ + char *contRules; /* lognorm rules for CONTAINER_NAME value match */ + uchar *contRulebase; /* lognorm rulebase filename for CONTAINER_NAME value match */ ++ int busyRetryInterval; /* how to handle 429 response - 0 means error, non-zero means retry every N seconds */ + }; + + /* action (instance) configuration data */ +@@ -135,6 +145,8 @@ typedef struct _instanceData { + msgPropDescr_t *srcMetadataDescr; /* where to get data for kubernetes queries */ + uchar *dstMetadataPath; /* where to put metadata obtained from kubernetes */ + uchar *caCertFile; /* File holding the CA cert (+optional chain) of CA that issued the Kubernetes server cert */ ++ uchar *myCertFile; /* File holding cert corresponding to private key used for client cert auth */ ++ uchar *myPrivKeyFile; /* File holding private key corresponding to cert used for client cert auth */ + sbool allowUnsignedCerts; /* For testing/debugging - do not check for CA certs (CURLOPT_SSL_VERIFYPEER FALSE) */ + uchar *token; /* The token value to use to authenticate to Kubernetes - takes precedence over tokenFile */ + uchar *tokenFile; /* The file whose contents is the token value to use to authenticate to Kubernetes */ +@@ -151,6 +163,7 @@ typedef struct _instanceData { + msgPropDescr_t *contNameDescr; /* CONTAINER_NAME field */ + msgPropDescr_t *contIdFullDescr; /* CONTAINER_ID_FULL field */ + struct cache_s *cache; ++ int busyRetryInterval; /* how to handle 429 response - 0 means error, non-zero means retry every N seconds */ + } instanceData; + + typedef struct wrkrInstanceData { +@@ -159,6 +172,16 @@ typedef struct wrkrInstanceData { + struct curl_slist *curlHdr; + char *curlRply; + size_t curlRplyLen; ++ statsobj_t *stats; /* stats for this instance */ ++ STATSCOUNTER_DEF(k8sRecordSeen, mutK8sRecordSeen) ++ STATSCOUNTER_DEF(namespaceMetadataSuccess, mutNamespaceMetadataSuccess) ++ STATSCOUNTER_DEF(namespaceMetadataNotFound, mutNamespaceMetadataNotFound) ++ STATSCOUNTER_DEF(namespaceMetadataBusy, mutNamespaceMetadataBusy) ++ STATSCOUNTER_DEF(namespaceMetadataError, mutNamespaceMetadataError) ++ STATSCOUNTER_DEF(podMetadataSuccess, mutPodMetadataSuccess) ++ STATSCOUNTER_DEF(podMetadataNotFound, mutPodMetadataNotFound) ++ STATSCOUNTER_DEF(podMetadataBusy, mutPodMetadataBusy) ++ STATSCOUNTER_DEF(podMetadataError, mutPodMetadataError) + } wrkrInstanceData_t; + + /* module parameters (v6 config format) */ +@@ -167,6 +190,8 @@ static struct cnfparamdescr modpdescr[] = { + { "srcmetadatapath", eCmdHdlrString, 0 }, + { "dstmetadatapath", eCmdHdlrString, 0 }, + { "tls.cacert", eCmdHdlrString, 0 }, ++ { "tls.mycert", eCmdHdlrString, 0 }, ++ { "tls.myprivkey", eCmdHdlrString, 0 }, + { "allowunsignedcerts", eCmdHdlrBinary, 0 }, + { "token", eCmdHdlrString, 0 }, + { "tokenfile", eCmdHdlrString, 0 }, +@@ -174,7 +199,8 @@ static struct cnfparamdescr modpdescr[] = { + { "de_dot", eCmdHdlrBinary, 0 }, + { "de_dot_separator", eCmdHdlrString, 0 }, + { "filenamerulebase", eCmdHdlrString, 0 }, +- { "containerrulebase", eCmdHdlrString, 0 } ++ { "containerrulebase", eCmdHdlrString, 0 }, ++ { "busyretryinterval", eCmdHdlrInt, 0 } + #if HAVE_LOADSAMPLESFROMSTRING == 1 + , + { "filenamerules", eCmdHdlrArray, 0 }, +@@ -193,6 +219,8 @@ static struct cnfparamdescr actpdescr[] = { + { "srcmetadatapath", eCmdHdlrString, 0 }, + { "dstmetadatapath", eCmdHdlrString, 0 }, + { "tls.cacert", eCmdHdlrString, 0 }, ++ { "tls.mycert", eCmdHdlrString, 0 }, ++ { "tls.myprivkey", eCmdHdlrString, 0 }, + { "allowunsignedcerts", eCmdHdlrBinary, 0 }, + { "token", eCmdHdlrString, 0 }, + { "tokenfile", eCmdHdlrString, 0 }, +@@ -200,7 +228,8 @@ static struct cnfparamdescr actpdescr[] = { + { "de_dot", eCmdHdlrBinary, 0 }, + { "de_dot_separator", eCmdHdlrString, 0 }, + { "filenamerulebase", eCmdHdlrString, 0 }, +- { "containerrulebase", eCmdHdlrString, 0 } ++ { "containerrulebase", eCmdHdlrString, 0 }, ++ { "busyretryinterval", eCmdHdlrInt, 0 } + #if HAVE_LOADSAMPLESFROMSTRING == 1 + , + { "filenamerules", eCmdHdlrArray, 0 }, +@@ -493,8 +522,9 @@ ENDbeginCnfLoad + BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +- FILE *fp; ++ FILE *fp = NULL; + int ret; ++ char errStr[1024]; + CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { +@@ -509,6 +539,7 @@ CODESTARTsetModCnf + } + + loadModConf->de_dot = DFLT_DE_DOT; ++ loadModConf->busyRetryInterval = DFLT_BUSY_RETRY_INTERVAL; + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) { + continue; +@@ -528,11 +559,39 @@ CODESTARTsetModCnf + rs_strerror_r(errno, errStr, sizeof(errStr)); + iRet = RS_RET_NO_FILE_ACCESS; + errmsg.LogError(0, iRet, +- "error: certificate file %s couldn't be accessed: %s\n", ++ "error: 'tls.cacert' file %s couldn't be accessed: %s\n", + loadModConf->caCertFile, errStr); + ABORT_FINALIZE(iRet); + } else { + fclose(fp); ++ fp = NULL; ++ } ++ } else if(!strcmp(modpblk.descr[i].name, "tls.mycert")) { ++ free(loadModConf->myCertFile); ++ loadModConf->myCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); ++ fp = fopen((const char*)loadModConf->myCertFile, "r"); ++ if(fp == NULL) { ++ rs_strerror_r(errno, errStr, sizeof(errStr)); ++ iRet = RS_RET_NO_FILE_ACCESS; ++ LogError(0, iRet, ++ "error: 'tls.mycert' file %s couldn't be accessed: %s\n", ++ loadModConf->myCertFile, errStr); ++ } else { ++ fclose(fp); ++ fp = NULL; ++ } ++ } else if(!strcmp(modpblk.descr[i].name, "tls.myprivkey")) { ++ loadModConf->myPrivKeyFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); ++ fp = fopen((const char*)loadModConf->myPrivKeyFile, "r"); ++ if(fp == NULL) { ++ rs_strerror_r(errno, errStr, sizeof(errStr)); ++ iRet = RS_RET_NO_FILE_ACCESS; ++ LogError(0, iRet, ++ "error: 'tls.myprivkey' file %s couldn't be accessed: %s\n", ++ loadModConf->myPrivKeyFile, errStr); ++ } else { ++ fclose(fp); ++ fp = NULL; + } + } else if(!strcmp(modpblk.descr[i].name, "allowunsignedcerts")) { + loadModConf->allowUnsignedCerts = pvals[i].val.d.n; +@@ -557,6 +614,7 @@ CODESTARTsetModCnf + ABORT_FINALIZE(iRet); + } else { + fclose(fp); ++ fp = NULL; + } + } else if(!strcmp(modpblk.descr[i].name, "annotation_match")) { + free_annotationmatch(&loadModConf->annotation_match); +@@ -586,6 +643,7 @@ CODESTARTsetModCnf + ABORT_FINALIZE(iRet); + } else { + fclose(fp); ++ fp = NULL; + } + #if HAVE_LOADSAMPLESFROMSTRING == 1 + } else if(!strcmp(modpblk.descr[i].name, "containerrules")) { +@@ -606,7 +663,10 @@ CODESTARTsetModCnf + ABORT_FINALIZE(iRet); + } else { + fclose(fp); ++ fp = NULL; + } ++ } else if(!strcmp(modpblk.descr[i].name, "busyretryinterval")) { ++ loadModConf->busyRetryInterval = pvals[i].val.d.n; + } else { + dbgprintf("mmkubernetes: program error, non-handled " + "param '%s' in module() block\n", modpblk.descr[i].name); +@@ -650,6 +710,8 @@ CODESTARTsetModCnf + caches = calloc(1, sizeof(struct cache_s *)); + + finalize_it: ++ if (fp) ++ fclose(fp); + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); + ENDsetModCnf +@@ -667,6 +729,8 @@ CODESTARTfreeInstance + free(pData->srcMetadataDescr); + free(pData->dstMetadataPath); + free(pData->caCertFile); ++ free(pData->myCertFile); ++ free(pData->myPrivKeyFile); + free(pData->token); + free(pData->tokenFile); + free(pData->fnRules); +@@ -710,6 +774,45 @@ CODESTARTcreateWrkrInstance + char *tokenHdr = NULL; + FILE *fp = NULL; + char *token = NULL; ++ char *statsName = NULL; ++ ++ CHKiRet(statsobj.Construct(&(pWrkrData->stats))); ++ if ((-1 == asprintf(&statsName, "mmkubernetes(%s)", pWrkrData->pData->kubernetesUrl)) || ++ (!statsName)) { ++ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); ++ } ++ CHKiRet(statsobj.SetName(pWrkrData->stats, (uchar *)statsName)); ++ free(statsName); ++ statsName = NULL; ++ CHKiRet(statsobj.SetOrigin(pWrkrData->stats, UCHAR_CONSTANT("mmkubernetes"))); ++ STATSCOUNTER_INIT(pWrkrData->k8sRecordSeen, pWrkrData->mutK8sRecordSeen); ++ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("recordseen"), ++ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->k8sRecordSeen))); ++ STATSCOUNTER_INIT(pWrkrData->namespaceMetadataSuccess, pWrkrData->mutNamespaceMetadataSuccess); ++ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadatasuccess"), ++ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataSuccess))); ++ STATSCOUNTER_INIT(pWrkrData->namespaceMetadataNotFound, pWrkrData->mutNamespaceMetadataNotFound); ++ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadatanotfound"), ++ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataNotFound))); ++ STATSCOUNTER_INIT(pWrkrData->namespaceMetadataBusy, pWrkrData->mutNamespaceMetadataBusy); ++ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadatabusy"), ++ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataBusy))); ++ STATSCOUNTER_INIT(pWrkrData->namespaceMetadataError, pWrkrData->mutNamespaceMetadataError); ++ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadataerror"), ++ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataError))); ++ STATSCOUNTER_INIT(pWrkrData->podMetadataSuccess, pWrkrData->mutPodMetadataSuccess); ++ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadatasuccess"), ++ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataSuccess))); ++ STATSCOUNTER_INIT(pWrkrData->podMetadataNotFound, pWrkrData->mutPodMetadataNotFound); ++ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadatanotfound"), ++ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataNotFound))); ++ STATSCOUNTER_INIT(pWrkrData->podMetadataBusy, pWrkrData->mutPodMetadataBusy); ++ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadatabusy"), ++ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataBusy))); ++ STATSCOUNTER_INIT(pWrkrData->podMetadataError, pWrkrData->mutPodMetadataError); ++ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadataerror"), ++ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataError))); ++ CHKiRet(statsobj.ConstructFinalize(pWrkrData->stats)); + + hdr = curl_slist_append(hdr, "Content-Type: text/json; charset=utf-8"); + if (pWrkrData->pData->token) { +@@ -749,12 +852,20 @@ CODESTARTcreateWrkrInstance + curl_easy_setopt(ctx, CURLOPT_WRITEDATA, pWrkrData); + if(pWrkrData->pData->caCertFile) + curl_easy_setopt(ctx, CURLOPT_CAINFO, pWrkrData->pData->caCertFile); ++ if(pWrkrData->pData->myCertFile) ++ curl_easy_setopt(ctx, CURLOPT_SSLCERT, pWrkrData->pData->myCertFile); ++ if(pWrkrData->pData->myPrivKeyFile) ++ curl_easy_setopt(ctx, CURLOPT_SSLKEY, pWrkrData->pData->myPrivKeyFile); + if(pWrkrData->pData->allowUnsignedCerts) + curl_easy_setopt(ctx, CURLOPT_SSL_VERIFYPEER, 0); + + pWrkrData->curlCtx = ctx; + finalize_it: + free(token); ++ free(statsName); ++ if ((iRet != RS_RET_OK) && pWrkrData->stats) { ++ statsobj.Destruct(&(pWrkrData->stats)); ++ } + if (fp) { + fclose(fp); + } +@@ -765,6 +876,7 @@ BEGINfreeWrkrInstance + CODESTARTfreeWrkrInstance + curl_easy_cleanup(pWrkrData->curlCtx); + curl_slist_free_all(pWrkrData->curlHdr); ++ statsobj.Destruct(&(pWrkrData->stats)); + ENDfreeWrkrInstance + + +@@ -790,6 +902,8 @@ cacheNew(const uchar *const url) + key_equals_string, (void (*)(void *)) json_object_put); + cache->nsHt = create_hashtable(100, hash_from_string, + key_equals_string, (void (*)(void *)) json_object_put); ++ dbgprintf("mmkubernetes: created cache mdht [%p] nsht [%p]\n", ++ cache->mdHt, cache->nsHt); + cache->cacheMtx = malloc(sizeof(pthread_mutex_t)); + if (!cache->mdHt || !cache->nsHt || !cache->cacheMtx) { + free (cache); +@@ -797,6 +911,7 @@ cacheNew(const uchar *const url) + FINALIZE; + } + pthread_mutex_init(cache->cacheMtx, NULL); ++ cache->lastBusyTime = 0; + + finalize_it: + return cache; +@@ -816,9 +931,10 @@ static void cacheFree(struct cache_s *cache) + BEGINnewActInst + struct cnfparamvals *pvals = NULL; + int i; +- FILE *fp; ++ FILE *fp = NULL; + char *rxstr = NULL; + char *srcMetadataPath = NULL; ++ char errStr[1024]; + CODESTARTnewActInst + DBGPRINTF("newActInst (mmkubernetes)\n"); + +@@ -840,6 +956,7 @@ CODESTARTnewActInst + + pData->de_dot = loadModConf->de_dot; + pData->allowUnsignedCerts = loadModConf->allowUnsignedCerts; ++ pData->busyRetryInterval = loadModConf->busyRetryInterval; + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) { + continue; +@@ -872,6 +988,33 @@ CODESTARTnewActInst + ABORT_FINALIZE(iRet); + } else { + fclose(fp); ++ fp = NULL; ++ } ++ } else if(!strcmp(actpblk.descr[i].name, "tls.mycert")) { ++ pData->myCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); ++ fp = fopen((const char*)pData->myCertFile, "r"); ++ if(fp == NULL) { ++ rs_strerror_r(errno, errStr, sizeof(errStr)); ++ iRet = RS_RET_NO_FILE_ACCESS; ++ LogError(0, iRet, ++ "error: 'tls.mycert' file %s couldn't be accessed: %s\n", ++ pData->myCertFile, errStr); ++ } else { ++ fclose(fp); ++ fp = NULL; ++ } ++ } else if(!strcmp(actpblk.descr[i].name, "tls.myprivkey")) { ++ pData->myPrivKeyFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); ++ fp = fopen((const char*)pData->myPrivKeyFile, "r"); ++ if(fp == NULL) { ++ rs_strerror_r(errno, errStr, sizeof(errStr)); ++ iRet = RS_RET_NO_FILE_ACCESS; ++ LogError(0, iRet, ++ "error: 'tls.myprivkey' file %s couldn't be accessed: %s\n", ++ pData->myPrivKeyFile, errStr); ++ } else { ++ fclose(fp); ++ fp = NULL; + } + } else if(!strcmp(actpblk.descr[i].name, "allowunsignedcerts")) { + pData->allowUnsignedCerts = pvals[i].val.d.n; +@@ -892,6 +1034,7 @@ CODESTARTnewActInst + ABORT_FINALIZE(iRet); + } else { + fclose(fp); ++ fp = NULL; + } + } else if(!strcmp(actpblk.descr[i].name, "annotation_match")) { + free_annotationmatch(&pData->annotation_match); +@@ -921,6 +1063,7 @@ CODESTARTnewActInst + ABORT_FINALIZE(iRet); + } else { + fclose(fp); ++ fp = NULL; + } + #if HAVE_LOADSAMPLESFROMSTRING == 1 + } else if(!strcmp(modpblk.descr[i].name, "containerrules")) { +@@ -941,7 +1083,10 @@ CODESTARTnewActInst + ABORT_FINALIZE(iRet); + } else { + fclose(fp); ++ fp = NULL; + } ++ } else if(!strcmp(actpblk.descr[i].name, "busyretryinterval")) { ++ pData->busyRetryInterval = pvals[i].val.d.n; + } else { + dbgprintf("mmkubernetes: program error, non-handled " + "param '%s' in action() block\n", actpblk.descr[i].name); +@@ -982,6 +1127,10 @@ CODESTARTnewActInst + pData->dstMetadataPath = (uchar *) strdup((char *) loadModConf->dstMetadataPath); + if(pData->caCertFile == NULL && loadModConf->caCertFile) + pData->caCertFile = (uchar *) strdup((char *) loadModConf->caCertFile); ++ if(pData->myCertFile == NULL && loadModConf->myCertFile) ++ pData->myCertFile = (uchar *) strdup((char *) loadModConf->myCertFile); ++ if(pData->myPrivKeyFile == NULL && loadModConf->myPrivKeyFile) ++ pData->myPrivKeyFile = (uchar *) strdup((char *) loadModConf->myPrivKeyFile); + if(pData->token == NULL && loadModConf->token) + pData->token = (uchar *) strdup((char *) loadModConf->token); + if(pData->tokenFile == NULL && loadModConf->tokenFile) +@@ -1018,6 +1167,8 @@ CODESTARTnewActInst + CODE_STD_FINALIZERnewActInst + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &actpblk); ++ if(fp) ++ fclose(fp); + free(rxstr); + free(srcMetadataPath); + ENDnewActInst +@@ -1061,6 +1212,8 @@ CODESTARTfreeCnf + free(pModConf->srcMetadataPath); + free(pModConf->dstMetadataPath); + free(pModConf->caCertFile); ++ free(pModConf->myCertFile); ++ free(pModConf->myPrivKeyFile); + free(pModConf->token); + free(pModConf->tokenFile); + free(pModConf->de_dot_separator); +@@ -1069,8 +1222,11 @@ CODESTARTfreeCnf + free(pModConf->contRules); + free(pModConf->contRulebase); + free_annotationmatch(&pModConf->annotation_match); +- for(i = 0; caches[i] != NULL; i++) ++ for(i = 0; caches[i] != NULL; i++) { ++ dbgprintf("mmkubernetes: freeing cache [%d] mdht [%p] nsht [%p]\n", ++ i, caches[i]->mdHt, caches[i]->nsHt); + cacheFree(caches[i]); ++ } + free(caches); + ENDfreeCnf + +@@ -1082,6 +1238,8 @@ CODESTARTdbgPrintInstInfo + dbgprintf("\tsrcMetadataPath='%s'\n", pData->srcMetadataDescr->name); + dbgprintf("\tdstMetadataPath='%s'\n", pData->dstMetadataPath); + dbgprintf("\ttls.cacert='%s'\n", pData->caCertFile); ++ dbgprintf("\ttls.mycert='%s'\n", pData->myCertFile); ++ dbgprintf("\ttls.myprivkey='%s'\n", pData->myPrivKeyFile); + dbgprintf("\tallowUnsignedCerts='%d'\n", pData->allowUnsignedCerts); + dbgprintf("\ttoken='%s'\n", pData->token); + dbgprintf("\ttokenFile='%s'\n", pData->tokenFile); +@@ -1093,6 +1251,7 @@ CODESTARTdbgPrintInstInfo + dbgprintf("\tfilenamerules='%s'\n", pData->fnRules); + dbgprintf("\tcontainerrules='%s'\n", pData->contRules); + #endif ++ dbgprintf("\tbusyretryinterval='%d'\n", pData->busyRetryInterval); + ENDdbgPrintInstInfo + + +@@ -1206,6 +1365,24 @@ queryKB(wrkrInstanceData_t *pWrkrData, char *url, struct json_object **rply) + struct json_object *jo; + long resp_code = 400; + ++ if (pWrkrData->pData->cache->lastBusyTime) { ++ time_t now; ++ datetime.GetTime(&now); ++ now -= pWrkrData->pData->cache->lastBusyTime; ++ if (now < pWrkrData->pData->busyRetryInterval) { ++ LogMsg(0, RS_RET_RETRY, LOG_DEBUG, ++ "mmkubernetes: Waited [%ld] of [%d] seconds for the requested url [%s]\n", ++ now, pWrkrData->pData->busyRetryInterval, url); ++ ABORT_FINALIZE(RS_RET_RETRY); ++ } else { ++ LogMsg(0, RS_RET_OK, LOG_DEBUG, ++ "mmkubernetes: Cleared busy status after [%d] seconds - " ++ "will retry the requested url [%s]\n", ++ pWrkrData->pData->busyRetryInterval, url); ++ pWrkrData->pData->cache->lastBusyTime = 0; ++ } ++ } ++ + /* query kubernetes for pod info */ + ccode = curl_easy_setopt(pWrkrData->curlCtx, CURLOPT_URL, url); + if(ccode != CURLE_OK) +@@ -1411,17 +1411,23 @@ queryKB(wrkrInstanceData_t *pWrkrData, char *url, struct json_object **rply) + ABORT_FINALIZE(RS_RET_ERR); + } + if(resp_code == 404) { +- errmsg.LogMsg(0, RS_RET_ERR, LOG_ERR, ++ errmsg.LogMsg(0, RS_RET_NOT_FOUND, LOG_INFO, + "mmkubernetes: Not Found: the resource does not exist at url [%s]\n", + url); +- ABORT_FINALIZE(RS_RET_ERR); ++ ABORT_FINALIZE(RS_RET_NOT_FOUND); + } + if(resp_code == 429) { +- errmsg.LogMsg(0, RS_RET_ERR, LOG_ERR, ++ if (pWrkrData->pData->busyRetryInterval) { ++ time_t now; ++ datetime.GetTime(&now); ++ pWrkrData->pData->cache->lastBusyTime = now; ++ } ++ ++ errmsg.LogMsg(0, RS_RET_RETRY, LOG_INFO, + "mmkubernetes: Too Many Requests: the server is too heavily loaded " + "to provide the data for the requested url [%s]\n", + url); +- ABORT_FINALIZE(RS_RET_ERR); ++ ABORT_FINALIZE(RS_RET_RETRY); + } + if(resp_code != 200) { + errmsg.LogMsg(0, RS_RET_ERR, LOG_ERR, +@@ -1299,12 +1482,14 @@ BEGINdoAction + char *mdKey = NULL; + struct json_object *jMetadata = NULL, *jMetadataCopy = NULL, *jMsgMeta = NULL, + *jo = NULL; +- int add_ns_metadata = 0; ++ int add_pod_metadata = 1; + CODESTARTdoAction + CHKiRet_Hdlr(extractMsgMetadata(pMsg, pWrkrData->pData, &jMsgMeta)) { + ABORT_FINALIZE((iRet == RS_RET_NOT_FOUND) ? RS_RET_OK : iRet); + } + ++ STATSCOUNTER_INC(pWrkrData->k8sRecordSeen, pWrkrData->mutK8sRecordSeen); ++ + if (fjson_object_object_get_ex(jMsgMeta, "pod_name", &jo)) + podName = json_object_get_string(jo); + if (fjson_object_object_get_ex(jMsgMeta, "namespace_name", &jo)) +@@ -1347,28 +1532,49 @@ CODESTARTdoAction + } + iRet = queryKB(pWrkrData, url, &jReply); + free(url); +- /* todo: implement support for the .orphaned namespace */ +- if (iRet != RS_RET_OK) { ++ if (iRet == RS_RET_NOT_FOUND) { ++ /* negative cache namespace - make a dummy empty namespace metadata object */ ++ jNsMeta = json_object_new_object(); ++ STATSCOUNTER_INC(pWrkrData->namespaceMetadataNotFound, ++ pWrkrData->mutNamespaceMetadataNotFound); ++ } else if (iRet == RS_RET_RETRY) { ++ /* server is busy - retry or error */ ++ STATSCOUNTER_INC(pWrkrData->namespaceMetadataBusy, ++ pWrkrData->mutNamespaceMetadataBusy); ++ if (0 == pWrkrData->pData->busyRetryInterval) { ++ pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx); ++ ABORT_FINALIZE(RS_RET_ERR); ++ } ++ add_pod_metadata = 0; /* don't cache pod metadata either - retry both */ ++ } else if (iRet != RS_RET_OK) { ++ /* hard error - something the admin needs to fix e.g. network, config, auth */ + json_object_put(jReply); + jReply = NULL; ++ STATSCOUNTER_INC(pWrkrData->namespaceMetadataError, ++ pWrkrData->mutNamespaceMetadataError); + pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx); + FINALIZE; +- } +- +- if(fjson_object_object_get_ex(jReply, "metadata", &jNsMeta)) { ++ } else if (fjson_object_object_get_ex(jReply, "metadata", &jNsMeta)) { + jNsMeta = json_object_get(jNsMeta); + parse_labels_annotations(jNsMeta, &pWrkrData->pData->annotation_match, + pWrkrData->pData->de_dot, + (const char *)pWrkrData->pData->de_dot_separator, + pWrkrData->pData->de_dot_separator_len); +- add_ns_metadata = 1; ++ STATSCOUNTER_INC(pWrkrData->namespaceMetadataSuccess, ++ pWrkrData->mutNamespaceMetadataSuccess); + } else { + /* namespace with no metadata??? */ + errmsg.LogMsg(0, RS_RET_ERR, LOG_INFO, + "mmkubernetes: namespace [%s] has no metadata!\n", ns); +- jNsMeta = NULL; ++ /* negative cache namespace - make a dummy empty namespace metadata object */ ++ jNsMeta = json_object_new_object(); ++ STATSCOUNTER_INC(pWrkrData->namespaceMetadataSuccess, ++ pWrkrData->mutNamespaceMetadataSuccess); + } + ++ if(jNsMeta) { ++ hashtable_insert(pWrkrData->pData->cache->nsHt, strdup(ns), jNsMeta); ++ } + json_object_put(jReply); + jReply = NULL; + } +@@ -1381,14 +1587,28 @@ CODESTARTdoAction + } + iRet = queryKB(pWrkrData, url, &jReply); + free(url); +- if(iRet != RS_RET_OK) { +- if(jNsMeta && add_ns_metadata) { +- hashtable_insert(pWrkrData->pData->cache->nsHt, strdup(ns), jNsMeta); ++ if (iRet == RS_RET_NOT_FOUND) { ++ /* negative cache pod - make a dummy empty pod metadata object */ ++ iRet = RS_RET_OK; ++ STATSCOUNTER_INC(pWrkrData->podMetadataNotFound, pWrkrData->mutPodMetadataNotFound); ++ } else if (iRet == RS_RET_RETRY) { ++ /* server is busy - retry or error */ ++ STATSCOUNTER_INC(pWrkrData->podMetadataBusy, pWrkrData->mutPodMetadataBusy); ++ if (0 == pWrkrData->pData->busyRetryInterval) { ++ pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx); ++ ABORT_FINALIZE(RS_RET_ERR); + } ++ add_pod_metadata = 0; /* do not cache so that we can retry */ ++ iRet = RS_RET_OK; ++ } else if(iRet != RS_RET_OK) { ++ /* hard error - something the admin needs to fix e.g. network, config, auth */ + json_object_put(jReply); + jReply = NULL; ++ STATSCOUNTER_INC(pWrkrData->podMetadataError, pWrkrData->mutPodMetadataError); + pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx); + FINALIZE; ++ } else { ++ STATSCOUNTER_INC(pWrkrData->podMetadataSuccess, pWrkrData->mutPodMetadataSuccess); + } + + jo = json_object_new_object(); +@@ -1435,11 +1655,9 @@ CODESTARTdoAction + json_object_object_add(jo, "container_id", json_object_get(jo2)); + json_object_object_add(jMetadata, "docker", jo); + +- hashtable_insert(pWrkrData->pData->cache->mdHt, mdKey, jMetadata); +- mdKey = NULL; +- if(jNsMeta && add_ns_metadata) { +- hashtable_insert(pWrkrData->pData->cache->nsHt, strdup(ns), jNsMeta); +- ns = NULL; ++ if (add_pod_metadata) { ++ hashtable_insert(pWrkrData->pData->cache->mdHt, mdKey, jMetadata); ++ mdKey = NULL; + } + } + +@@ -1450,6 +1668,11 @@ CODESTARTdoAction + * outside of the cache lock + */ + jMetadataCopy = json_tokener_parse(json_object_get_string(jMetadata)); ++ if (!add_pod_metadata) { ++ /* jMetadata object was created from scratch and not cached */ ++ json_object_put(jMetadata); ++ jMetadata = NULL; ++ } + pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx); + /* the +1 is there to skip the leading '$' */ + msgAddJSON(pMsg, (uchar *) pWrkrData->pData->dstMetadataPath + 1, jMetadataCopy, 0, 0); +@@ -1691,6 +1693,8 @@ BEGINmodExit + + objRelease(regexp, LM_REGEXP_FILENAME); + objRelease(errmsg, CORE_COMPONENT); ++ objRelease(datetime, CORE_COMPONENT); ++ objRelease(statsobj, CORE_COMPONENT); + ENDmodExit + + +@@ -1705,6 +1711,8 @@ CODEmodInit_QueryRegCFSLineHdlr + DBGPRINTF("mmkubernetes: module compiled with rsyslog version %s.\n", VERSION); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(regexp, LM_REGEXP_FILENAME)); ++ CHKiRet(objUse(datetime, CORE_COMPONENT)); ++ CHKiRet(objUse(statsobj, CORE_COMPONENT)); + + /* CURL_GLOBAL_ALL initializes more than is needed but the + * libcurl documentation discourages use of other values +--- a/contrib/mmkubernetes/mmkubernetes.c ++++ b/contrib/mmkubernetes/mmkubernetes.c +@@ -560,7 +560,6 @@ + loadModConf->caCertFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)loadModConf->caCertFile, "r"); + if(fp == NULL) { +- char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + iRet = RS_RET_NO_FILE_ACCESS; + errmsg.LogError(0, iRet, +@@ -608,7 +607,6 @@ + loadModConf->tokenFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)loadModConf->tokenFile, "r"); + if(fp == NULL) { +- char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + iRet = RS_RET_NO_FILE_ACCESS; + errmsg.LogError(0, iRet, +@@ -638,7 +636,6 @@ + loadModConf->fnRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)loadModConf->fnRulebase, "r"); + if(fp == NULL) { +- char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + iRet = RS_RET_NO_FILE_ACCESS; + errmsg.LogError(0, iRet, +@@ -659,7 +656,6 @@ + loadModConf->contRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)loadModConf->contRulebase, "r"); + if(fp == NULL) { +- char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + iRet = RS_RET_NO_FILE_ACCESS; + errmsg.LogError(0, iRet, +@@ -975,7 +971,6 @@ + pData->caCertFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)pData->caCertFile, "r"); + if(fp == NULL) { +- char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + iRet = RS_RET_NO_FILE_ACCESS; + errmsg.LogError(0, iRet, +@@ -1022,7 +1017,6 @@ + pData->tokenFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)pData->tokenFile, "r"); + if(fp == NULL) { +- char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + iRet = RS_RET_NO_FILE_ACCESS; + errmsg.LogError(0, iRet, +@@ -1052,7 +1046,6 @@ + pData->fnRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)pData->fnRulebase, "r"); + if(fp == NULL) { +- char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + iRet = RS_RET_NO_FILE_ACCESS; + errmsg.LogError(0, iRet, +@@ -1073,7 +1066,6 @@ + pData->contRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)pData->contRulebase, "r"); + if(fp == NULL) { +- char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + iRet = RS_RET_NO_FILE_ACCESS; + errmsg.LogError(0, iRet, diff --git a/SOURCES/rsyslog-8.24.0-rhbz1632211-journal-cursor-fix.patch b/SOURCES/rsyslog-8.24.0-rhbz1632211-journal-cursor-fix.patch new file mode 100644 index 0000000..a5f35c0 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1632211-journal-cursor-fix.patch @@ -0,0 +1,104 @@ +From: Jiri Vymazal +Date: Thu, 14 Mar 2019 10:58:03 +0100 +Subject: [PATCH] Journal cursor related fixes + +Added missing free() calls of received journal cursor +In one case there was possibility of free()'d value of journal +cursor not being reset, causing double-free and crash later on. +Not trying to get and save position of invalid journal +--- + plugins/imjournal/imjournal.c | 28 +++++---- + 1 file changed, 15 insertions(+), 13 deletitions(-) + +diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c +index a85e52100..f5c2be4b6 100644 +--- a/plugins/imjournal/imjournal.c ++++ b/plugins/imjournal/imjournal.c +@@ -121,7 +121,7 @@ + + #define J_PROCESS_PERIOD 1024 /* Call sd_journal_process() every 1,024 records */ + +-static rsRetVal persistJournalState(void); ++static rsRetVal persistJournalState(int trySave); + static rsRetVal loadJournalState(void); + + static rsRetVal openJournal(sd_journal** jj) { +@@ -140,10 +140,10 @@ + RETiRet; + } + +-static void closeJournal(sd_journal** jj) { ++static void closeJournal(sd_journal** jj, int trySave) { + + if (cs.stateFile) { /* can't persist without a state file */ +- persistJournalState(); ++ persistJournalState(trySave); + } + sd_journal_close(*jj); + j_inotify_fd = 0; +@@ -433,7 +434,7 @@ + /* This function gets journal cursor and saves it into state file + */ + static rsRetVal +-persistJournalState (void) ++persistJournalState(int trySave) + { + DEFiRet; + FILE *sf; /* state file */ +@@ -443,12 +444,13 @@ + if (cs.bWorkAroundJournalBug) { + if (!last_cursor) + ABORT_FINALIZE(RS_RET_OK); +- +- } else if ((ret = sd_journal_get_cursor(j, &last_cursor)) < 0) { +- char errStr[256]; +- rs_strerror_r(-(ret), errStr, sizeof(errStr)); +- errmsg.LogError(0, RS_RET_ERR, "sd_journal_get_cursor() failed: '%s'\n", errStr); +- ABORT_FINALIZE(RS_RET_ERR); ++ } else if (trySave) { ++ if ((ret = sd_journal_get_cursor(j, &last_cursor))) { ++ LogError(-ret, RS_RET_ERR, "imjournal: sd_journal_get_cursor() failed"); ++ ABORT_FINALIZE(RS_RET_ERR); ++ } ++ } else { /* not trying to get cursor out of invalid journal state */ ++ ABORT_FINALIZE(RS_RET_OK); + } + /* we create a temporary name by adding a ".tmp" + * suffix to the end of our state file's name +@@ -501,7 +506,7 @@ + r = sd_journal_wait(j, POLL_TIMEOUT); + + if (r == SD_JOURNAL_INVALIDATE) { +- closeJournal(&j); ++ closeJournal(&j, 0); + + iRet = openJournal(&j); + if (iRet != RS_RET_OK) +@@ -628,7 +634,7 @@ + tryRecover(void) { + errmsg.LogMsg(0, RS_RET_OK, LOG_INFO, "imjournal: trying to recover from unexpected " + "journal error"); +- closeJournal(&j); ++ closeJournal(&j, 1); + srSleep(10, 0); // do not hammer machine with too-frequent retries + openJournal(&j); + } +@@ -708,7 +708,7 @@ + if (cs.stateFile) { /* can't persist without a state file */ + /* TODO: This could use some finer metric. */ + if ((count % cs.iPersistStateInterval) == 0) { +- persistJournalState(); ++ persistJournalState(1); + } + } + } +@@ -764,7 +764,7 @@ + /* close journal */ + BEGINafterRun + CODESTARTafterRun +- closeJournal(&j); ++ closeJournal(&j, 1); + ratelimitDestruct(ratelimiter); + ENDafterRun + + diff --git a/SOURCES/rsyslog-8.24.0-rhbz1632659-omfwd-mem-corruption.patch b/SOURCES/rsyslog-8.24.0-rhbz1632659-omfwd-mem-corruption.patch new file mode 100644 index 0000000..61e67e0 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1632659-omfwd-mem-corruption.patch @@ -0,0 +1,51 @@ +From 5bbd0a4b3c212425ace54bf8a8ede5b832776209 Mon Sep 17 00:00:00 2001 +From: Rainer Gerhards +Date: Wed, 6 Sep 2017 13:16:42 +0200 +Subject: [PATCH] core: memory corruption during configuration parsing + +when omfwd is used with the $streamdriverpermittedpeers legacy +parameter, a memory corruption can occur. This depends on the +length of the provided strings and probably the malloc subsystem. + +Once config parsing succeeds, no problem can happen. + +Thanks to Brent Douglas for initially reporting this issue and +providing great analysis. +Thanks to github user bwdoll for analyzing this bug and providing +a suggested fix (which is almost what this commit includes). + +closes https://github.com/rsyslog/rsyslog/issues/1408 +closes https://github.com/rsyslog/rsyslog/issues/1474 +--- + tools/omfwd.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/tools/omfwd.c b/tools/omfwd.c +index 3bffbb3cc..8d51fbb51 100644 +--- a/tools/omfwd.c ++++ b/tools/omfwd.c +@@ -1157,7 +1157,6 @@ CODESTARTnewActInst + pData->pszStrmDrvrAuthMode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "streamdriverpermittedpeers")) { + uchar *start, *str; +- uchar save; + uchar *p; + int lenStr; + str = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); +@@ -1170,8 +1169,6 @@ CODESTARTnewActInst + if(*p == ',') { + *p = '\0'; + } +- save = *(p+1); /* we always have this, at least the \0 byte at EOS */ +- *(p+1) = '\0'; + if(*start == '\0') { + DBGPRINTF("omfwd: ignoring empty permitted peer\n"); + } else { +@@ -1181,7 +1178,6 @@ CODESTARTnewActInst + start = p+1; + if(lenStr) + --lenStr; +- *(p+1) = save; + } + free(str); + } else if(!strcmp(actpblk.descr[i].name, "ziplevel")) { diff --git a/SOURCES/rsyslog-8.24.0-rhbz1649250-imfile-rotation.patch b/SOURCES/rsyslog-8.24.0-rhbz1649250-imfile-rotation.patch new file mode 100644 index 0000000..85cb451 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1649250-imfile-rotation.patch @@ -0,0 +1,306 @@ +From 31350bc0b935920f9924317b4cb3602602420f83 Mon Sep 17 00:00:00 2001 +From: Jiri Vymazal +Date: Fri, 16 Nov 2018 13:16:13 +0100 +Subject: [PATCH] bugfix imfile: file change was not reliably detected + +A change in the inode was not detected under all circumstances, +most importantly not in some logrotate cases. + +Previously, truncation was only detected at end of file. Especially with +busy files that could cause loss of data and possibly also stall imfile +reading. The new code now also checks during each read. Obviously, there +is some additional overhead associated with that, but this is unavoidable. + +It still is highly recommended NOT to turn on "reopenOnTruncate" in imfile. +Note that there are also inherant reliability issues. There is no way to +"fix" these, as they are caused by races between the process(es) who truncate +and rsyslog reading the file. But with the new code, the "problem window" +should be much smaller and, more importantly, imfile should not stall. +--- + plugins/imfile/imfile.c | 13 ++++++++++++- + runtime/rsyslog.h | 1 + + runtime/stream.c | 116 ++++++++- + runtime/stream.h | 7 +++++++ + 4 files changed, 125 insertions(+), 11 deletions(-) + +diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c +index f4a4ef9b7..6be8b2999 100644 +--- a/plugins/imfile/imfile.c ++++ b/plugins/imfile/imfile.c +@@ -740,8 +740,19 @@ detect_updates(fs_edge_t *const edge) + act_obj_unlink(act); + restart = 1; + break; ++ } else if(fileInfo.st_ino != act->ino) { ++ DBGPRINTF("file '%s' inode changed from %llu to %llu, unlinking from " ++ "internal lists\n", act->name, (long long unsigned) act->ino, ++ (long long unsigned) fileInfo.st_ino); ++ if(act->pStrm != NULL) { ++ /* we do no need to re-set later, as act_obj_unlink ++ * will destroy the strm obj */ ++ strmSet_checkRotation(act->pStrm, STRM_ROTATION_DO_NOT_CHECK); ++ } ++ act_obj_unlink(act); ++ restart = 1; ++ break; + } +- // TODO: add inode check for change notification! + + /* Note: active nodes may get deleted, so we need to do the + * pointer advancement at the end of the for loop! +diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h +index 61d0af623..22a1c46d1 100644 +--- a/runtime/rsyslog.h ++++ b/runtime/rsyslog.h +@@ -183,6 +183,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified otherwise */ + RS_RET_NOT_IMPLEMENTED = -7, /**< implementation is missing (probably internal error or lazyness ;)) */ + RS_RET_OUT_OF_MEMORY = -6, /**< memory allocation failed */ + RS_RET_PROVIDED_BUFFER_TOO_SMALL = -50,/**< the caller provided a buffer, but the called function sees the size of this buffer is too small - operation not carried out */ ++ RS_RET_FILE_TRUNCATED = -51, /**< (input) file was truncated, not an error but a status */ + RS_RET_TRUE = -3, /**< to indicate a true state (can be used as TRUE, legacy) */ + RS_RET_FALSE = -2, /**< to indicate a false state (can be used as FALSE, legacy) */ + RS_RET_NO_IRET = -8, /**< This is a trick for the debuging system - it means no iRet is provided */ +diff --git a/runtime/stream.c b/runtime/stream.c +index 2d494c612..5b52591ef 100644 +--- a/runtime/stream.c ++++ b/runtime/stream.c +@@ -400,6 +400,7 @@ static rsRetVal strmOpenFile(strm_t *pThis) + CHKiRet(doPhysOpen(pThis)); + + pThis->iCurrOffs = 0; ++ pThis->iBufPtrMax = 0; + CHKiRet(getFileSize(pThis->pszCurrFName, &offset)); + if(pThis->tOperationsMode == STREAMMODE_WRITE_APPEND) { + pThis->iCurrOffs = offset; +@@ -574,7 +574,7 @@ strmNextFile(strm_t *pThis) + * a file change is detected only if the inode changes. -- rgerhards, 2011-01-10 + */ + static rsRetVal +-strmHandleEOFMonitor(strm_t *pThis) ++strmHandleEOFMonitor(strm_t *const pThis) + { + DEFiRet; + struct stat statName; +@@ -611,7 +611,7 @@ strmHandleEOFMonitor(strm_t *pThis) + * rgerhards, 2008-02-13 + */ + static rsRetVal +-strmHandleEOF(strm_t *pThis) ++strmHandleEOF(strm_t *const pThis) + { + DEFiRet; + +@@ -629,7 +629,13 @@ strmHandleEOF(strm_t *pThis) + CHKiRet(strmNextFile(pThis)); + break; + case STREAMTYPE_FILE_MONITOR: +- CHKiRet(strmHandleEOFMonitor(pThis)); ++ DBGOPRINT((obj_t*) pThis, "file '%s' (%d) EOF, rotationCheck %d\n", ++ pThis->pszCurrFName, pThis->fd, pThis->rotationCheck); ++ if(pThis->rotationCheck == STRM_ROTATION_DO_CHECK) { ++ CHKiRet(strmHandleEOFMonitor(pThis)); ++ } else { ++ ABORT_FINALIZE(RS_RET_EOF); ++ } + break; + } + +@@ -636,6 +637,75 @@ strmHandleEOF(strm_t *pThis) + RETiRet; + } + ++ ++/* helper to checkTruncation */ ++static rsRetVal ++rereadTruncated(strm_t *const pThis, const char *const reason) ++{ ++ DEFiRet; ++ ++ LogMsg(errno, RS_RET_FILE_TRUNCATED, LOG_WARNING, "file '%s': truncation detected, " ++ "(%s) - re-start reading from beginning", ++ pThis->pszCurrFName, reason); ++ DBGPRINTF("checkTruncation, file %s last buffer CHANGED\n", pThis->pszCurrFName); ++ CHKiRet(strmCloseFile(pThis)); ++ CHKiRet(strmOpenFile(pThis)); ++ iRet = RS_RET_FILE_TRUNCATED; ++ ++finalize_it: ++ RETiRet; ++} ++/* helper to read: ++ * Check if file has been truncated since last read and, if so, re-set reading ++ * to begin of file. To detect truncation, we try to re-read the last block. ++ * If that does not succeed or different data than from the original read is ++ * returned, truncation is assumed. ++ * NOTE: this function must be called only if truncation is enabled AND ++ * when the previous read buffer still is valid (aka "before the next read"). ++ * It is ok to call with a 0-size buffer, which we than assume as begin of ++ * reading. In that case, no truncation will be detected. ++ * rgerhards, 2018-09-20 ++ */ ++static rsRetVal ++checkTruncation(strm_t *const pThis) ++{ ++ DEFiRet; ++ int ret; ++ off64_t backseek; ++ assert(pThis->bReopenOnTruncate); ++ ++ DBGPRINTF("checkTruncation, file %s, iBufPtrMax %zd\n", pThis->pszCurrFName, pThis->iBufPtrMax); ++ if(pThis->iBufPtrMax == 0) { ++ FINALIZE; ++ } ++ ++ int currpos = lseek64(pThis->fd, 0, SEEK_CUR); ++ backseek = -1 * (off64_t) pThis->iBufPtrMax; ++ dbgprintf("checkTruncation in actual processing, currpos %d, backseek is %d\n", (int)currpos, (int) backseek); ++ ret = lseek64(pThis->fd, backseek, SEEK_CUR); ++ if(ret < 0) { ++ iRet = rereadTruncated(pThis, "cannot seek backward to begin of last block"); ++ FINALIZE; ++ } ++ ++ const ssize_t lenRead = read(pThis->fd, pThis->pIOBuf_truncation, pThis->iBufPtrMax); ++ dbgprintf("checkTruncation proof-read: %d bytes\n", (int) lenRead); ++ if(lenRead < 0) { ++ iRet = rereadTruncated(pThis, "last block could not be re-read"); ++ FINALIZE; ++ } ++ ++ if(!memcmp(pThis->pIOBuf_truncation, pThis->pIOBuf, pThis->iBufPtrMax)) { ++ DBGPRINTF("checkTruncation, file %s last buffer unchanged\n", pThis->pszCurrFName); ++ } else { ++ iRet = rereadTruncated(pThis, "last block data different"); ++ } ++ ++finalize_it: ++ RETiRet; ++} ++ ++ + /* read the next buffer from disk + * rgerhards, 2008-02-13 + */ +@@ -668,6 +741,13 @@ strmReadBuf(strm_t *pThis, int *padBytes) + toRead = (size_t) bytesLeft; + } + } ++ if(pThis->bReopenOnTruncate) { ++ rsRetVal localRet = checkTruncation(pThis); ++ if(localRet == RS_RET_FILE_TRUNCATED) { ++ continue; ++ } ++ CHKiRet(localRet); ++ } + iLenRead = read(pThis->fd, pThis->pIOBuf, toRead); + DBGOPRINT((obj_t*) pThis, "file %d read %ld bytes\n", pThis->fd, iLenRead); + /* end crypto */ +@@ -854,7 +854,7 @@ + * a line, but following lines that are indented are part of the same log entry + */ + static rsRetVal +-strmReadLine(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF, ++strmReadLine(strm_t *const pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF, + uint32_t trimLineOverBytes, int64 *const strtOffs) + { + uchar c; +@@ -1184,6 +1264,7 @@ static rsRetVal strmConstructFinalize(strm_t *pThis) + } else { + /* we work synchronously, so we need to alloc a fixed pIOBuf */ + CHKmalloc(pThis->pIOBuf = (uchar*) MALLOC(pThis->sIOBufSize)); ++ CHKmalloc(pThis->pIOBuf_truncation = (char*) MALLOC(pThis->sIOBufSize)); + } + + finalize_it: +@@ -1231,6 +1312,7 @@ CODESTARTobjDestruct(strm) + } + } else { + free(pThis->pIOBuf); ++ free(pThis->pIOBuf_truncation); + } + + /* Finally, we can free the resources. +@@ -2147,11 +2150,22 @@ DEFpropSetMeth(strm, cryprov, cryprov_if_t*) + void + strmSetReadTimeout(strm_t *const __restrict__ pThis, const int val) + { ++ ISOBJ_TYPE_assert(pThis, strm); + pThis->readTimeout = val; + } + +-static rsRetVal strmSetbDeleteOnClose(strm_t *pThis, int val) ++void ++strmSet_checkRotation(strm_t *const pThis, const int val) { ++ ISOBJ_TYPE_assert(pThis, strm); ++ assert(val == STRM_ROTATION_DO_CHECK || val == STRM_ROTATION_DO_NOT_CHECK); ++ pThis->rotationCheck = val; ++} ++ ++ ++static rsRetVal ++strmSetbDeleteOnClose(strm_t *const pThis, const int val) + { ++ ISOBJ_TYPE_assert(pThis, strm); + pThis->bDeleteOnClose = val; + if(pThis->cryprov != NULL) { + pThis->cryprov->SetDeleteOnClose(pThis->cryprovFileData, pThis->bDeleteOnClose); +@@ -2162,15 +2176,19 @@ static rsRetVal strmSetbDeleteOnClose(strm_t *pThis, int val) + return RS_RET_OK; + } + +-static rsRetVal strmSetiMaxFiles(strm_t *pThis, int iNewVal) ++static rsRetVal ++strmSetiMaxFiles(strm_t *const pThis, const int iNewVal) + { ++ ISOBJ_TYPE_assert(pThis, strm); + pThis->iMaxFiles = iNewVal; + pThis->iFileNumDigits = getNumberDigits(iNewVal); + return RS_RET_OK; + } + +-static rsRetVal strmSetFileNotFoundError(strm_t *pThis, int pFileNotFoundError) ++static rsRetVal ++strmSetFileNotFoundError(strm_t *const pThis, const int pFileNotFoundError) + { ++ ISOBJ_TYPE_assert(pThis, strm); + pThis->fileNotFoundError = pFileNotFoundError; + return RS_RET_OK; + } +diff --git a/runtime/stream.h b/runtime/stream.h +index e3d6c2372..f6f48378a 100644 +--- a/runtime/stream.h ++++ b/runtime/stream.h +@@ -91,6 +91,10 @@ typedef enum { /* when extending, do NOT change existing modes! */ + STREAMMODE_WRITE_APPEND = 4 + } strmMode_t; + ++/* settings for stream rotation (applies not to all processing modes!) */ ++#define STRM_ROTATION_DO_CHECK 0 ++#define STRM_ROTATION_DO_NOT_CHECK 1 ++ + #define STREAM_ASYNC_NUMBUFS 2 /* must be a power of 2 -- TODO: make configurable */ + /* The strm_t data structure */ + typedef struct strm_s { +@@ -114,6 +118,7 @@ typedef struct strm_s { + sbool bDisabled; /* should file no longer be written to? (currently set only if omfile file size limit fails) */ + sbool bSync; /* sync this file after every write? */ + sbool bReopenOnTruncate; ++ int rotationCheck; /* rotation check mode */ + size_t sIOBufSize;/* size of IO buffer */ + uchar *pszDir; /* Directory */ + int lenDir; +@@ -124,6 +124,7 @@ typedef struct strm_s { + ino_t inode; /* current inode for files being monitored (undefined else) */ + uchar *pszCurrFName; /* name of current file (if open) */ + uchar *pIOBuf; /* the iobuffer currently in use to gather data */ ++ char *pIOBuf_truncation; /* iobuffer used during trucation detection block re-reads */ + size_t iBufPtrMax; /* current max Ptr in Buffer (if partial read!) */ + size_t iBufPtr; /* pointer into current buffer */ + int iUngetC; /* char set via UngetChar() call or -1 if none set */ +@@ -238,5 +238,6 @@ + const uchar * strmGetPrevLineSegment(strm_t *const pThis); + const uchar * strmGetPrevMsgSegment(strm_t *const pThis); + int strmGetPrevWasNL(const strm_t *const pThis); ++void strmSet_checkRotation(strm_t *const pThis, const int val); + + #endif /* #ifndef STREAM_H_INCLUDED */ diff --git a/SOURCES/rsyslog-8.24.0-rhbz1656860-imfile-buffer-overflow.patch b/SOURCES/rsyslog-8.24.0-rhbz1656860-imfile-buffer-overflow.patch new file mode 100644 index 0000000..f7398d3 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1656860-imfile-buffer-overflow.patch @@ -0,0 +1,40 @@ +From d5bcd5b89b2f88611e73ea193ce35178b1e89b32 Mon Sep 17 00:00:00 2001 +From: Rainer Gerhards +Date: Tue, 19 Dec 2017 10:15:46 +0100 +Subject: [PATCH] core bugfix: MAXFNAME was set too low + +it just permitted 200 chars, with almost all systems permitting for +more. I tried to find a more portable way to find out the actual max, +but this turned out horrible. The next solution would have been to use +dynamic alloc, but that often is overkill. So I now settle to just +increasing the value to 4KiB. This is the Linux limit, and it is by +far the highest I could find. This should be good to go for quite +some while but should not put too much stressure on the stack alloc. + +closes https://github.com/rsyslog/rsyslog/issues/2228 +--- + runtime/syslogd-types.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/runtime/syslogd-types.h b/runtime/syslogd-types.h +index 2cbe8039a..360f6d557 100644 +--- a/runtime/syslogd-types.h ++++ b/runtime/syslogd-types.h +@@ -4,7 +4,7 @@ + * + * File begun on 2007-07-13 by RGerhards (extracted from syslogd.c) + * +- * Copyright 2007-2014 Adiscon GmbH. ++ * Copyright 2007-2017 Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * +@@ -38,7 +38,7 @@ + # define UNAMESZ 8 /* length of a login name */ + #endif + #define MAXUNAMES 20 /* maximum number of user names */ +-#define MAXFNAME 200 /* max file pathname length */ ++#define MAXFNAME 4096 /* max file pathname length */ + + #define _DB_MAXDBLEN 128 /* maximum number of db */ + #define _DB_MAXUNAMELEN 128 /* maximum number of user name */ diff --git a/SOURCES/rsyslog-8.24.0-rhbz1658288-imptcp-octet-segfault.patch b/SOURCES/rsyslog-8.24.0-rhbz1658288-imptcp-octet-segfault.patch new file mode 100644 index 0000000..cbccd21 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1658288-imptcp-octet-segfault.patch @@ -0,0 +1,50 @@ +From 0381a0de64a5a048c3d48b79055bd9848d0c7fc2 Mon Sep 17 00:00:00 2001 +From: PascalWithopf +Date: Wed, 19 Apr 2017 13:06:30 +0200 +Subject: [PATCH] imptcp: fix Segmentation Fault when octet count is to high + +--- + plugins/imptcp/imptcp.c | 14 ++++++- + 1 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c +index acf0dcd25..b9a4e2fdf 100644 +--- a/plugins/imptcp/imptcp.c ++++ b/plugins/imptcp/imptcp.c +@@ -902,7 +902,16 @@ processDataRcvd(ptcpsess_t *const __restrict__ pThis, + + if(pThis->inputState == eInOctetCnt) { + if(isdigit(c)) { +- pThis->iOctetsRemain = pThis->iOctetsRemain * 10 + c - '0'; ++ if(pThis->iOctetsRemain <= 200000000) { ++ pThis->iOctetsRemain = pThis->iOctetsRemain * 10 + c - '0'; ++ } else { ++ errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: " ++ "frame too large (at least %d%c), change to octet stuffing", ++ pThis->iOctetsRemain, c); ++ pThis->eFraming = TCP_FRAMING_OCTET_STUFFING; ++ pThis->inputState = eInMsg; ++ } ++ *(pThis->pMsg + pThis->iMsg++) = c; + } else { /* done with the octet count, so this must be the SP terminator */ + DBGPRINTF("TCP Message with octet-counter, size %d.\n", pThis->iOctetsRemain); + if(c != ' ') { +@@ -911,9 +920,9 @@ processDataRcvd(ptcpsess_t *const __restrict__ pThis, + } + if(pThis->iOctetsRemain < 1) { + /* TODO: handle the case where the octet count is 0! */ +- DBGPRINTF("Framing Error: invalid octet count\n"); + errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: " + "invalid octet count %d.", pThis->iOctetsRemain); ++ pThis->eFraming = TCP_FRAMING_OCTET_STUFFING; + } else if(pThis->iOctetsRemain > iMaxLine) { + /* while we can not do anything against it, we can at least log an indication + * that something went wrong) -- rgerhards, 2008-03-14 +@@ -924,6 +933,7 @@ processDataRcvd(ptcpsess_t *const __restrict__ pThis, + "max msg size is %d, truncating...", pThis->iOctetsRemain, iMaxLine); + } + pThis->inputState = eInMsg; ++ pThis->iMsg = 0; + } + } else { + assert(pThis->inputState == eInMsg); diff --git a/SOURCES/rsyslog-8.24.0-rhbz1666365-internal-messages-memory-leak.patch b/SOURCES/rsyslog-8.24.0-rhbz1666365-internal-messages-memory-leak.patch new file mode 100644 index 0000000..51ef1d2 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1666365-internal-messages-memory-leak.patch @@ -0,0 +1,39 @@ +From 890e3bb0d83719350ace0ee00b1d2d471333778d Mon Sep 17 00:00:00 2001 +From: Rainer Gerhards +Date: Wed, 10 May 2017 11:46:45 +0200 +Subject: [PATCH] core bugfix: memory leak when internal messages not processed + internally + +In this case, the message object is not destructed, resulting in +a memory leak. Usually, this is no problem due to the low number +of internal message, but it can become an issue if a large number +of messages is emitted. + +closes https://github.com/rsyslog/rsyslog/issues/1548 +closes https://github.com/rsyslog/rsyslog/issues/1531 +--- + tools/rsyslogd.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tools/rsyslogd.c b/tools/rsyslogd.c +index 417804e18..d2e5361a6 100644 +--- a/tools/rsyslogd.c ++++ b/tools/rsyslogd.c +@@ -840,7 +840,7 @@ submitMsgWithDfltRatelimiter(smsg_t *pMsg) + + + static void +-logmsgInternal_doWrite(smsg_t *const __restrict__ pMsg) ++logmsgInternal_doWrite(smsg_t *pMsg) + { + if(bProcessInternalMessages) { + ratelimitAddMsg(internalMsg_ratelimiter, NULL, pMsg); +@@ -852,6 +852,8 @@ logmsgInternal_doWrite(smsg_t *const __restrict__ pMsg) + # else + syslog(pri, "%s", msg); + # endif ++ /* we have emitted the message and must destruct it */ ++ msgDestruct(&pMsg); + } + } + diff --git a/SOURCES/rsyslog-8.24.0-rhbz1685901-symlink-error-flood.patch b/SOURCES/rsyslog-8.24.0-rhbz1685901-symlink-error-flood.patch new file mode 100644 index 0000000..2b658fb --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1685901-symlink-error-flood.patch @@ -0,0 +1,25 @@ +From 31350bc0b935920f9924317b4cb3602602420f83 Mon Sep 17 00:00:00 2001 +From: Jiri Vymazal +Date: Fri, 16 Nov 2018 13:16:13 +0100 +Subject: [PATCH] disable file vs directory error on symlinks + +The file/directory node-object alignment now ignores symlinks. +Previously it reported error on each directory symlink spamming +user error logs. +--- + plugins/imfile/imfile.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c +index f42670ca2..1618d151c 100644 +--- a/plugins/imfile/imfile.c ++++ b/plugins/imfile/imfile.c +@@ -869,7 +869,7 @@ poll_tree(fs_edge_t *const chld) + "directory - ignored", file); + continue; + } +- if(chld->is_file != is_file) { ++ if(!issymlink && (chld->is_file != is_file)) { + LogMsg(0, RS_RET_ERR, LOG_WARNING, + "imfile: '%s' is %s but %s expected - ignored", + file, (is_file) ? "FILE" : "DIRECTORY", diff --git a/SPECS/rsyslog.spec b/SPECS/rsyslog.spec index 7f5f89e..03afdba 100644 --- a/SPECS/rsyslog.spec +++ b/SPECS/rsyslog.spec @@ -14,7 +14,7 @@ Summary: Enhanced system logging and kernel message trapping daemon Name: rsyslog Version: 8.24.0 -Release: 34%{?dist} +Release: 38%{?dist} License: (GPLv3+ and ASL 2.0) Group: System Environment/Daemons URL: http://www.rsyslog.com/ @@ -104,6 +104,16 @@ Patch42: rsyslog-8.24.0-rhbz1597264-man-page-fix.patch Patch43: rsyslog-8.24.0-rhbz1559408-async-writer.patch Patch44: rsyslog-8.24.0-rhbz1600462-wrktable-realloc-null.patch +Patch45: rsyslog-8.24.0-rhbz1632659-omfwd-mem-corruption.patch +Patch46: rsyslog-8.24.0-rhbz1649250-imfile-rotation.patch +Patch47: rsyslog-8.24.0-rhbz1658288-imptcp-octet-segfault.patch +Patch48: rsyslog-8.24.0-rhbz1622767-mmkubernetes-stop-on-pod-delete.patch +Patch49: rsyslog-8.24.0-rhbz1685901-symlink-error-flood.patch +Patch50: rsyslog-8.24.0-rhbz1632211-journal-cursor-fix.patch +Patch51: rsyslog-8.24.0-rhbz1666365-internal-messages-memory-leak.patch +Patch52: rsyslog-8.24.0-doc-rhbz1625935-mmkubernetes-CRI-O.patch +Patch53: rsyslog-8.24.0-rhbz1656860-imfile-buffer-overflow.patch + %package crypto Summary: Encryption support Group: System Environment/Daemons @@ -333,6 +343,7 @@ container metadata. %patch37 -p1 %patch40 -p1 %patch41 -p1 +%patch52 -p1 #regenerate the docs mv build/searchindex.js searchindex_backup.js sphinx-build -b html source build @@ -396,6 +407,16 @@ mv build doc %patch43 -p1 -b .async-writer %patch44 -p1 -b .null-realloc-chk +%patch45 -p1 -b .omfwd-mem-corrupt +%patch46 -p1 -b .imfile-rotation +%patch47 -p1 -b .imptcp-octet-count +%patch48 -p1 -b .mmkubernetes-stop +%patch49 -p1 -b .symlink-err-flood +%patch50 -p1 -b .imjournal-cursor +%patch51 -p1 -b .internal-msg-memleak +#%patch52 is applied right after doc setup +%patch53 -p1 -b .imfile-buffer-overflow + autoreconf %build @@ -654,6 +675,40 @@ done %{_libdir}/rsyslog/mmkubernetes.so %changelog +* Mon Apr 08 2019 Jiri Vymazal - 8.24.0-38 +RHEL 7.7 ERRATUM +- added patch increasing max path size preventing buffer overflow + with too long paths + resolves: rhbz#1656860 + +* Wed Mar 20 2019 Jiri Vymazal - 8.24.0-37 +RHEL 7.7 ERRATUM +- edited patch fixing mmkubernetes halt after pod deletition + (covscan found an issue in previous version) + resolves: rhbz#1622767 +- added patch stopping flooding logs with journald errors + resolves: rhbz#1632211 +- added patch stopping flooding logs with symlink false-positives + resolves: rhbz#1685901 +- added patch stopping memory leak when processing internal msgs + resolves: rhbz#1666365 +- added documentation patch with info about CRI-O to mmkubernetes + resolves: rhbz#1625935 + +* Wed Feb 27 2019 Jiri Vymazal - 8.24.0-36 +RHEL 7.7 ERRATUM +- added patch fixing mmkubernetes halt after pod deletition + resolves: rhbz#1622767 + +* Mon Jan 28 2019 Jiri Vymazal - 8.24.0-35 +RHEL 7.7 ERRATUM +- added patch fixing memory corruption in omfwd module + resolves: rhbz#1632659 +- added patch fixing imfile sopping monitor after rotation + resolves: rhbz#1649250 +- added patch addressing imptcp CVE-2018-16881 + resolves: rhbz#1658288 + * Tue Aug 07 2018 Jiri Vymazal - 8.24.0-34 RHEL 7.6 ERRATUM - updated imfile rewrite patch with parent name bugfix