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 <rmeggins@redhat.com>
+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 <rmeggins@redhat.com>
+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 <jvymazal@redhat.com>
+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 <rgerhards@adiscon.com>
+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 <jvymazal@redhat.com>
+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 <rgerhards@adiscon.com>
+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 <pwithopf@adiscon.com>
+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 <rgerhards@adiscon.com>
+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 <jvymazal@redhat.com>
+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 <jvymazal@redhat.com> - 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 <jvymazal@redhat.com> - 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 <jvymazal@redhat.com> - 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 <jvymazal@redhat.com> - 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 <jvymazal@redhat.com> - 8.24.0-34
 RHEL 7.6 ERRATUM
 - updated imfile rewrite patch with parent name bugfix