From ff08e8bb0f57b85b55cdc129d7659e7e81177491 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mar 31 2020 09:32:37 +0000 Subject: import rsyslog-8.24.0-52.el7 --- diff --git a/SOURCES/rsyslog-8.24.0-doc-rhbz1309698-imudp-case-sensitive-option.patch b/SOURCES/rsyslog-8.24.0-doc-rhbz1309698-imudp-case-sensitive-option.patch new file mode 100644 index 0000000..58f4b57 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-doc-rhbz1309698-imudp-case-sensitive-option.patch @@ -0,0 +1,64 @@ +From 27eda7938d678bc69b46cfcb8351e871161ba526 Mon Sep 17 00:00:00 2001 +From: Noriko Hosoi +Date: Fri, 13 Jul 2018 10:44:13 -0700 +Subject: [PATCH] Introducing an option preservecase to imudp and imtcp module + for managing the case of FROMHOST value. + +Usage: + module(load="imudp" [preservecase="on"|"off"]) + module(load="imtdp" [preservecase="on"|"off"]) + +If preservecase="on", FROMHOST value is handled in the case sensitive manner. +If preservecase="off", FROMHOST value is handled in the case insensitive manner. + +To maintain the current behaviour, the default value of preservecase is +"on" for imtcp and "off" for imudp. + +References: + https://github.com/rsyslog/rsyslog/pull/2774 + https://bugzilla.redhat.com/show_bug.cgi?id=1309698 +--- + source/configuration/modules/imtcp.rst | 9 +++++++++ + source/configuration/modules/imudp.rst | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/source/configuration/modules/imtcp.rst b/source/configuration/modules/imtcp.rst +index 2ddb7e9a..b9fe0adb 100644 +--- a/source/configuration/modules/imtcp.rst ++++ b/source/configuration/modules/imtcp.rst +@@ -138,6 +138,15 @@ + Array of peers: + PermittedPeer=["test1.example.net","10.1.2.3","test2.example.net","..."] + ++.. function:: PreserveCase ++ ++ *Default: off* ++ ++ This parameter is for controlling the case in fromhost. If set to "on", ++ the case in fromhost is preserved. E.g., 'Host1.Example.Org' when the ++ message was received from 'Host1.Example.Org'. Defaults to "off" for ++ backwards compatibility. ++ + Input Parameters + ^^^^^^^^^^^^^^^^ + +diff --git a/source/configuration/modules/imudp.rst b/source/configuration/modules/imudp.rst +index 487853f6..b92f0810 100644 +--- a/source/configuration/modules/imudp.rst ++++ b/source/configuration/modules/imudp.rst +@@ -97,6 +97,15 @@ + set to 32. It may increase in the future when massive multicore + processors become available. + ++.. function:: PreserveCase ++ ++ *Default: off* ++ ++ This parameter is for controlling the case in fromhost. If set to "on", ++ the case in fromhost is preserved. E.g., 'Host1.Example.Org' when the ++ message was received from 'Host1.Example.Org'. Defaults to "off" for ++ backwards compatibility. ++ + .. index:: imudp; input parameters + + Input Parameters diff --git a/SOURCES/rsyslog-8.24.0-doc-rhbz1696686-imjournal-fsync.patch b/SOURCES/rsyslog-8.24.0-doc-rhbz1696686-imjournal-fsync.patch new file mode 100644 index 0000000..ef68b32 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-doc-rhbz1696686-imjournal-fsync.patch @@ -0,0 +1,41 @@ +From 3ba46e563a3a5384fd6d783a8315273c237cb6af Mon Sep 17 00:00:00 2001 +From: Jiri Vymazal +Date: Tue, 23 Jul 2019 12:47:09 +0200 +Subject: [PATCH] Documetation for new 'fsync' imjournal option + +related to #3762 main repo PR +--- + source/configuration/modules/imjournal.rst | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletitions (-) + +diff --git a/source/configuration/modules/imjournal.rst b/source/configuration/modules/imjournal.rst +index d8523ae8..47428fc6 100644 +--- a/source/configuration/modules/imjournal.rst ++++ b/source/configuration/modules/imjournal.rst +@@ -3,8 +3,7 @@ + + **Module Name:** imjournal + +-**Author:** Milan Bartos (This module is **not** +-project-supported) ++**Author:** Milan Bartos + + **Available since**: 7.3.11 + +@@ -107,6 +106,16 @@ + with each message to work around this problem. Be aware that in some cases this + might result in imjournal performance hit. + ++- **FSync** [**off**/on] ++ ++ When there is a hard crash, power loss or similar abrupt end of rsyslog process, ++ there is a risk of state file not being written to persistent storage or possibly ++ being corrupted. This then results in imjournal starting reading elsewhere then ++ desired and most probably message duplication. To mitigate this problem you can ++ turn this option on which will force state file writes to persistent physical ++ storage. Please note that fsync calls are costly, so especially with lower ++ PersistStateInterval value, this may present considerable performance hit. ++ + **Caveats/Known Bugs:** + + - As stated above, a corrupted systemd journal database can cause major diff --git a/SOURCES/rsyslog-8.24.0-rhbz1309698-imudp-case-sensitive-option.patch b/SOURCES/rsyslog-8.24.0-rhbz1309698-imudp-case-sensitive-option.patch new file mode 100644 index 0000000..900ce2f --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1309698-imudp-case-sensitive-option.patch @@ -0,0 +1,285 @@ +From 9ac54f0d7d70b8a9879889b4522a1d552fca1100 Mon Sep 17 00:00:00 2001 +From: Noriko Hosoi +Date: Thu, 12 Jul 2018 11:52:04 -0700 +Subject: [PATCH] Introducing an option preservecase to imudp and imtcp module + for managing the case of FROMHOST value. + +Usage: +module(load="imudp" [preservecase="on"|"off"]) +module(load="imtdp" [preservecase="on"|"off"]) + +If preservecase="on", FROMHOST value is handled in the case sensitive manner. +If preservecase="off", FROMHOST value is handled in the case insensitive manner. + +To maintain the current behaviour, the default value of preservecase is +"on" for imtcp and "off" for imudp. + +Incremented tcpsrvCURR_IF_VERSION by 1. + +References: +https://github.com/rsyslog/rsyslog/pull/2774 +https://bugzilla.redhat.com/show_bug.cgi?id=1309698 +--- + plugins/imtcp/imtcp.c | 14 ++++++++++++-- + plugins/imudp/imudp.c | 15 ++++++++++++--- + runtime/msg.c | 6 +++++- + runtime/msg.h | 2 ++ + runtime/net.c | 2 +- + runtime/tcpsrv.c | 21 +++++++++++++++++++++ + runtime/tcpsrv.h | 5 ++++- + 7 files changed, 57 insertions(+), 8 deletions(-) + +diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c +index 8e3dcc0a21..45fa240b59 100644 +--- a/plugins/imtcp/imtcp.c ++++ b/plugins/imtcp/imtcp.c +@@ -100,6 +100,7 @@ static struct configSettings_s { + int iAddtlFrameDelim; + int bDisableLFDelim; + int bUseFlowControl; ++ int bPreserveCase; + uchar *pszStrmDrvrAuthMode; + uchar *pszInputName; + uchar *pszBindRuleset; +@@ -144,6 +145,7 @@ struct modConfData_s { + uchar *pszStrmDrvrAuthMode; /* authentication mode to use */ + struct cnfarray *permittedPeers; + sbool configSetViaV2Method; ++ sbool bPreserveCase; /* preserve case of fromhost; true by default */ + }; + + static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ +@@ -169,7 +171,8 @@ static struct cnfparamdescr modpdescr[] = { + { "keepalive", eCmdHdlrBinary, 0 }, + { "keepalive.probes", eCmdHdlrPositiveInt, 0 }, + { "keepalive.time", eCmdHdlrPositiveInt, 0 }, +- { "keepalive.interval", eCmdHdlrPositiveInt, 0 } ++ { "keepalive.interval", eCmdHdlrPositiveInt, 0 }, ++ { "preservecase", eCmdHdlrBinary, 0 } + }; + static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, +@@ -375,6 +378,7 @@ addListner(modConfData_t *modConf, instanceConf_t *inst) + if(pPermPeersRoot != NULL) { + CHKiRet(tcpsrv.SetDrvrPermPeers(pOurTcpsrv, pPermPeersRoot)); + } ++ CHKiRet(tcpsrv.SetPreserveCase(pOurTcpsrv, modConf->bPreserveCase)); + } + + /* initialized, now add socket and listener params */ +@@ -473,6 +477,7 @@ CODESTARTbeginCnfLoad + loadModConf->pszStrmDrvrAuthMode = NULL; + loadModConf->permittedPeers = NULL; + loadModConf->configSetViaV2Method = 0; ++ loadModConf->bPreserveCase = 1; /* default to true */ + bLegacyCnfModGlobalsPermitted = 1; + /* init legacy config variables */ + cs.pszStrmDrvrAuthMode = NULL; +@@ -543,6 +548,8 @@ CODESTARTsetModCnf + loadModConf->pszStrmDrvrName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(modpblk.descr[i].name, "permittedpeer")) { + loadModConf->permittedPeers = cnfarrayDup(pvals[i].val.d.ar); ++ } else if(!strcmp(modpblk.descr[i].name, "preservecase")) { ++ loadModConf->bPreserveCase = (int) pvals[i].val.d.n; + } else { + dbgprintf("imtcp: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); +@@ -584,6 +591,7 @@ CODESTARTendCnfLoad + loadModConf->pszStrmDrvrAuthMode = cs.pszStrmDrvrAuthMode; + cs.pszStrmDrvrAuthMode = NULL; + } ++ pModConf->bPreserveCase = cs.bPreserveCase; + } + free(cs.pszStrmDrvrAuthMode); + cs.pszStrmDrvrAuthMode = NULL; +@@ -731,6 +739,7 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus + cs.pszInputName = NULL; + free(cs.pszStrmDrvrAuthMode); + cs.pszStrmDrvrAuthMode = NULL; ++ cs.bPreserveCase = 1; + return RS_RET_OK; + } + +@@ -797,7 +806,8 @@ CODEmodInit_QueryRegCFSLineHdlr + NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserverstreamdrivermode"), 0, eCmdHdlrInt, + NULL, &cs.iStrmDrvrMode, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); +- ++ CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserverpreservecase"), 1, eCmdHdlrBinary, ++ NULL, &cs.bPreserveCase, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler, + resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); + ENDmodInit +diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c +index 51a9d712a0..74437781ca 100644 +--- a/plugins/imudp/imudp.c ++++ b/plugins/imudp/imudp.c +@@ -152,6 +152,7 @@ struct modConfData_s { + int batchSize; /* max nbr of input batch --> also recvmmsg() max count */ + int8_t wrkrMax; /* max nbr of worker threads */ + sbool configSetViaV2Method; ++ sbool bPreserveCase; /* preserves the case of fromhost; "off" by default */ + }; + static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ + static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +@@ -162,7 +163,8 @@ static struct cnfparamdescr modpdescr[] = { + { "schedulingpriority", eCmdHdlrInt, 0 }, + { "batchsize", eCmdHdlrInt, 0 }, + { "threads", eCmdHdlrPositiveInt, 0 }, +- { "timerequery", eCmdHdlrInt, 0 } ++ { "timerequery", eCmdHdlrInt, 0 }, ++ { "preservecase", eCmdHdlrBinary, 0 } + }; + static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, +@@ -447,8 +449,12 @@ processPacket(struct lstn_s *lstn, struct sockaddr_storage *frominetPrev, int *p + if(lstn->dfltTZ != NULL) + MsgSetDfltTZ(pMsg, (char*) lstn->dfltTZ); + pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME | NEEDS_DNSRESOL; +- if(*pbIsPermitted == 2) +- pMsg->msgFlags |= NEEDS_ACLCHK_U; /* request ACL check after resolution */ ++ if(*pbIsPermitted == 2) { ++ pMsg->msgFlags |= NEEDS_ACLCHK_U; /* request ACL check after resolution */ ++ } ++ if(runModConf->bPreserveCase) { ++ pMsg->msgFlags |= PRESERVE_CASE; /* preserve case of fromhost */ ++ } + CHKiRet(msgSetFromSockinfo(pMsg, frominet)); + CHKiRet(ratelimitAddMsg(lstn->ratelimiter, multiSub, pMsg)); + STATSCOUNTER_INC(lstn->ctrSubmit, lstn->mutCtrSubmit); +@@ -1030,6 +1036,7 @@ CODESTARTbeginCnfLoad + loadModConf->iTimeRequery = TIME_REQUERY_DFLT; + loadModConf->iSchedPrio = SCHED_PRIO_UNSET; + loadModConf->pszSchedPolicy = NULL; ++ loadModConf->bPreserveCase = 0; /* off */ + bLegacyCnfModGlobalsPermitted = 1; + /* init legacy config vars */ + cs.pszBindRuleset = NULL; +@@ -1079,6 +1086,8 @@ CODESTARTsetModCnf + } else { + loadModConf->wrkrMax = wrkrMax; + } ++ } else if(!strcmp(modpblk.descr[i].name, "preservecase")) { ++ loadModConf->bPreserveCase = (int) pvals[i].val.d.n; + } else { + dbgprintf("imudp: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); +diff --git a/runtime/msg.c b/runtime/msg.c +index c43f813142..9ed4eaf84d 100644 +--- a/runtime/msg.c ++++ b/runtime/msg.c +@@ -506,7 +506,11 @@ resolveDNS(smsg_t * const pMsg) { + MsgLock(pMsg); + CHKiRet(objUse(net, CORE_COMPONENT)); + if(pMsg->msgFlags & NEEDS_DNSRESOL) { +- localRet = net.cvthname(pMsg->rcvFrom.pfrominet, &localName, NULL, &ip); ++ if (pMsg->msgFlags & PRESERVE_CASE) { ++ localRet = net.cvthname(pMsg->rcvFrom.pfrominet, NULL, &localName, &ip); ++ } else { ++ localRet = net.cvthname(pMsg->rcvFrom.pfrominet, &localName, NULL, &ip); ++ } + if(localRet == RS_RET_OK) { + /* we pass down the props, so no need for AddRef */ + MsgSetRcvFromWithoutAddRef(pMsg, localName); +diff --git a/runtime/msg.h b/runtime/msg.h +index cd530aca38..1287cb7a4b 100644 +--- a/runtime/msg.h ++++ b/runtime/msg.h +@@ -144,6 +144,7 @@ struct msg { + #define NEEDS_DNSRESOL 0x040 /* fromhost address is unresolved and must be locked up via DNS reverse lookup first */ + #define NEEDS_ACLCHK_U 0x080 /* check UDP ACLs after DNS resolution has been done in main queue consumer */ + #define NO_PRI_IN_RAW 0x100 /* rawmsg does not include a PRI (Solaris!), but PRI is already set correctly in the msg object */ ++#define PRESERVE_CASE 0x200 /* preserve case in fromhost */ + + /* (syslog) protocol types */ + #define MSG_LEGACY_PROTOCOL 0 +diff --git a/runtime/net.c b/runtime/net.c +index d6ff8a3d4d..aef906601c 100644 +--- a/runtime/net.c ++++ b/runtime/net.c +@@ -1152,7 +1152,7 @@ cvthname(struct sockaddr_storage *f, prop_t **localName, prop_t **fqdn, prop_t * + { + DEFiRet; + assert(f != NULL); +- iRet = dnscacheLookup(f, NULL, fqdn, localName, ip); ++ iRet = dnscacheLookup(f, fqdn, NULL, localName, ip); + RETiRet; + } + +diff --git a/runtime/tcpsrv.c b/runtime/tcpsrv.c +index 61e9ff4d22..d5993b4f00 100644 +--- a/runtime/tcpsrv.c ++++ b/runtime/tcpsrv.c +@@ -495,6 +495,15 @@ SessAccept(tcpsrv_t *pThis, tcpLstnPortList_t *pLstnInfo, tcps_sess_t **ppSess, + + /* get the host name */ + CHKiRet(netstrm.GetRemoteHName(pNewStrm, &fromHostFQDN)); ++ if (!pThis->bPreserveCase) { ++ /* preserve_case = off */ ++ uchar *p; ++ for(p = fromHostFQDN; *p; p++) { ++ if (isupper((int) *p)) { ++ *p = tolower((int) *p); ++ } ++ } ++ } + CHKiRet(netstrm.GetRemoteIP(pNewStrm, &fromHostIP)); + CHKiRet(netstrm.GetRemAddr(pNewStrm, &addr)); + /* TODO: check if we need to strip the domain name here -- rgerhards, 2008-04-24 */ +@@ -1001,6 +1010,7 @@ BEGINobjConstruct(tcpsrv) /* be sure to specify the object type also in END macr + pThis->ratelimitBurst = 10000; + pThis->bUseFlowControl = 1; + pThis->pszDrvrName = NULL; ++ pThis->bPreserveCase = 1; /* preserve case in fromhost; default to true. */ + ENDobjConstruct(tcpsrv) + + +@@ -1433,6 +1443,16 @@ SetSessMax(tcpsrv_t *pThis, int iMax) + } + + ++static rsRetVal ++SetPreserveCase(tcpsrv_t *pThis, int bPreserveCase) ++{ ++ DEFiRet; ++ ISOBJ_TYPE_assert(pThis, tcpsrv); ++ pThis-> bPreserveCase = bPreserveCase; ++ RETiRet; ++} ++ ++ + /* queryInterface function + * rgerhards, 2008-02-29 + */ +@@ -1491,6 +1511,7 @@ CODESTARTobjQueryInterface(tcpsrv) + pIf->SetRuleset = SetRuleset; + pIf->SetLinuxLikeRatelimiters = SetLinuxLikeRatelimiters; + pIf->SetNotificationOnRemoteClose = SetNotificationOnRemoteClose; ++ pIf->SetPreserveCase = SetPreserveCase; + + finalize_it: + ENDobjQueryInterface(tcpsrv) +diff --git a/runtime/tcpsrv.h b/runtime/tcpsrv.h +index 22a65c20a0..f17b1b4384 100644 +--- a/runtime/tcpsrv.h ++++ b/runtime/tcpsrv.h +@@ -81,6 +81,7 @@ struct tcpsrv_s { + + int addtlFrameDelim; /**< additional frame delimiter for plain TCP syslog framing (e.g. to handle NetScreen) */ + int bDisableLFDelim; /**< if 1, standard LF frame delimiter is disabled (*very dangerous*) */ ++ sbool bPreserveCase; /**< preserve case in fromhost */ + int ratelimitInterval; + int ratelimitBurst; + tcps_sess_t **pSessions;/**< array of all of our sessions */ +@@ -168,8 +169,10 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */ + rsRetVal (*SetKeepAliveTime)(tcpsrv_t*, int); + /* added v18 */ + rsRetVal (*SetbSPFramingFix)(tcpsrv_t*, sbool); ++ /* added v21 -- Preserve case in fromhost, 2018-08-16 */ ++ rsRetVal (*SetPreserveCase)(tcpsrv_t *pThis, int bPreserveCase); + ENDinterface(tcpsrv) +-#define tcpsrvCURR_IF_VERSION 18 /* increment whenever you change the interface structure! */ ++#define tcpsrvCURR_IF_VERSION 21 /* increment whenever you change the interface structure! */ + /* change for v4: + * - SetAddtlFrameDelim() added -- rgerhards, 2008-12-10 + * - SetInputName() added -- rgerhards, 2008-12-10 diff --git a/SOURCES/rsyslog-8.24.0-rhbz1549706-corrupt-property-crash.patch b/SOURCES/rsyslog-8.24.0-rhbz1549706-corrupt-property-crash.patch new file mode 100644 index 0000000..5e5f488 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1549706-corrupt-property-crash.patch @@ -0,0 +1,29 @@ +From 3a93e5e377cad7acd241f0f93de625657fada25c Mon Sep 17 00:00:00 2001 +From: Derek Smith +Date: Wed, 21 Jun 2017 13:32:02 +0100 +Subject: [PATCH] type should be set back to VARTYPE_NONE incase we assigned a + property type of VARTYPE_STRING while failing to grab the length value + +--- + runtime/obj.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/runtime/obj.c b/runtime/obj.c +index 2186727ae6..771e5c16a7 100644 +--- a/runtime/obj.c ++++ b/runtime/obj.c +@@ -664,6 +664,14 @@ rsRetVal objDeserializeProperty(var_t *pProp, strm_t *pStrm) + if(c != '\n') ABORT_FINALIZE(RS_RET_INVALID_PROPFRAME); + + finalize_it: ++ /* ensure the type of var is reset back to VARTYPE_NONE since ++ * the deconstruct method of var might free unallocated memory ++ */ ++ if(iRet != RS_RET_OK && iRet != RS_RET_NO_PROPLINE) { ++ if(step <= 2) { ++ pProp->varType = VARTYPE_NONE; ++ } ++ } + if(Debug && iRet != RS_RET_OK && iRet != RS_RET_NO_PROPLINE) { + strm.GetCurrOffset(pStrm, &offs); + dbgprintf("error %d deserializing property name, offset %lld, step %d\n", diff --git a/SOURCES/rsyslog-8.24.0-rhbz1600171-omelastic-ES6.patch b/SOURCES/rsyslog-8.24.0-rhbz1600171-omelastic-ES6.patch new file mode 100644 index 0000000..4948349 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1600171-omelastic-ES6.patch @@ -0,0 +1,34 @@ +From 8aca362e812827501f0545f4abea140f89fa87e3 Mon Sep 17 00:00:00 2001 +From: Rich Megginson +Date: Mon, 16 Jul 2018 15:55:35 -0600 +Subject: [PATCH] Bug 1600171 - Rsyslog omelasticsearch does not work with ES + 6.x strict headers + +https://bugzilla.redhat.com/show_bug.cgi?id=1600171 +I did not attempt to backport all of the commits that +touched this particular code, just the code that uses +the macro for the content type. +--- + plugins/omelasticsearch/omelasticsearch.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/plugins/omelasticsearch/omelasticsearch.c b/plugins/omelasticsearch/omelasticsearch.c +index 248a369d2..feb6425f7 100644 +--- a/plugins/omelasticsearch/omelasticsearch.c ++++ b/plugins/omelasticsearch/omelasticsearch.c +@@ -1607,10 +1607,11 @@ curlPostSetup(CURL *handle, HEADER *header, uchar* authBuf, wrkrInstanceData_t * + curl_easy_setopt(handle, CURLOPT_SSLKEY, pWrkrData->pData->myPrivKeyFile); + } + ++#define CONTENT_JSON "Content-Type: application/json; charset=utf-8" + static rsRetVal + curlSetup(wrkrInstanceData_t *pWrkrData, instanceData *pData) + { +- pWrkrData->curlHeader = curl_slist_append(NULL, "Content-Type: text/json; charset=utf-8"); ++ pWrkrData->curlHeader = curl_slist_append(NULL, CONTENT_JSON); + pWrkrData->curlPostHandle = curl_easy_init(); + if (pWrkrData->curlPostHandle == NULL) { + return RS_RET_OBJ_CREATION_FAILED; +-- +2.17.1 + diff --git a/SOURCES/rsyslog-8.24.0-rhbz1627799-cert-chains.patch b/SOURCES/rsyslog-8.24.0-rhbz1627799-cert-chains.patch new file mode 100644 index 0000000..b90850e --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1627799-cert-chains.patch @@ -0,0 +1,622 @@ +diff -up rsyslog-8.24.0/plugins/imtcp/imtcp.c.v36tls rsyslog-8.24.0/plugins/imtcp/imtcp.c +--- rsyslog-8.24.0/plugins/imtcp/imtcp.c.v36tls 2019-08-19 17:37:07.872166694 +0100 ++++ rsyslog-8.24.0/plugins/imtcp/imtcp.c 2019-08-19 17:37:07.876166693 +0100 +@@ -100,6 +100,7 @@ static struct configSettings_s { + int bDisableLFDelim; + int bUseFlowControl; + int bPreserveCase; ++ uchar *gnutlsPriorityString; + uchar *pszStrmDrvrAuthMode; + uchar *pszInputName; + uchar *pszBindRuleset; +@@ -136,6 +137,7 @@ struct modConfData_s { + int iKeepAliveProbes; + int iKeepAliveTime; + sbool bEmitMsgOnClose; /* emit an informational message on close by remote peer */ ++ uchar *gnutlsPriorityString; + uchar *pszStrmDrvrName; /* stream driver to use */ + uchar *pszStrmDrvrAuthMode; /* authentication mode to use */ + struct cnfarray *permittedPeers; +@@ -164,7 +166,8 @@ static struct cnfparamdescr modpdescr[] + { "keepalive.probes", eCmdHdlrPositiveInt, 0 }, + { "keepalive.time", eCmdHdlrPositiveInt, 0 }, + { "keepalive.interval", eCmdHdlrPositiveInt, 0 }, +- { "preservecase", eCmdHdlrBinary, 0 } ++ { "preservecase", eCmdHdlrBinary, 0 }, ++ { "gnutlsprioritystring", eCmdHdlrString, 0 } + }; + static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, +@@ -354,6 +357,7 @@ addListner(modConfData_t *modConf, insta + CHKiRet(tcpsrv.SetKeepAliveIntvl(pOurTcpsrv, modConf->iKeepAliveIntvl)); + CHKiRet(tcpsrv.SetKeepAliveProbes(pOurTcpsrv, modConf->iKeepAliveProbes)); + CHKiRet(tcpsrv.SetKeepAliveTime(pOurTcpsrv, modConf->iKeepAliveTime)); ++ CHKiRet(tcpsrv.SetGnutlsPriorityString(pOurTcpsrv, modConf->gnutlsPriorityString)); + CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, modConf->iTCPSessMax)); + CHKiRet(tcpsrv.SetLstnMax(pOurTcpsrv, modConf->iTCPLstnMax)); + CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, modConf->iStrmDrvrMode)); +@@ -463,6 +467,7 @@ CODESTARTbeginCnfLoad + loadModConf->bEmitMsgOnClose = 0; + loadModConf->iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; + loadModConf->bDisableLFDelim = 0; ++ loadModConf->gnutlsPriorityString = NULL; + loadModConf->pszStrmDrvrName = NULL; + loadModConf->pszStrmDrvrAuthMode = NULL; + loadModConf->permittedPeers = NULL; +@@ -517,6 +522,8 @@ CODESTARTsetModCnf + loadModConf->iKeepAliveTime = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "keepalive.interval")) { + loadModConf->iKeepAliveIntvl = (int) pvals[i].val.d.n; ++ } else if(!strcmp(modpblk.descr[i].name, "gnutlsprioritystring")) { ++ loadModConf->gnutlsPriorityString = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(modpblk.descr[i].name, "streamdriver.mode")) { + loadModConf->iStrmDrvrMode = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "streamdriver.authmode")) { +diff -up rsyslog-8.24.0/runtime/netstrm.c.v36tls rsyslog-8.24.0/runtime/netstrm.c +--- rsyslog-8.24.0/runtime/netstrm.c.v36tls 2017-01-10 09:00:04.000000000 +0000 ++++ rsyslog-8.24.0/runtime/netstrm.c 2019-08-19 17:37:07.876166693 +0100 +@@ -280,6 +280,16 @@ SetKeepAliveIntvl(netstrm_t *pThis, int + RETiRet; + } + ++/* gnutls priority string */ ++static rsRetVal ++SetGnutlsPriorityString(netstrm_t *pThis, uchar *gnutlsPriorityString) ++{ ++ DEFiRet; ++ ISOBJ_TYPE_assert(pThis, netstrm); ++ iRet = pThis->Drvr.SetGnutlsPriorityString(pThis->pDrvrData, gnutlsPriorityString); ++ RETiRet; ++} ++ + /* check connection - slim wrapper for NSD driver function */ + static rsRetVal + CheckConnection(netstrm_t *pThis) +@@ -387,6 +397,7 @@ CODESTARTobjQueryInterface(netstrm) + pIf->SetKeepAliveProbes = SetKeepAliveProbes; + pIf->SetKeepAliveTime = SetKeepAliveTime; + pIf->SetKeepAliveIntvl = SetKeepAliveIntvl; ++ pIf->SetGnutlsPriorityString = SetGnutlsPriorityString; + finalize_it: + ENDobjQueryInterface(netstrm) + +diff -up rsyslog-8.24.0/runtime/netstrm.h.v36tls rsyslog-8.24.0/runtime/netstrm.h +--- rsyslog-8.24.0/runtime/netstrm.h.v36tls 2017-01-10 09:00:04.000000000 +0000 ++++ rsyslog-8.24.0/runtime/netstrm.h 2019-08-19 17:37:07.876166693 +0100 +@@ -75,14 +75,16 @@ BEGINinterface(netstrm) /* name must als + rsRetVal (*SetKeepAliveProbes)(netstrm_t *pThis, int keepAliveProbes); + rsRetVal (*SetKeepAliveTime)(netstrm_t *pThis, int keepAliveTime); + rsRetVal (*SetKeepAliveIntvl)(netstrm_t *pThis, int keepAliveIntvl); ++ rsRetVal (*SetGnutlsPriorityString)(netstrm_t *pThis, uchar *priorityString); + ENDinterface(netstrm) +-#define netstrmCURR_IF_VERSION 8 /* increment whenever you change the interface structure! */ ++#define netstrmCURR_IF_VERSION 9 /* increment whenever you change the interface structure! */ + /* interface version 3 added GetRemAddr() + * interface version 4 added EnableKeepAlive() -- rgerhards, 2009-06-02 + * interface version 5 changed return of CheckConnection from void to rsRetVal -- alorbach, 2012-09-06 + * interface version 6 changed signature of GetRemoteIP() -- rgerhards, 2013-01-21 + * interface version 7 added KeepAlive parameter set functions + * interface version 8 changed signature of Connect() -- dsa, 2016-11-14 ++ * interface version 9 added SetGnutlsPriorityString -- PascalWithopf, 2017-08-08 + * */ + + /* prototypes */ +diff -up rsyslog-8.24.0/runtime/netstrms.c.v36tls rsyslog-8.24.0/runtime/netstrms.c +--- rsyslog-8.24.0/runtime/netstrms.c.v36tls 2016-12-03 17:41:03.000000000 +0000 ++++ rsyslog-8.24.0/runtime/netstrms.c 2019-08-19 17:37:07.876166693 +0100 +@@ -113,6 +113,10 @@ CODESTARTobjDestruct(netstrms) + free(pThis->pBaseDrvrName); + pThis->pBaseDrvrName = NULL; + } ++ if(pThis->gnutlsPriorityString != NULL) { ++ free(pThis->gnutlsPriorityString); ++ pThis->gnutlsPriorityString = NULL; ++ } + ENDobjDestruct(netstrms) + + +@@ -196,6 +200,31 @@ GetDrvrAuthMode(netstrms_t *pThis) + } + + ++/* Set the priorityString for GnuTLS ++ * PascalWithopf 2017-08-16 ++ */ ++static rsRetVal ++SetDrvrGnutlsPriorityString(netstrms_t *pThis, uchar *iVal) ++{ ++ DEFiRet; ++ ISOBJ_TYPE_assert(pThis, netstrms); ++ CHKmalloc(pThis->gnutlsPriorityString = (uchar*)strdup((char*)iVal)); ++finalize_it: ++ RETiRet; ++} ++ ++ ++/* return the priorityString for GnuTLS ++ * PascalWithopf, 2017-08-16 ++ */ ++static uchar* ++GetDrvrGnutlsPriorityString(netstrms_t *pThis) ++{ ++ ISOBJ_TYPE_assert(pThis, netstrms); ++ return pThis->gnutlsPriorityString; ++} ++ ++ + /* set the driver mode -- rgerhards, 2008-04-30 */ + static rsRetVal + SetDrvrMode(netstrms_t *pThis, int iMode) +@@ -272,6 +301,8 @@ CODESTARTobjQueryInterface(netstrms) + pIf->GetDrvrMode = GetDrvrMode; + pIf->SetDrvrAuthMode = SetDrvrAuthMode; + pIf->GetDrvrAuthMode = GetDrvrAuthMode; ++ pIf->SetDrvrGnutlsPriorityString = SetDrvrGnutlsPriorityString; ++ pIf->GetDrvrGnutlsPriorityString = GetDrvrGnutlsPriorityString; + pIf->SetDrvrPermPeers = SetDrvrPermPeers; + pIf->GetDrvrPermPeers = GetDrvrPermPeers; + finalize_it: +diff -up rsyslog-8.24.0/runtime/netstrms.h.v36tls rsyslog-8.24.0/runtime/netstrms.h +--- rsyslog-8.24.0/runtime/netstrms.h.v36tls 2016-12-03 17:41:03.000000000 +0000 ++++ rsyslog-8.24.0/runtime/netstrms.h 2019-08-19 17:37:07.876166693 +0100 +@@ -33,6 +33,7 @@ struct netstrms_s { + uchar *pDrvrName; /**< full base driver name (set when driver is loaded) */ + int iDrvrMode; /**< current default driver mode */ + uchar *pszDrvrAuthMode; /**< current driver authentication mode */ ++ uchar *gnutlsPriorityString; /**< priorityString for connection */ + permittedPeers_t *pPermPeers;/**< current driver's permitted peers */ + + nsd_if_t Drvr; /**< our stream driver */ +@@ -52,6 +53,8 @@ BEGINinterface(netstrms) /* name must al + int (*GetDrvrMode)(netstrms_t *pThis); + uchar* (*GetDrvrAuthMode)(netstrms_t *pThis); + permittedPeers_t* (*GetDrvrPermPeers)(netstrms_t *pThis); ++ rsRetVal (*SetDrvrGnutlsPriorityString)(netstrms_t *pThis, uchar*); ++ uchar* (*GetDrvrGnutlsPriorityString)(netstrms_t *pThis); + ENDinterface(netstrms) + #define netstrmsCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ + +diff -up rsyslog-8.24.0/runtime/nsd_gtls.c.v36tls rsyslog-8.24.0/runtime/nsd_gtls.c +--- rsyslog-8.24.0/runtime/nsd_gtls.c.v36tls 2017-01-10 09:00:04.000000000 +0000 ++++ rsyslog-8.24.0/runtime/nsd_gtls.c 2019-08-19 17:39:30.576158227 +0100 +@@ -73,8 +73,20 @@ DEFobjCurrIf(nsd_ptcp) + + static int bGlblSrvrInitDone = 0; /**< 0 - server global init not yet done, 1 - already done */ + +-static pthread_mutex_t mutGtlsStrerror; /**< a mutex protecting the potentially non-reentrant gtlStrerror() function */ ++static pthread_mutex_t mutGtlsStrerror; ++/*< a mutex protecting the potentially non-reentrant gtlStrerror() function */ + ++/* a macro to abort if GnuTLS error is not acceptable. We split this off from ++ * CHKgnutls() to avoid some Coverity report in cases where we know GnuTLS ++ * failed. Note: gnuRet must already be set accordingly! ++ */ ++#define ABORTgnutls { \ ++ uchar *pErr = gtlsStrerror(gnuRet); \ ++ LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d in %s:%d: %s\n", \ ++ gnuRet, __FILE__, __LINE__, pErr); \ ++ free(pErr); \ ++ ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \ ++} + /* a macro to check GnuTLS calls against unexpected errors */ + #define CHKgnutls(x) { \ + gnuRet = (x); \ +@@ -82,10 +94,7 @@ static pthread_mutex_t mutGtlsStrerror; + errmsg.LogError(0, RS_RET_GNUTLS_ERR, "error reading file - a common cause is that the file does not exist"); \ + ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \ + } else if(gnuRet != 0) { \ +- uchar *pErr = gtlsStrerror(gnuRet); \ +- errmsg.LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d in %s:%d: %s\n", gnuRet, __FILE__, __LINE__, pErr); \ +- free(pErr); \ +- ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \ ++ ABORTgnutls; \ + } \ + } + +@@ -192,9 +201,12 @@ gtlsLoadOurCertKey(nsd_gtls_t *pThis) + + /* try load certificate */ + CHKiRet(readFile(certFile, &data)); +- CHKgnutls(gnutls_x509_crt_init(&pThis->ourCert)); +- pThis->bOurCertIsInit = 1; +- CHKgnutls(gnutls_x509_crt_import(pThis->ourCert, &data, GNUTLS_X509_FMT_PEM)); ++ pThis->nOurCerts = sizeof(pThis->pOurCerts) / sizeof(gnutls_x509_crt_t); ++ gnuRet = gnutls_x509_crt_list_import(pThis->pOurCerts, &pThis->nOurCerts, ++ &data, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); ++ if(gnuRet < 0) { ++ ABORTgnutls; ++ } + free(data.data); + data.data = NULL; + +@@ -210,7 +222,9 @@ finalize_it: + if(data.data != NULL) + free(data.data); + if(pThis->bOurCertIsInit) { +- gnutls_x509_crt_deinit(pThis->ourCert); ++ for(unsigned i=0; inOurCerts; ++i) { ++ gnutls_x509_crt_deinit(pThis->pOurCerts[i]); ++ } + pThis->bOurCertIsInit = 0; + } + if(pThis->bOurKeyIsInit) { +@@ -255,8 +269,8 @@ gtlsClientCertCallback(gnutls_session_t + #else + st->type = GNUTLS_CRT_X509; + #endif +- st->ncerts = 1; +- st->cert.x509 = &pThis->ourCert; ++ st->ncerts = pThis->nOurCerts; ++ st->cert.x509 = pThis->pOurCerts; + st->key.x509 = pThis->ourKey; + st->deinit_all = 0; + +@@ -532,8 +546,8 @@ gtlsRecordRecv(nsd_gtls_t *pThis) + dbgprintf("GnuTLS receive requires a retry (this most probably is OK and no error condition)\n"); + ABORT_FINALIZE(RS_RET_RETRY); + } else { +- int gnuRet; /* TODO: build a specific function for GnuTLS error reporting */ +- CHKgnutls(lenRcvd); /* this will abort the function */ ++ int gnuRet = lenRcvd; ++ ABORTgnutls; + } + + finalize_it: +@@ -646,7 +660,7 @@ gtlsInitSession(nsd_gtls_t *pThis) + pThis->bIsInitiator = 0; + + /* avoid calling all the priority functions, since the defaults are adequate. */ +- CHKgnutls(gnutls_set_default_priority(session)); ++ + CHKgnutls(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred)); + + /* request client certificate if any. */ +@@ -1204,7 +1218,9 @@ CODESTARTobjDestruct(nsd_gtls) + } + + if(pThis->bOurCertIsInit) +- gnutls_x509_crt_deinit(pThis->ourCert); ++ for(unsigned i=0; inOurCerts; ++i) { ++ gnutls_x509_crt_deinit(pThis->pOurCerts[i]); ++ } + if(pThis->bOurKeyIsInit) + gnutls_x509_privkey_deinit(pThis->ourKey); + if(pThis->bHaveSess) +@@ -1299,6 +1315,21 @@ finalize_it: + } + + ++/* gnutls priority string ++ * PascalWithopf 2017-08-16 ++ */ ++static rsRetVal ++SetGnutlsPriorityString(nsd_t *pNsd, uchar *gnutlsPriorityString) ++{ ++ DEFiRet; ++ nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd; ++ ++ ISOBJ_TYPE_assert((pThis), nsd_gtls); ++ pThis->gnutlsPriorityString = gnutlsPriorityString; ++ RETiRet; ++} ++ ++ + /* Provide access to the underlying OS socket. This is primarily + * useful for other drivers (like nsd_gtls) who utilize ourselfs + * for some of their functionality. -- rgerhards, 2008-04-18 +@@ -1476,6 +1507,7 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew + int gnuRet; + nsd_gtls_t *pNew = NULL; + nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd; ++ const char *error_position; + + ISOBJ_TYPE_assert((pThis), nsd_gtls); + CHKiRet(nsd_gtlsConstruct(&pNew)); // TODO: prevent construct/destruct! +@@ -1493,6 +1525,19 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew + gtlsSetTransportPtr(pNew, ((nsd_ptcp_t*) (pNew->pTcp))->sock); + pNew->authMode = pThis->authMode; + pNew->pPermPeers = pThis->pPermPeers; ++ pNew->gnutlsPriorityString = pThis->gnutlsPriorityString; ++ /* here is the priorityString set */ ++ if(pNew->gnutlsPriorityString != NULL) { ++ if(gnutls_priority_set_direct(pNew->sess, ++ (const char*) pNew->gnutlsPriorityString, ++ &error_position)==GNUTLS_E_INVALID_REQUEST) { ++ LogError(0, RS_RET_GNUTLS_ERR, "Syntax Error in" ++ " Priority String: \"%s\"\n", error_position); ++ } ++ } else { ++ /* Use default priorities */ ++ CHKgnutls(gnutls_set_default_priority(pNew->sess)); ++ } + + /* we now do the handshake. This is a bit complicated, because we are + * on non-blocking sockets. Usually, the handshake will not complete +@@ -1673,6 +1718,31 @@ EnableKeepAlive(nsd_t *pNsd) + return nsd_ptcp.EnableKeepAlive(pThis->pTcp); + } + ++/* ++ * SNI should not be used if the hostname is a bare IP address ++ */ ++static int ++SetServerNameIfPresent(nsd_gtls_t *pThis, uchar *host) { ++ struct sockaddr_in sa; ++ struct sockaddr_in6 sa6; ++ ++ int inet_pton_ret = inet_pton(AF_INET, CHAR_CONVERT(host), &(sa.sin_addr)); ++ ++ if (inet_pton_ret == 0) { // host wasn't a bare IPv4 address: try IPv6 ++ inet_pton_ret = inet_pton(AF_INET6, CHAR_CONVERT(host), &(sa6.sin6_addr)); ++ } ++ ++ switch(inet_pton_ret) { ++ case 1: // host is a valid IP address: don't use SNI ++ return 0; ++ case 0: // host isn't a valid IP address: assume it's a domain name, use SNI ++ return gnutls_server_name_set(pThis->sess, GNUTLS_NAME_DNS, host, ustrlen(host)); ++ default: // unexpected error ++ return -1; ++ } ++ ++} ++ + /* open a connection to a remote host (server). With GnuTLS, we always + * open a plain tcp socket and then, if in TLS mode, do a handshake on it. + * rgerhards, 2008-03-19 +@@ -1685,6 +1755,7 @@ Connect(nsd_t *pNsd, int family, uchar * + nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd; + int sock; + int gnuRet; ++ const char *error_position; + # ifdef HAVE_GNUTLS_CERTIFICATE_TYPE_SET_PRIORITY + static const int cert_type_priority[2] = { GNUTLS_CRT_X509, 0 }; + # endif +@@ -1704,6 +1775,8 @@ Connect(nsd_t *pNsd, int family, uchar * + pThis->bHaveSess = 1; + pThis->bIsInitiator = 1; + ++ CHKgnutls(SetServerNameIfPresent(pThis, host)); ++ + /* in the client case, we need to set a callback that ensures our certificate + * will be presented to the server even if it is not signed by one of the server's + * trusted roots. This is necessary to support fingerprint authentication. +@@ -1721,8 +1794,19 @@ Connect(nsd_t *pNsd, int family, uchar * + FINALIZE; /* we have an error case! */ + } + +- /* Use default priorities */ +- CHKgnutls(gnutls_set_default_priority(pThis->sess)); ++ /*priority string setzen*/ ++ if(pThis->gnutlsPriorityString != NULL) { ++ if(gnutls_priority_set_direct(pThis->sess, ++ (const char*) pThis->gnutlsPriorityString, ++ &error_position)==GNUTLS_E_INVALID_REQUEST) { ++ LogError(0, RS_RET_GNUTLS_ERR, "Syntax Error in" ++ " Priority String: \"%s\"\n", error_position); ++ } ++ } else { ++ /* Use default priorities */ ++ CHKgnutls(gnutls_set_default_priority(pThis->sess)); ++ } ++ + # ifdef HAVE_GNUTLS_CERTIFICATE_TYPE_SET_PRIORITY + /* The gnutls_certificate_type_set_priority function is deprecated + * and not available in recent GnuTLS versions. However, there is no +@@ -1806,6 +1890,7 @@ CODESTARTobjQueryInterface(nsd_gtls) + pIf->SetKeepAliveIntvl = SetKeepAliveIntvl; + pIf->SetKeepAliveProbes = SetKeepAliveProbes; + pIf->SetKeepAliveTime = SetKeepAliveTime; ++ pIf->SetGnutlsPriorityString = SetGnutlsPriorityString; + finalize_it: + ENDobjQueryInterface(nsd_gtls) + +diff -up rsyslog-8.24.0/runtime/nsd_gtls.h.v36tls rsyslog-8.24.0/runtime/nsd_gtls.h +--- rsyslog-8.24.0/runtime/nsd_gtls.h.v36tls 2016-12-03 17:41:03.000000000 +0000 ++++ rsyslog-8.24.0/runtime/nsd_gtls.h 2019-08-19 17:37:07.878166693 +0100 +@@ -25,6 +25,7 @@ + #include "nsd.h" + + #define NSD_GTLS_MAX_RCVBUF 8 * 1024 /* max size of buffer for message reception */ ++#define NSD_GTLS_MAX_CERT 10 /* max number of certs in our chain */ + + typedef enum { + gtlsRtry_None = 0, /**< no call needs to be retried */ +@@ -56,7 +57,10 @@ struct nsd_gtls_s { + * set to 1 and changed to 0 after the first report. It is changed back to 1 after + * one successful authentication. */ + permittedPeers_t *pPermPeers; /* permitted peers */ +- gnutls_x509_crt_t ourCert; /**< our certificate, if in client mode (unused in server mode) */ ++ uchar *gnutlsPriorityString; /* gnutls priority string */ ++ gnutls_x509_crt_t pOurCerts[NSD_GTLS_MAX_CERT]; /**< our certificate, if in client mode ++ (unused in server mode) */ ++ unsigned int nOurCerts; /* number of certificates in our chain */ + gnutls_x509_privkey_t ourKey; /**< our private key, if in client mode (unused in server mode) */ + short bOurCertIsInit; /**< 1 if our certificate is initialized and must be deinit on destruction */ + short bOurKeyIsInit; /**< 1 if our private key is initialized and must be deinit on destruction */ +diff -up rsyslog-8.24.0/runtime/nsd.h.v36tls rsyslog-8.24.0/runtime/nsd.h +--- rsyslog-8.24.0/runtime/nsd.h.v36tls 2017-01-10 09:00:04.000000000 +0000 ++++ rsyslog-8.24.0/runtime/nsd.h 2019-08-19 17:37:07.878166693 +0100 +@@ -83,14 +83,17 @@ BEGINinterface(nsd) /* name must also be + rsRetVal (*SetKeepAliveIntvl)(nsd_t *pThis, int keepAliveIntvl); + rsRetVal (*SetKeepAliveProbes)(nsd_t *pThis, int keepAliveProbes); + rsRetVal (*SetKeepAliveTime)(nsd_t *pThis, int keepAliveTime); ++ /* v10 */ ++ rsRetVal (*SetGnutlsPriorityString)(nsd_t *pThis, uchar *gnutlsPriorityString); + ENDinterface(nsd) +-#define nsdCURR_IF_VERSION 9 /* increment whenever you change the interface structure! */ ++#define nsdCURR_IF_VERSION 10 /* increment whenever you change the interface structure! */ + /* interface version 4 added GetRemAddr() + * interface version 5 added EnableKeepAlive() -- rgerhards, 2009-06-02 + * interface version 6 changed return of CheckConnection from void to rsRetVal -- alorbach, 2012-09-06 + * interface version 7 changed signature ofGetRempoteIP() -- rgerhards, 2013-01-21 + * interface version 8 added keep alive parameter set functions + * interface version 9 changed signature of Connect() -- dsa, 2016-11-14 ++ * interface version 10 added SetGnutlsPriorityString() -- PascalWithopf, 2017-08-08 + */ + + /* interface for the select call */ +diff -up rsyslog-8.24.0/runtime/nsd_ptcp.c.v36tls rsyslog-8.24.0/runtime/nsd_ptcp.c +--- rsyslog-8.24.0/runtime/nsd_ptcp.c.v36tls 2017-01-10 09:00:04.000000000 +0000 ++++ rsyslog-8.24.0/runtime/nsd_ptcp.c 2019-08-19 17:37:07.879166693 +0100 +@@ -176,6 +176,23 @@ finalize_it: + } + + ++/* Set priorityString ++ * PascalWithopf 2017-08-18 */ ++static rsRetVal ++SetGnutlsPriorityString(nsd_t __attribute__((unused)) *pNsd, uchar *iVal) ++{ ++ DEFiRet; ++ if(iVal != NULL) { ++ LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: " ++ "gnutlsPriorityString '%s' not supported by ptcp netstream " ++ "driver", iVal); ++ ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED); ++ } ++finalize_it: ++ RETiRet; ++} ++ ++ + /* Set the permitted peers. This is a dummy, always returning an + * error because we do not support fingerprint authentication. + * rgerhards, 2008-05-17 +@@ -535,6 +552,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rs + CHKiRet(pNS->Drvr.SetMode(pNewNsd, netstrms.GetDrvrMode(pNS))); + CHKiRet(pNS->Drvr.SetAuthMode(pNewNsd, netstrms.GetDrvrAuthMode(pNS))); + CHKiRet(pNS->Drvr.SetPermPeers(pNewNsd, netstrms.GetDrvrPermPeers(pNS))); ++ CHKiRet(pNS->Drvr.SetGnutlsPriorityString(pNewNsd, netstrms.GetDrvrGnutlsPriorityString(pNS))); + CHKiRet(netstrms.CreateStrm(pNS, &pNewStrm)); + pNewStrm->pDrvrData = (nsd_t*) pNewNsd; + pNewNsd = NULL; +@@ -854,6 +872,7 @@ CODESTARTobjQueryInterface(nsd_ptcp) + pIf->SetSock = SetSock; + pIf->SetMode = SetMode; + pIf->SetAuthMode = SetAuthMode; ++ pIf->SetGnutlsPriorityString = SetGnutlsPriorityString; + pIf->SetPermPeers = SetPermPeers; + pIf->Rcv = Rcv; + pIf->Send = Send; +diff -up rsyslog-8.24.0/runtime/tcpsrv.c.v36tls rsyslog-8.24.0/runtime/tcpsrv.c +--- rsyslog-8.24.0/runtime/tcpsrv.c.v36tls 2019-08-19 17:37:07.874166693 +0100 ++++ rsyslog-8.24.0/runtime/tcpsrv.c 2019-08-19 17:37:07.880166693 +0100 +@@ -470,6 +470,9 @@ SessAccept(tcpsrv_t *pThis, tcpLstnPortL + } + + /* we found a free spot and can construct our session object */ ++ if(pThis->gnutlsPriorityString != NULL) { ++ CHKiRet(netstrm.SetGnutlsPriorityString(pNewStrm, pThis->gnutlsPriorityString)); ++ } + CHKiRet(tcps_sess.Construct(&pSess)); + CHKiRet(tcps_sess.SetTcpsrv(pSess, pThis)); + CHKiRet(tcps_sess.SetLstnInfo(pSess, pLstnInfo)); +@@ -1001,6 +1004,8 @@ tcpsrvConstructFinalize(tcpsrv_t *pThis) + CHKiRet(netstrms.SetDrvrAuthMode(pThis->pNS, pThis->pszDrvrAuthMode)); + if(pThis->pPermPeers != NULL) + CHKiRet(netstrms.SetDrvrPermPeers(pThis->pNS, pThis->pPermPeers)); ++ if(pThis->gnutlsPriorityString != NULL) ++ CHKiRet(netstrms.SetDrvrGnutlsPriorityString(pThis->pNS, pThis->gnutlsPriorityString)); + CHKiRet(netstrms.ConstructFinalize(pThis->pNS)); + + /* set up listeners */ +@@ -1173,6 +1178,16 @@ SetKeepAliveTime(tcpsrv_t *pThis, int iV + } + + static rsRetVal ++SetGnutlsPriorityString(tcpsrv_t *pThis, uchar *iVal) ++{ ++ DEFiRet; ++ DBGPRINTF("tcpsrv: gnutlsPriorityString set to %s\n", ++ (iVal == NULL) ? "(null)" : (const char*) iVal); ++ pThis->gnutlsPriorityString = iVal; ++ RETiRet; ++} ++ ++static rsRetVal + SetOnMsgReceive(tcpsrv_t *pThis, rsRetVal (*OnMsgReceive)(tcps_sess_t*, uchar*, int)) + { + DEFiRet; +@@ -1414,6 +1429,7 @@ CODESTARTobjQueryInterface(tcpsrv) + pIf->SetKeepAliveIntvl = SetKeepAliveIntvl; + pIf->SetKeepAliveProbes = SetKeepAliveProbes; + pIf->SetKeepAliveTime = SetKeepAliveTime; ++ pIf->SetGnutlsPriorityString = SetGnutlsPriorityString; + pIf->SetUsrP = SetUsrP; + pIf->SetInputName = SetInputName; + pIf->SetOrigin = SetOrigin; +diff -up rsyslog-8.24.0/runtime/tcpsrv.h.v36tls rsyslog-8.24.0/runtime/tcpsrv.h +--- rsyslog-8.24.0/runtime/tcpsrv.h.v36tls 2019-08-19 17:37:07.874166693 +0100 ++++ rsyslog-8.24.0/runtime/tcpsrv.h 2019-08-19 17:37:07.880166693 +0100 +@@ -61,6 +61,7 @@ struct tcpsrv_s { + int iKeepAliveTime; /**< socket layer KEEPALIVE timeout */ + netstrms_t *pNS; /**< pointer to network stream subsystem */ + int iDrvrMode; /**< mode of the stream driver to use */ ++ uchar *gnutlsPriorityString; /**< priority string for gnutls */ + uchar *pszDrvrAuthMode; /**< auth mode of the stream driver to use */ + uchar *pszDrvrName; /**< name of stream driver to use */ + uchar *pszInputName; /**< value to be used as input name */ +@@ -169,6 +170,8 @@ BEGINinterface(tcpsrv) /* name must also + rsRetVal (*SetKeepAliveTime)(tcpsrv_t*, int); + /* added v18 */ + rsRetVal (*SetbSPFramingFix)(tcpsrv_t*, sbool); ++ /* added v19 -- PascalWithopf, 2017-08-08 */ ++ rsRetVal (*SetGnutlsPriorityString)(tcpsrv_t*, uchar*); + /* added v21 -- Preserve case in fromhost, 2018-08-16 */ + rsRetVal (*SetPreserveCase)(tcpsrv_t *pThis, int bPreserveCase); + ENDinterface(tcpsrv) +diff -up rsyslog-8.24.0/tools/omfwd.c.v36tls rsyslog-8.24.0/tools/omfwd.c +--- rsyslog-8.24.0/tools/omfwd.c.v36tls 2019-08-19 17:37:07.848166695 +0100 ++++ rsyslog-8.24.0/tools/omfwd.c 2019-08-19 17:37:07.881166693 +0100 +@@ -91,6 +91,7 @@ typedef struct _instanceData { + int iKeepAliveIntvl; + int iKeepAliveProbes; + int iKeepAliveTime; ++ uchar *gnutlsPriorityString; + + # define FORW_UDP 0 + # define FORW_TCP 1 +@@ -138,6 +139,7 @@ typedef struct configSettings_s { + int iKeepAliveIntvl; + int iKeepAliveProbes; + int iKeepAliveTime; ++ uchar *gnutlsPriorityString; + permittedPeers_t *pPermPeers; + } configSettings_t; + static configSettings_t cs; +@@ -169,6 +171,7 @@ static struct cnfparamdescr actpdescr[] + { "keepalive.probes", eCmdHdlrPositiveInt, 0 }, + { "keepalive.time", eCmdHdlrPositiveInt, 0 }, + { "keepalive.interval", eCmdHdlrPositiveInt, 0 }, ++ { "gnutlsprioritystring", eCmdHdlrString, 0 }, + { "streamdriver", eCmdHdlrGetWord, 0 }, + { "streamdrivermode", eCmdHdlrInt, 0 }, + { "streamdriverauthmode", eCmdHdlrGetWord, 0 }, +@@ -717,6 +720,9 @@ static rsRetVal TCPSendInit(void *pvData + CHKiRet(netstrm.SetDrvrPermPeers(pWrkrData->pNetstrm, pData->pPermPeers)); + } + /* params set, now connect */ ++ if(pData->gnutlsPriorityString != NULL) { ++ CHKiRet(netstrm.SetGnutlsPriorityString(pWrkrData->pNetstrm, pData->gnutlsPriorityString)); ++ } + CHKiRet(netstrm.Connect(pWrkrData->pNetstrm, glbl.GetDefPFFamily(), + (uchar*)pData->port, (uchar*)pData->target, pData->device)); + +@@ -960,6 +966,7 @@ setInstParamDefaults(instanceData *pData + pData->iKeepAliveProbes = 0; + pData->iKeepAliveIntvl = 0; + pData->iKeepAliveTime = 0; ++ pData->gnutlsPriorityString = NULL; + pData->bResendLastOnRecon = 0; + pData->bSendToAll = -1; /* unspecified */ + pData->iUDPSendDelay = 0; +@@ -1046,6 +1053,8 @@ CODESTARTnewActInst + pData->iKeepAliveIntvl = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "keepalive.time")) { + pData->iKeepAliveTime = (int) pvals[i].val.d.n; ++ } else if(!strcmp(actpblk.descr[i].name, "gnutlsprioritystring")) { ++ pData->gnutlsPriorityString = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "streamdriver")) { + pData->pszStrmDrvr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "streamdrivermode")) { diff --git a/SOURCES/rsyslog-8.24.0-rhbz1649250-imfile-rotation.patch b/SOURCES/rsyslog-8.24.0-rhbz1649250-imfile-rotation.patch index 85cb451..c52abc1 100644 --- a/SOURCES/rsyslog-8.24.0-rhbz1649250-imfile-rotation.patch +++ b/SOURCES/rsyslog-8.24.0-rhbz1649250-imfile-rotation.patch @@ -142,7 +142,7 @@ index 2d494c612..5b52591ef 100644 +checkTruncation(strm_t *const pThis) +{ + DEFiRet; -+ int ret; ++ off64_t ret; + off64_t backseek; + assert(pThis->bReopenOnTruncate); + diff --git a/SOURCES/rsyslog-8.24.0-rhbz1684236-omelastic-sigsegv.patch b/SOURCES/rsyslog-8.24.0-rhbz1684236-omelastic-sigsegv.patch new file mode 100644 index 0000000..2f839a6 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1684236-omelastic-sigsegv.patch @@ -0,0 +1,65 @@ +From 48dd54fd6d1edeb5dcdde95935a3ca9d2a6ab52e Mon Sep 17 00:00:00 2001 +From: Rich Megginson +Date: Wed, 6 Mar 2019 10:23:28 -0700 +Subject: [PATCH] Bug 1684236 - rsyslog-8.24.0-34.el7.x86_64 SIGSEGV when using + rsyslog-elasticsearch-8.24.0-34 + +https://bugzilla.redhat.com/show_bug.cgi?id=1684236 + +Cause: When omelasticsearch has a problem sending data to +Elasticsearch because the connection was broken, the curl api +returns an error code that was not being checked. The +omelasticsearch code also assumed that the reply field would +always be allocated, but it is not in this error case. + +Consequence: rsyslog crashes when the connection to Elasticsearch +is lost while attempting to send data to Elasticsearch. + +Fix: Check for the correct error code (CURLE_GOT_NOTHING), and +also check that the reply field was allocated. + +Result: rsyslog does not crash when the connection to Elasticsearch +is lost while attempting to send data to Elasticsearch. +--- + plugins/omelasticsearch/omelasticsearch.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/plugins/omelasticsearch/omelasticsearch.c b/plugins/omelasticsearch/omelasticsearch.c +index 248a369d2..d0c3f91d5 100644 +--- a/plugins/omelasticsearch/omelasticsearch.c ++++ b/plugins/omelasticsearch/omelasticsearch.c +@@ -1431,6 +1431,7 @@ curlPost(wrkrInstanceData_t *pWrkrData, uchar *message, int msglen, uchar **tpls + || code == CURLE_COULDNT_RESOLVE_PROXY + || code == CURLE_COULDNT_CONNECT + || code == CURLE_WRITE_ERROR ++ || code == CURLE_GOT_NOTHING + ) { + STATSCOUNTER_INC(indexHTTPReqFail, mutIndexHTTPReqFail); + indexHTTPFail += nmsgs; +@@ -1441,15 +1442,20 @@ curlPost(wrkrInstanceData_t *pWrkrData, uchar *message, int msglen, uchar **tpls + } + + DBGPRINTF("omelasticsearch: pWrkrData replyLen = '%d'\n", pWrkrData->replyLen); +- if(pWrkrData->replyLen > 0) { ++ if(NULL != pWrkrData->reply) { ++ if(pWrkrData->replyLen > 0) { + pWrkrData->reply[pWrkrData->replyLen] = '\0'; /* Append 0 Byte if replyLen is above 0 - byte has been reserved in malloc */ ++ } ++ CHKiRet(checkResult(pWrkrData, message)); ++ DBGPRINTF("omelasticsearch: pWrkrData reply: '%s'\n", pWrkrData->reply); ++ } else { ++ DBGPRINTF("omelasticsearch: pWrkrData reply is NULL\n"); + } +- DBGPRINTF("omelasticsearch: pWrkrData reply: '%s'\n", pWrkrData->reply); + +- CHKiRet(checkResult(pWrkrData, message)); + finalize_it: + incrementServerIndex(pWrkrData); + free(pWrkrData->reply); ++ pWrkrData->reply = NULL; + RETiRet; + } + +-- +2.20.1 + diff --git a/SOURCES/rsyslog-8.24.0-rhbz1696686-imjournal-fsync.patch b/SOURCES/rsyslog-8.24.0-rhbz1696686-imjournal-fsync.patch new file mode 100644 index 0000000..430dbd1 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1696686-imjournal-fsync.patch @@ -0,0 +1,114 @@ +From 628d791b26062945fad4afa5985f6b84f46f16d4 Mon Sep 17 00:00:00 2001 +From: Jiri Vymazal +Date: Tue, 23 Jul 2019 11:28:31 +0200 +Subject: [PATCH] Add "fsync" option for imjournal + +The new option makes possible to force physical write of stateFile +to persistent storage, ensuring we do not lose/duplicate messages +in case of hard crash or power loss. +--- + plugins/imjournal/imjournal.c | 41 +++++++++++++++---- + 1 file changed, 32 insertions(+), 9 deletitions(-) + +diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c +index 5739bf408c..6c8829243a 100644 +--- a/plugins/imjournal/imjournal.c ++++ b/plugins/imjournal/imjournal.c +@@ -24,6 +24,7 @@ + #include "config.h" + #include "rsyslog.h" + #include ++#include + #include + #include + #include +@@ -81,6 +82,7 @@ static struct configSettings_s { + int bUseJnlPID; + char *dfltTag; + int bWorkAroundJournalBug; ++ int bFsync; + } cs; + + static rsRetVal facilityHdlr(uchar **pp, void *pVal); +@@ -99,7 +99,8 @@ static struct cnfparamdescr modpdescr[] = { + { "defaultfacility", eCmdHdlrString, 0 }, + { "usepidfromsystem", eCmdHdlrBinary, 0 }, + { "defaulttag", eCmdHdlrGetWord, 0 }, +- { "workaroundjournalbug", eCmdHdlrBinary, 0 } ++ { "workaroundjournalbug", eCmdHdlrBinary, 0 }, ++ { "fsync", eCmdHdlrBinary, 0 } + }; + static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, +@@ -437,7 +437,7 @@ persistJournalState(int trySave) + persistJournalState(int trySave) + { + DEFiRet; +- FILE *sf; /* state file */ ++ FILE *sf = NULL; /* state file */ + char tmp_sf[MAXFNAME]; + int ret = 0; + +@@ -468,13 +468,6 @@ persistJournalState(int trySave) + ret = fputs(last_cursor, sf); + if (ret < 0) { + errmsg.LogError(errno, RS_RET_IO_ERROR, "imjournal: failed to save cursor to: '%s'", tmp_sf); +- ret = fclose(sf); +- ABORT_FINALIZE(RS_RET_IO_ERROR); +- } +- +- ret = fclose(sf); +- if (ret < 0) { +- errmsg.LogError(errno, RS_RET_IO_ERROR, "imjournal: fclose() failed for path: '%s'", tmp_sf); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + +@@ -484,7 +477,30 @@ persistJournalState(int trySave) + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + ++ if (cs.bFsync) { ++ if (fsync(fileno(sf)) != 0) { ++ LogError(errno, RS_RET_IO_ERROR, "imjournal: fsync on '%s' failed", cs.stateFile); ++ ABORT_FINALIZE(RS_RET_IO_ERROR); ++ } ++ /* In order to guarantee physical write we need to force parent sync as well */ ++ DIR *wd; ++ if (!(wd = opendir((char *)glbl.GetWorkDir()))) { ++ LogError(errno, RS_RET_IO_ERROR, "imjournal: failed to open '%s' directory", glbl.GetWorkDir()); ++ ABORT_FINALIZE(RS_RET_IO_ERROR); ++ } ++ if (fsync(dirfd(wd)) != 0) { ++ LogError(errno, RS_RET_IO_ERROR, "imjournal: fsync on '%s' failed", glbl.GetWorkDir()); ++ ABORT_FINALIZE(RS_RET_IO_ERROR); ++ } ++ } ++ + finalize_it: ++ if (sf != NULL) { ++ if (fclose(sf) == EOF) { ++ LogError(errno, RS_RET_IO_ERROR, "imjournal: fclose() failed for path: '%s'", tmp_sf); ++ iRet = RS_RET_IO_ERROR; ++ } ++ } + RETiRet; + } + +@@ -746,6 +747,8 @@ CODESTARTbeginCnfLoad + cs.iDfltFacility = DFLT_FACILITY; + cs.dfltTag = NULL; + cs.bUseJnlPID = 0; ++ cs.bWorkAroundJournalBug = 0; ++ cs.bFsync = 0; + ENDbeginCnfLoad + + +@@ -943,6 +963,8 @@ CODESTARTsetModCnf + cs.dfltTag = (char *)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if (!strcmp(modpblk.descr[i].name, "workaroundjournalbug")) { + cs.bWorkAroundJournalBug = (int) pvals[i].val.d.n; ++ } else if (!strcmp(modpblk.descr[i].name, "fsync")) { ++ cs.bFsync = (int) pvals[i].val.d.n; + } else { + dbgprintf("imjournal: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); diff --git a/SOURCES/rsyslog-8.24.0-rhbz1744682-ratelimiter-segfault.patch b/SOURCES/rsyslog-8.24.0-rhbz1744682-ratelimiter-segfault.patch new file mode 100644 index 0000000..6089930 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1744682-ratelimiter-segfault.patch @@ -0,0 +1,41 @@ +From b54769b4d8371ce1d60e3c43172a445336ec79b6 Mon Sep 17 00:00:00 2001 +From: Rainer Gerhards +Date: Mon, 24 Sep 2018 13:27:26 +0200 +Subject: [PATCH] bugfix imfile: segfault in ratelimiter + +imfile crashes inside rate limit processing, often when log +files are rotated. However, this could occur in any case where +the monitored files was closed by imfile, it rotation is just +the most probable cause for this (moving the file to another +directory or deleting it also can trigger the same issue, for +example). The root cause was invalid sequence of operations. + +closes https://github.com/rsyslog/rsyslog/issues/3021 +--- + plugins/imfile/imfile.c | 8 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c +index e710f7c44c..f4a4ef9b72 100644 +--- a/plugins/imfile/imfile.c ++++ b/plugins/imfile/imfile.c +@@ -915,9 +915,6 @@ act_obj_destroy(act_obj_t *const act, const int is_deleted) + } + } + } +- if(act->ratelimiter != NULL) { +- ratelimitDestruct(act->ratelimiter); +- } + if(act->pStrm != NULL) { + const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances? + pollFile(act); /* get any left-over data */ +@@ -934,6 +931,9 @@ act_obj_destroy(act_obj_t *const act, const int is_deleted) + unlink((char*)statefn); + } + } ++ if(act->ratelimiter != NULL) { ++ ratelimitDestruct(act->ratelimiter); ++ } + #ifdef HAVE_INOTIFY_INIT + if(act->wd != -1) { + wdmapDel(act->wd); diff --git a/SOURCES/rsyslog-8.24.0-rhbz1746497-ratelimiter-segfault.patch b/SOURCES/rsyslog-8.24.0-rhbz1746497-ratelimiter-segfault.patch deleted file mode 100644 index 6089930..0000000 --- a/SOURCES/rsyslog-8.24.0-rhbz1746497-ratelimiter-segfault.patch +++ /dev/null @@ -1,41 +0,0 @@ -From b54769b4d8371ce1d60e3c43172a445336ec79b6 Mon Sep 17 00:00:00 2001 -From: Rainer Gerhards -Date: Mon, 24 Sep 2018 13:27:26 +0200 -Subject: [PATCH] bugfix imfile: segfault in ratelimiter - -imfile crashes inside rate limit processing, often when log -files are rotated. However, this could occur in any case where -the monitored files was closed by imfile, it rotation is just -the most probable cause for this (moving the file to another -directory or deleting it also can trigger the same issue, for -example). The root cause was invalid sequence of operations. - -closes https://github.com/rsyslog/rsyslog/issues/3021 ---- - plugins/imfile/imfile.c | 8 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c -index e710f7c44c..f4a4ef9b72 100644 ---- a/plugins/imfile/imfile.c -+++ b/plugins/imfile/imfile.c -@@ -915,9 +915,6 @@ act_obj_destroy(act_obj_t *const act, const int is_deleted) - } - } - } -- if(act->ratelimiter != NULL) { -- ratelimitDestruct(act->ratelimiter); -- } - if(act->pStrm != NULL) { - const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances? - pollFile(act); /* get any left-over data */ -@@ -934,6 +931,9 @@ act_obj_destroy(act_obj_t *const act, const int is_deleted) - unlink((char*)statefn); - } - } -+ if(act->ratelimiter != NULL) { -+ ratelimitDestruct(act->ratelimiter); -+ } - #ifdef HAVE_INOTIFY_INIT - if(act->wd != -1) { - wdmapDel(act->wd); diff --git a/SOURCES/rsyslog-8.24.0-rhbz1763746-file-id.patch b/SOURCES/rsyslog-8.24.0-rhbz1763746-file-id.patch new file mode 100644 index 0000000..2238bfc --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1763746-file-id.patch @@ -0,0 +1,602 @@ +From 70ea76962bfe9ffed2bd604898e43e0e3b17645d Mon Sep 17 00:00:00 2001 +From: Rainer Gerhards +Date: Thu, 23 Aug 2018 10:15:21 +0200 +Subject: [PATCH] omfile: implement file-id, used in state file + +This ensures that files with the same inodes are not accidently treated +as equal, at least within the limits of the file id hash (see doc for +details). + +We use the siphash reference implementation to generate our non-cryptographic +hash. + +State file handling was invalid. When a file was moved and re-created +rsyslog could use the file_id if the new file to write the old files' +state file. This could make the file reader stuck until it reached the +previous offset. Depending on file sizes this could never happen AND +would cause large message loss. This situation was timing dependent +(a race) and most frequently occurred under log rotation. In polling +mode the bug was less likely, but could also occur. +--- + plugins/imfile/Makefile.am | 2 +- + plugins/imfile/imfile.c | 190 ++++++++++++++++++----- + plugins/imfile/siphash.c | 185 ++++++++++++++++++++++++++++++++ + 3 files changed, 381 insertions(+), 19 deletions(-) + create mode 100644 plugins/imfile/siphash.c + +diff --git a/plugins/imfile/Makefile.am b/plugins/imfile/Makefile.am +index f4df0ed687..9e137efdc8 100644 +--- a/plugins/imfile/Makefile.am ++++ b/plugins/imfile/Makefile.am +@@ -1,6 +1,6 @@ + pkglib_LTLIBRARIES = imfile.la + +-imfile_la_SOURCES = imfile.c ++imfile_la_SOURCES = imfile.c siphash.c + imfile_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) + imfile_la_LDFLAGS = -module -avoid-version + imfile_la_LIBADD = +diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c +index 4bc6078bda..14f4f1f495 100644 +--- a/plugins/imfile/imfile.c ++++ b/plugins/imfile/imfile.c +@@ -66,6 +66,8 @@ + MODULE_CNFNAME("imfile") + + /* defines */ ++#define FILE_ID_HASH_SIZE 20 /* max size of a file_id hash */ ++#define FILE_ID_SIZE 512 /* how many bytes are used for file-id? */ + + /* Module static data */ + DEF_IMOD_STATIC_DATA /* must be present, starts static data */ +@@ -75,6 +77,9 @@ + DEFobjCurrIf(prop) + DEFobjCurrIf(ruleset) + ++extern int rs_siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, ++ uint8_t *out, const size_t outlen); /* see siphash.c */ ++ + static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ + + #define NUM_MULTISUB 1024 /* default max number of submits */ +@@ -155,8 +160,10 @@ + int wd; + time_t timeoutBase; /* what time to calculate the timeout against? */ + /* file dynamic data */ ++ char file_id[FILE_ID_HASH_SIZE]; /* file id for this entry, once we could obtain it */ + int in_move; /* workaround for inotify move: if set, state file must not be deleted */ + ino_t ino; /* current inode nbr */ ++ int fd; /* fd to file in order to obtain file_id (needs to be preserved across move) */ + strm_t *pStrm; /* its stream (NULL if not assigned) */ + int nRecords; /**< How many records did we process before persisting the stream? */ + ratelimit_t *ratelimiter; +@@ -187,7 +194,7 @@ + static int getBasename(uchar *const __restrict__ basen, uchar *const __restrict__ path); + static void act_obj_unlink(act_obj_t *act); + static uchar * getStateFileName(const act_obj_t *, uchar *, const size_t); +-static int getFullStateFileName(const uchar *const, uchar *const pszout, const size_t ilenout); ++static int getFullStateFileName(const uchar *const, const char *const, uchar *const pszout, const size_t ilenout); + + + #define OPMODE_POLLING 0 +@@ -328,7 +335,7 @@ + act->name, statefn); + + /* Get full path and file name */ +- lenSFNam = getFullStateFileName(statefn, pszSFNam, sizeof(pszSFNam)); ++ lenSFNam = getFullStateFileName(statefn, "", pszSFNam, sizeof(pszSFNam)); + + /* check if the file exists */ + if(stat((char*) pszSFNam, &stat_buf) == -1) { +@@ -561,16 +568,25 @@ + } + } + } ++ DBGPRINTF("need to add new active object '%s' in '%s' - checking if accessible\n", name, edge->path); ++ const int fd = open(name, O_RDONLY | O_CLOEXEC); ++ if(fd < 0) { ++ if (is_file) { LogMsg(errno, RS_RET_ERR, LOG_WARNING, "imfile: error accessing file '%s'", name); ++ } else { DBGPRINTF("imfile: error accessing file '%s'", name); } ++ FINALIZE; ++ } + DBGPRINTF("add new active object '%s' in '%s'\n", name, edge->path); + CHKmalloc(act = calloc(sizeof(act_obj_t), 1)); + CHKmalloc(act->name = strdup(name)); +- if (-1 == getBasename((uchar*)basename, (uchar*)name)) { +- CHKmalloc(act->basename = strdup(name)); /* assume basename is same as name */ +- } else { +- CHKmalloc(act->basename = strdup(basename)); +- } ++ if (-1 == getBasename((uchar*)basename, (uchar*)name)) { ++ CHKmalloc(act->basename = strdup(name)); /* assume basename is same as name */ ++ } else { ++ CHKmalloc(act->basename = strdup(basename)); ++ } + act->edge = edge; + act->ino = ino; ++ act->fd = fd; ++ act->file_id[0] = '\0'; + act->is_symlink = is_symlink; + if (source) { /* we are target of symlink */ + CHKmalloc(act->source_name = strdup(source)); +@@ -813,7 +828,7 @@ + pollFile(act); /* get any left-over data */ + if(inst->bRMStateOnDel) { + statefn = getStateFileName(act, statefile, sizeof(statefile)); +- getFullStateFileName(statefn, toDel, sizeof(toDel)); ++ getFullStateFileName(statefn, "", toDel, sizeof(toDel)); // TODO: check! + statefn = toDel; + } + persistStrmState(act); +@@ -832,6 +847,9 @@ + wdmapDel(act->wd); + } + #endif ++ if(act->fd >= 0) { ++ close(act->fd); ++ } + #if defined(OS_SOLARIS) && defined (HAVE_PORT_SOURCE_FILE) + if(act->pfinf != NULL) { + free(act->pfinf->fobj.fo_name); +@@ -1029,7 +1047,7 @@ + * open or otherwise modify disk file state. + */ + static int +-getFullStateFileName(const uchar *const pszstatefile, uchar *const pszout, const size_t ilenout) ++getFullStateFileName(const uchar *const pszstatefile, const char *const file_id, uchar *const pszout, const size_t ilenout) + { + int lenout; + const uchar* pszworkdir; +@@ -1038,14 +1056,69 @@ + pszworkdir = glblGetWorkDirRaw(); + + /* Construct file name */ +- lenout = snprintf((char*)pszout, ilenout, "%s/%s", +- (char*) (pszworkdir == NULL ? "." : (char*) pszworkdir), (char*)pszstatefile); ++ lenout = snprintf((char*)pszout, ilenout, "%s/%s%s%s", ++ (char*) (pszworkdir == NULL ? "." : (char*) pszworkdir), (char*)pszstatefile, ++ (*file_id == '\0') ? "" : ":", file_id); + + /* return out length */ + return lenout; + } + + ++/* hash function for file-id ++ * Takes a block of data and returns a string with the hash value. ++ * ++ * Currently one provided by Aaaron Wiebe based on perl's hashing algorithm ++ * (so probably pretty generic). Not for excessively large strings! ++ * TODO: re-think the hash function! ++ */ ++#if defined(__clang__) ++#pragma GCC diagnostic ignored "-Wunknown-attributes" ++#endif ++static void __attribute__((nonnull(1,3))) ++#if defined(__clang__) ++__attribute__((no_sanitize("unsigned-integer-overflow"))) ++#endif ++get_file_id_hash(const char *data, size_t lendata, ++ char *const hash_str, const size_t len_hash_str) ++{ ++ assert(len_hash_str >= 17); /* we always generate 8-byte strings */ ++ ++ size_t i; ++ uint8_t out[8], k[16]; ++ for (i = 0; i < 16; ++i) ++ k[i] = i; ++ memset(out, 0, sizeof(out)); ++ rs_siphash((const uint8_t *)data, lendata, k, out, 8); ++ ++ for(i = 0 ; i < 8 ; ++i) { ++ if(2 * i+1 >= len_hash_str) ++ break; ++ snprintf(hash_str+(2*i), 3, "%2.2x", out[i]); ++ } ++} ++ ++ ++ ++/* this returns the file-id for a given file ++ */ ++static void getFileID(act_obj_t *const act) ++{ ++ /* save the old id for cleaning purposes */ ++ strncpy(act->file_id_prev, (const char*)act->file_id, FILE_ID_HASH_SIZE); ++ act->file_id[0] = '\0'; ++ assert(act->fd >= 0); /* fd must have been opened at act_obj_t creation! */ ++ char filedata[FILE_ID_SIZE]; ++ lseek(act->fd, 0, SEEK_SET); /* Seek to beginning of file so we have correct id */ ++ const int r = read(act->fd, filedata, FILE_ID_SIZE); ++ if(r == FILE_ID_SIZE) { ++ get_file_id_hash(filedata, sizeof(filedata), act->file_id, sizeof(act->file_id)); ++ } else { ++ DBGPRINTF("getFileID partial or error read, ret %d\n", r); ++ } ++ DBGPRINTF("getFileID for '%s', file_id_hash '%s'\n", act->name, act->file_id); ++} ++ + /* this generates a state file name suitable for the given file. To avoid + * malloc calls, it must be passed a buffer which should be MAXFNAME large. + * Note: the buffer is not necessarily populated ... always ONLY use the +@@ -1060,7 +1135,7 @@ + { + DBGPRINTF("getStateFileName for '%s'\n", act->name); + snprintf((char*)buf, lenbuf - 1, "imfile-state:%lld", (long long) act->ino); +- DBGPRINTF("getStateFileName: stat file name now is %s\n", buf); ++ DBGPRINTF("getStateFileName: state file name now is %s\n", buf); + return buf; + } + +@@ -1136,18 +1209,45 @@ + const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances? + + uchar *const statefn = getStateFileName(act, statefile, sizeof(statefile)); ++ getFileID(act); + +- getFullStateFileName(statefn, pszSFNam, sizeof(pszSFNam)); ++ getFullStateFileName(statefn, act->file_id, pszSFNam, sizeof(pszSFNam)); + DBGPRINTF("trying to open state for '%s', state file '%s'\n", act->name, pszSFNam); + + /* check if the file exists */ + fd = open((char*)pszSFNam, O_CLOEXEC | O_NOCTTY | O_RDONLY, 0600); + if(fd < 0) { + if(errno == ENOENT) { +- DBGPRINTF("NO state file (%s) exists for '%s' - trying to see if " +- "old-style file exists\n", pszSFNam, act->name); +- CHKiRet(OLD_openFileWithStateFile(act)); +- FINALIZE; ++ if(act->file_id[0] != '\0') { ++ const char *pszSFNamHash = strdup((const char*)pszSFNam); ++ CHKmalloc(pszSFNamHash); ++ DBGPRINTF("state file %s for %s does not exist - trying to see if " ++ "inode-only file exists\n", pszSFNam, act->name); ++ getFullStateFileName(statefn, "", pszSFNam, sizeof(pszSFNam)); ++ fd = open((char*)pszSFNam, O_CLOEXEC | O_NOCTTY | O_RDONLY, 0600); ++ if(fd >= 0) { ++ dbgprintf("found inode-only state file, renaming it now that we " ++ "know the file_id, new name: %s\n", pszSFNamHash); ++ /* we now can use identify the file, so let's rename it */ ++ if(rename((const char*)pszSFNam, pszSFNamHash) != 0) { ++ LogError(errno, RS_RET_IO_ERROR, ++ "imfile error trying to rename state file for '%s' - " ++ "ignoring this error, usually this means a file no " ++ "longer file is left over, but this may also cause " ++ "some real trouble. Still the best we can do ", ++ act->name); ++ free((void*) pszSFNamHash); ++ ABORT_FINALIZE(RS_RET_IO_ERROR); ++ } ++ } ++ free((void*) pszSFNamHash); ++ } ++ if(fd < 0) { ++ DBGPRINTF("state file %s for %s does not exist - trying to see if " ++ "old-style file exists\n", pszSFNam, act->name); ++ CHKiRet(OLD_openFileWithStateFile(act)); ++ FINALIZE; ++ } + } else { + LogError(errno, RS_RET_IO_ERROR, + "imfile error trying to access state file for '%s'", +@@ -1156,6 +1256,7 @@ + } + } + ++ DBGPRINTF("opened state file %s for %s\n", pszSFNam, act->name); + CHKiRet(strm.Construct(&act->pStrm)); + + struct json_object *jval; +@@ -1289,6 +1390,7 @@ + { + int64 strtOffs; + DEFiRet; ++ int64_t startOffs = 0; + int nProcessed = 0; + + DBGPRINTF("pollFileReal enter, pStrm %p, name '%s'\n", act->pStrm, act->name); +@@ -1301,6 +1403,7 @@ + CHKiRet(openFile(act)); /* open file */ + } + ++ startOffs = act->pStrm->iCurrOffs; + /* loop below will be exited when strmReadLine() returns EOF */ + while(glbl.GetGlobalInputTermState() == 0) { + if(inst->maxLinesAtOnce != 0 && nProcessed >= inst->maxLinesAtOnce) +@@ -1313,6 +1416,11 @@ + inst->escapeLF, &strtOffs)); + } + ++nProcessed; ++ if(startOffs < FILE_ID_SIZE && act->pStrm->iCurrOffs >= FILE_ID_SIZE) { ++ dbgprintf("initiating state file write as sufficient data is now present; file=%s\n", act->name); ++ persistStrmState(act); ++ startOffs = act->pStrm->iCurrOffs; /* disable check */ ++ } + runModConf->bHadFileData = 1; /* this is just a flag, so set it and forget it */ + CHKiRet(enqLine(act, *pCStr, strtOffs)); /* process line */ + rsCStrDestruct(pCStr); /* discard string (must be done by us!) */ +@@ -2122,7 +2230,8 @@ + uchar statefname[MAXFNAME]; + + uchar *const statefn = getStateFileName(act, statefile, sizeof(statefile)); +- getFullStateFileName(statefn, statefname, sizeof(statefname)); ++ getFileID(act); ++ getFullStateFileName(statefn, act->file_id, statefname, sizeof(statefname)); + DBGPRINTF("persisting state for '%s', state file '%s'\n", act->name, statefname); + + struct json_object *jval = NULL; +diff --git a/plugins/imfile/siphash.c b/plugins/imfile/siphash.c +new file mode 100644 +index 0000000000..8d5fac7343 +--- /dev/null ++++ b/plugins/imfile/siphash.c +@@ -0,0 +1,185 @@ ++/* SipHash reference C implementation ++ * ++ * Copyright (c) 2012-2016 Jean-Philippe Aumasson ++ * ++ * Copyright (c) 2012-2014 Daniel J. Bernstein ++ * ++ * Slightly adapted by rsyslog in regard to build system and code style ++ * check. ++ * ++ * To the extent possible under law, the author(s) have dedicated all copyright ++ * and related and neighboring rights to this software to the public domain ++ * worldwide. This software is distributed without any warranty. ++ * ++ * You should have received a copy of the CC0 Public Domain Dedication along ++ * with ++ * this software. If not, see ++ * . ++ * ++ * For details on siphash see https://131002.net/siphash/ ++ */ ++#include ++#include ++#include ++#include ++ ++/* default: SipHash-2-4 */ ++#define cROUNDS 2 ++#define dROUNDS 4 ++ ++#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) ++ ++#define U32TO8_LE(p, v) \ ++ (p)[0] = (uint8_t)((v)); \ ++ (p)[1] = (uint8_t)((v) >> 8); \ ++ (p)[2] = (uint8_t)((v) >> 16); \ ++ (p)[3] = (uint8_t)((v) >> 24); ++ ++#define U64TO8_LE(p, v) \ ++ U32TO8_LE((p), (uint32_t)((v))); \ ++ U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); ++ ++#define U8TO64_LE(p) \ ++ (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ ++ ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ ++ ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ ++ ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) ++ ++#define SIPROUND \ ++ do { \ ++ v0 += v1; \ ++ v1 = ROTL(v1, 13); \ ++ v1 ^= v0; \ ++ v0 = ROTL(v0, 32); \ ++ v2 += v3; \ ++ v3 = ROTL(v3, 16); \ ++ v3 ^= v2; \ ++ v0 += v3; \ ++ v3 = ROTL(v3, 21); \ ++ v3 ^= v0; \ ++ v2 += v1; \ ++ v1 = ROTL(v1, 17); \ ++ v1 ^= v2; \ ++ v2 = ROTL(v2, 32); \ ++ } while (0) ++ ++#ifdef DEBUG ++#define TRACE \ ++ do { \ ++ printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32), \ ++ (uint32_t)v0); \ ++ printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32), \ ++ (uint32_t)v1); \ ++ printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32), \ ++ (uint32_t)v2); \ ++ printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32), \ ++ (uint32_t)v3); \ ++ } while (0) ++#else ++#define TRACE ++#endif ++ ++extern int rs_siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, ++ uint8_t *out, const size_t outlen); /* avoid compiler warning */ ++#if defined(__clang__) ++#pragma GCC diagnostic ignored "-Wunknown-attributes" ++#endif ++int ++#if defined(__clang__) ++__attribute__((no_sanitize("unsigned-integer-overflow"))) ++#endif ++rs_siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, ++ uint8_t *out, const size_t outlen) { ++ ++ uint64_t v0 = 0x736f6d6570736575ULL; ++ uint64_t v1 = 0x646f72616e646f6dULL; ++ uint64_t v2 = 0x6c7967656e657261ULL; ++ uint64_t v3 = 0x7465646279746573ULL; ++ uint64_t k0 = U8TO64_LE(k); ++ uint64_t k1 = U8TO64_LE(k + 8); ++ uint64_t m; ++ int i; ++ const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); ++ const int left = inlen & 7; ++ uint64_t b = ((uint64_t)inlen) << 56; ++ assert((outlen == 8) || (outlen == 16)); ++ v3 ^= k1; ++ v2 ^= k0; ++ v1 ^= k1; ++ v0 ^= k0; ++ ++ if (outlen == 16) ++ v1 ^= 0xee; ++ ++ for (; in != end; in += 8) { ++ m = U8TO64_LE(in); ++ v3 ^= m; ++ ++ TRACE; ++ for (i = 0; i < cROUNDS; ++i) ++ SIPROUND; ++ ++ v0 ^= m; ++ } ++ ++ switch (left) { ++ case 7: ++ b |= ((uint64_t)in[6]) << 48; ++ /*FALLTHROUGH*/ ++ case 6: ++ b |= ((uint64_t)in[5]) << 40; ++ /*FALLTHROUGH*/ ++ case 5: ++ b |= ((uint64_t)in[4]) << 32; ++ /*FALLTHROUGH*/ ++ case 4: ++ b |= ((uint64_t)in[3]) << 24; ++ /*FALLTHROUGH*/ ++ case 3: ++ b |= ((uint64_t)in[2]) << 16; ++ /*FALLTHROUGH*/ ++ case 2: ++ b |= ((uint64_t)in[1]) << 8; ++ /*FALLTHROUGH*/ ++ case 1: ++ b |= ((uint64_t)in[0]); ++ break; ++ case 0: ++ default: ++ break; ++ } ++ ++ v3 ^= b; ++ ++ TRACE; ++ for (i = 0; i < cROUNDS; ++i) ++ SIPROUND; ++ ++ v0 ^= b; ++ ++ if (outlen == 16) ++ v2 ^= 0xee; ++ else ++ v2 ^= 0xff; ++ ++ TRACE; ++ for (i = 0; i < dROUNDS; ++i) ++ SIPROUND; ++ ++ b = v0 ^ v1 ^ v2 ^ v3; ++ U64TO8_LE(out, b); ++ ++ if (outlen == 8) ++ return 0; ++ ++ v1 ^= 0xdd; ++ ++ TRACE; ++ for (i = 0; i < dROUNDS; ++i) ++ SIPROUND; ++ ++ b = v0 ^ v1 ^ v2 ^ v3; ++ U64TO8_LE(out + 8, b); ++ ++ return 0; ++} +--- a/plugins/imfile/imfile.c ++++ b/plugins/imfile/imfile.c +@@ -182,6 +182,7 @@ struct act_obj_s { + time_t timeoutBase; /* what time to calculate the timeout against? */ + /* file dynamic data */ + char file_id[FILE_ID_HASH_SIZE]; /* file id for this entry, once we could obtain it */ ++ char file_id_prev[FILE_ID_HASH_SIZE]; /* previous file id for this entry, set if changed */ + int in_move; /* workaround for inotify move: if set, state file must not be deleted */ + ino_t ino; /* current inode nbr */ + int fd; /* fd to file in order to obtain file_id (needs to be preserved across move) */ +@@ -727,6 +728,7 @@ act_obj_add(fs_edge_t *const edge, const char *const name, const int is_file, + act->ino = ino; + act->fd = fd; + act->file_id[0] = '\0'; ++ act->file_id_prev[0] = '\0'; + act->is_symlink = is_symlink; + if (source) { /* we are target of symlink */ + CHKmalloc(act->source_name = strdup(source)); +@@ -1378,28 +1380,13 @@ openFileWithStateFile(act_obj_t *const act) + if(fd < 0) { + if(errno == ENOENT) { + if(act->file_id[0] != '\0') { +- const char *pszSFNamHash = strdup((const char*)pszSFNam); +- CHKmalloc(pszSFNamHash); + DBGPRINTF("state file %s for %s does not exist - trying to see if " + "inode-only file exists\n", pszSFNam, act->name); + getFullStateFileName(statefn, "", pszSFNam, sizeof(pszSFNam)); + fd = open((char*)pszSFNam, O_CLOEXEC | O_NOCTTY | O_RDONLY, 0600); + if(fd >= 0) { +- dbgprintf("found inode-only state file, renaming it now that we " +- "know the file_id, new name: %s\n", pszSFNamHash); +- /* we now can use identify the file, so let's rename it */ +- if(rename((const char*)pszSFNam, pszSFNamHash) != 0) { +- LogError(errno, RS_RET_IO_ERROR, +- "imfile error trying to rename state file for '%s' - " +- "ignoring this error, usually this means a file no " +- "longer file is left over, but this may also cause " +- "some real trouble. Still the best we can do ", +- act->name); +- free((void*) pszSFNamHash); +- ABORT_FINALIZE(RS_RET_IO_ERROR); +- } ++ dbgprintf("found inode-only state file, will be renamed at next persist\n"); + } +- free((void*) pszSFNamHash); + } + if(fd < 0) { + DBGPRINTF("state file %s for %s does not exist - trying to see if " +@@ -2609,6 +2596,24 @@ atomicWriteStateFile(const char *fn, const char *content) + RETiRet; + } + ++static void ++removeOldStatefile(const uchar *statefn, const char *hashToDelete) ++{ ++ int ret; ++ uchar statefname[MAXFNAME]; ++ ++ getFullStateFileName(statefn, hashToDelete, statefname, sizeof(statefname)); ++ DBGPRINTF("removing old state file: '%s'\n", statefname); ++ ret = unlink((const char*)statefname); ++ if(ret != 0 && errno != ENOENT) { ++ LogError(errno, RS_RET_IO_ERROR, ++ "imfile error trying to delete old state file: '%s' - ignoring this " ++ "error, usually this means a file no longer file is left over, but " ++ "this may also cause some real trouble. Still the best we can do ", ++ statefname); ++ } ++} ++ + + /* This function persists information for a specific file being monitored. + * To do so, it simply persists the stream object. We do NOT abort on error +@@ -2660,6 +2664,10 @@ persistStrmState(act_obj_t *const act) + CHKiRet(atomicWriteStateFile((const char*)statefname, jstr)); + json_object_put(json); + ++ if (strncmp((const char *)act->file_id_prev, (const char *)act->file_id, FILE_ID_HASH_SIZE)) { ++ removeOldStatefile(statefn, act->file_id_prev); ++ } ++ + finalize_it: + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "imfile: could not persist state " diff --git a/SOURCES/rsyslog-8.24.0-rhbz1768320-pmaixfw-CVE.patch b/SOURCES/rsyslog-8.24.0-rhbz1768320-pmaixfw-CVE.patch new file mode 100644 index 0000000..2f5d5c1 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1768320-pmaixfw-CVE.patch @@ -0,0 +1,36 @@ +From 10549ba915556c557b22b3dac7e4cb73ad22d3d8 Mon Sep 17 00:00:00 2001 +From: Rainer Gerhards +Date: Fri, 27 Sep 2019 13:36:02 +0200 +Subject: [PATCH] pmaixforwardedfrom bugfix: potential misadressing + +--- + contrib/pmaixforwardedfrom/pmaixforwardedfrom.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/contrib/pmaixforwardedfrom/pmaixforwardedfrom.c b/contrib/pmaixforwardedfrom/pmaixforwardedfrom.c +index 37157c7d4a..ebf12ebbef 100644 +--- a/contrib/pmaixforwardedfrom/pmaixforwardedfrom.c ++++ b/contrib/pmaixforwardedfrom/pmaixforwardedfrom.c +@@ -109,6 +109,10 @@ CODESTARTparse + } + /* bump the message portion up by skipLen(23 or 5) characters to overwrite the "Message forwarded from " or "From " with the hostname */ + lenMsg -=skipLen; ++ if(lenMsg < 2) { ++ dbgprintf("not a AIX message forwarded from message has nothing after header\n"); ++ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE); ++ } + memmove(p2parse, p2parse + skipLen, lenMsg); + *(p2parse + lenMsg) = '\n'; + *(p2parse + lenMsg + 1) = '\0'; +@@ -120,6 +124,11 @@ really an AIX log, but has a similar preamble */ + --lenMsg; + ++p2parse; + } ++ if (lenMsg < 1) { ++ dbgprintf("not a AIX message forwarded from message has nothing after colon " ++ "or no colon at all\n"); ++ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE); ++ } + if (lenMsg && *p2parse != ':') { + DBGPRINTF("not a AIX message forwarded from mangled log but similar enough that the preamble has been removed\n"); + ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE); diff --git a/SOURCES/rsyslog-8.24.0-rhbz1768323-pmcisco-CVE.patch b/SOURCES/rsyslog-8.24.0-rhbz1768323-pmcisco-CVE.patch new file mode 100644 index 0000000..bc14c9a --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1768323-pmcisco-CVE.patch @@ -0,0 +1,34 @@ +From abc0960a7561e18944a0e08d48f4eb570ea7435a Mon Sep 17 00:00:00 2001 +From: Rainer Gerhards +Date: Fri, 27 Sep 2019 15:02:52 +0200 +Subject: [PATCH] pmcisconames bugfix: potential misadressing + +--- + contrib/pmcisconames/pmcisconames.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/contrib/pmcisconames/pmcisconames.c b/contrib/pmcisconames/pmcisconames.c +index 7f376ad170..39506ce592 100644 +--- a/contrib/pmcisconames/pmcisconames.c ++++ b/contrib/pmcisconames/pmcisconames.c +@@ -119,6 +119,11 @@ CODESTARTparse + --lenMsg; + ++p2parse; + } ++ /* Note: we deliberately count the 0-byte below because we need to go chars+1! */ ++ if(lenMsg < (int) sizeof(OpeningText)) { ++ dbgprintf("pmcisconames: too short for being cisco messages\n"); ++ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE); ++ } + /* skip the space after the hostname */ + lenMsg -=1; + p2parse +=1; +@@ -126,7 +131,7 @@ CODESTARTparse + /* if the syslog tag is : and the next thing starts with a % assume that this is a mangled cisco log and fix it */ + if(strncasecmp((char*) p2parse, OpeningText, sizeof(OpeningText)-1) != 0) { + /* wrong opening text */ +- DBGPRINTF("not a cisco name mangled log!\n"); ++ DBGPRINTF("not a cisco name mangled log!\n"); + ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE); + } + /* bump the message portion up by two characters to overwrite the extra : */ diff --git a/SOURCES/rsyslog-8.24.0-rhbz1805675-file-id.patch b/SOURCES/rsyslog-8.24.0-rhbz1805675-file-id.patch deleted file mode 100644 index 4843de4..0000000 --- a/SOURCES/rsyslog-8.24.0-rhbz1805675-file-id.patch +++ /dev/null @@ -1,610 +0,0 @@ -From 70ea76962bfe9ffed2bd604898e43e0e3b17645d Mon Sep 17 00:00:00 2001 -From: Rainer Gerhards -Date: Thu, 23 Aug 2018 10:15:21 +0200 -Subject: [PATCH] omfile: implement file-id, used in state file - -This ensures that files with the same inodes are not accidently treated -as equal, at least within the limits of the file id hash (see doc for -details). - -We use the siphash reference implementation to generate our non-cryptographic -hash. - -State file handling was invalid. When a file was moved and re-created -rsyslog could use the file_id if the new file to write the old files' -state file. This could make the file reader stuck until it reached the -previous offset. Depending on file sizes this could never happen AND -would cause large message loss. This situation was timing dependent -(a race) and most frequently occurred under log rotation. In polling -mode the bug was less likely, but could also occur. ---- - plugins/imfile/Makefile.am | 2 +- - plugins/imfile/imfile.c | 190 ++++++++++++++++++----- - plugins/imfile/siphash.c | 185 ++++++++++++++++++++++++++++++++ - 3 files changed, 381 insertions(+), 19 deletions(-) - create mode 100644 plugins/imfile/siphash.c - -diff --git a/plugins/imfile/Makefile.am b/plugins/imfile/Makefile.am -index f4df0ed687..9e137efdc8 100644 ---- a/plugins/imfile/Makefile.am -+++ b/plugins/imfile/Makefile.am -@@ -1,6 +1,6 @@ - pkglib_LTLIBRARIES = imfile.la - --imfile_la_SOURCES = imfile.c -+imfile_la_SOURCES = imfile.c siphash.c - imfile_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) - imfile_la_LDFLAGS = -module -avoid-version - imfile_la_LIBADD = -diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c -index 4bc6078bda..14f4f1f495 100644 ---- a/plugins/imfile/imfile.c -+++ b/plugins/imfile/imfile.c -@@ -66,6 +66,8 @@ - MODULE_CNFNAME("imfile") - - /* defines */ -+#define FILE_ID_HASH_SIZE 20 /* max size of a file_id hash */ -+#define FILE_ID_SIZE 512 /* how many bytes are used for file-id? */ - - /* Module static data */ - DEF_IMOD_STATIC_DATA /* must be present, starts static data */ -@@ -75,6 +77,9 @@ - DEFobjCurrIf(prop) - DEFobjCurrIf(ruleset) - -+extern int rs_siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, -+ uint8_t *out, const size_t outlen); /* see siphash.c */ -+ - static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ - - #define NUM_MULTISUB 1024 /* default max number of submits */ -@@ -155,8 +160,10 @@ - int wd; - time_t timeoutBase; /* what time to calculate the timeout against? */ - /* file dynamic data */ -+ char file_id[FILE_ID_HASH_SIZE]; /* file id for this entry, once we could obtain it */ - int in_move; /* workaround for inotify move: if set, state file must not be deleted */ - ino_t ino; /* current inode nbr */ -+ int fd; /* fd to file in order to obtain file_id (needs to be preserved across move) */ - strm_t *pStrm; /* its stream (NULL if not assigned) */ - int nRecords; /**< How many records did we process before persisting the stream? */ - ratelimit_t *ratelimiter; -@@ -187,7 +194,7 @@ - static int getBasename(uchar *const __restrict__ basen, uchar *const __restrict__ path); - static void act_obj_unlink(act_obj_t *act); - static uchar * getStateFileName(const act_obj_t *, uchar *, const size_t); --static int getFullStateFileName(const uchar *const, uchar *const pszout, const size_t ilenout); -+static int getFullStateFileName(const uchar *const, const char *const, uchar *const pszout, const size_t ilenout); - - - #define OPMODE_POLLING 0 -@@ -328,7 +335,7 @@ - act->name, statefn); - - /* Get full path and file name */ -- lenSFNam = getFullStateFileName(statefn, pszSFNam, sizeof(pszSFNam)); -+ lenSFNam = getFullStateFileName(statefn, "", pszSFNam, sizeof(pszSFNam)); - - /* check if the file exists */ - if(stat((char*) pszSFNam, &stat_buf) == -1) { -@@ -561,16 +568,25 @@ - } - } - } -+ DBGPRINTF("need to add new active object '%s' in '%s' - checking if accessible\n", name, edge->path); -+ const int fd = open(name, O_RDONLY | O_CLOEXEC); -+ if(fd < 0) { -+ if (is_file) { LogMsg(errno, RS_RET_ERR, LOG_WARNING, "imfile: error accessing file '%s'", name); -+ } else { DBGPRINTF("imfile: error accessing file '%s'", name); } -+ FINALIZE; -+ } - DBGPRINTF("add new active object '%s' in '%s'\n", name, edge->path); - CHKmalloc(act = calloc(sizeof(act_obj_t), 1)); - CHKmalloc(act->name = strdup(name)); -- if (-1 == getBasename((uchar*)basename, (uchar*)name)) { -- CHKmalloc(act->basename = strdup(name)); /* assume basename is same as name */ -- } else { -- CHKmalloc(act->basename = strdup(basename)); -- } -+ if (-1 == getBasename((uchar*)basename, (uchar*)name)) { -+ CHKmalloc(act->basename = strdup(name)); /* assume basename is same as name */ -+ } else { -+ CHKmalloc(act->basename = strdup(basename)); -+ } - act->edge = edge; - act->ino = ino; -+ act->fd = fd; -+ act->file_id[0] = '\0'; - act->is_symlink = is_symlink; - if (source) { /* we are target of symlink */ - CHKmalloc(act->source_name = strdup(source)); -@@ -813,7 +828,7 @@ - pollFile(act); /* get any left-over data */ - if(inst->bRMStateOnDel) { - statefn = getStateFileName(act, statefile, sizeof(statefile)); -- getFullStateFileName(statefn, toDel, sizeof(toDel)); -+ getFullStateFileName(statefn, "", toDel, sizeof(toDel)); // TODO: check! - statefn = toDel; - } - persistStrmState(act); -@@ -832,6 +847,9 @@ - wdmapDel(act->wd); - } - #endif -+ if(act->fd >= 0) { -+ close(act->fd); -+ } - #if defined(OS_SOLARIS) && defined (HAVE_PORT_SOURCE_FILE) - if(act->pfinf != NULL) { - free(act->pfinf->fobj.fo_name); -@@ -1029,7 +1047,7 @@ - * open or otherwise modify disk file state. - */ - static int --getFullStateFileName(const uchar *const pszstatefile, uchar *const pszout, const size_t ilenout) -+getFullStateFileName(const uchar *const pszstatefile, const char *const file_id, uchar *const pszout, const size_t ilenout) - { - int lenout; - const uchar* pszworkdir; -@@ -1038,14 +1056,68 @@ - pszworkdir = glblGetWorkDirRaw(); - - /* Construct file name */ -- lenout = snprintf((char*)pszout, ilenout, "%s/%s", -- (char*) (pszworkdir == NULL ? "." : (char*) pszworkdir), (char*)pszstatefile); -+ lenout = snprintf((char*)pszout, ilenout, "%s/%s%s%s", -+ (char*) (pszworkdir == NULL ? "." : (char*) pszworkdir), (char*)pszstatefile, -+ (*file_id == '\0') ? "" : ":", file_id); - - /* return out length */ - return lenout; - } - - -+/* hash function for file-id -+ * Takes a block of data and returns a string with the hash value. -+ * -+ * Currently one provided by Aaaron Wiebe based on perl's hashing algorithm -+ * (so probably pretty generic). Not for excessively large strings! -+ * TODO: re-think the hash function! -+ */ -+#if defined(__clang__) -+#pragma GCC diagnostic ignored "-Wunknown-attributes" -+#endif -+static void __attribute__((nonnull(1,3))) -+#if defined(__clang__) -+__attribute__((no_sanitize("unsigned-integer-overflow"))) -+#endif -+get_file_id_hash(const char *data, size_t lendata, -+ char *const hash_str, const size_t len_hash_str) -+{ -+ assert(len_hash_str >= 17); /* we always generate 8-byte strings */ -+ -+ size_t i; -+ uint8_t out[8], k[16]; -+ for (i = 0; i < 16; ++i) -+ k[i] = i; -+ memset(out, 0, sizeof(out)); -+ rs_siphash((const uint8_t *)data, lendata, k, out, 8); -+ -+ for(i = 0 ; i < 8 ; ++i) { -+ if(2 * i+1 >= len_hash_str) -+ break; -+ snprintf(hash_str+(2*i), 3, "%2.2x", out[i]); -+ } -+} -+ -+ -+ -+/* this returns the file-id for a given file -+ */ -+static void getFileID(act_obj_t *const act) -+{ -+ /* save the old id for cleaning purposes */ -+ strncpy(act->file_id_prev, (const char*)act->file_id, FILE_ID_HASH_SIZE); -+ act->file_id[0] = '\0'; -+ assert(act->fd >= 0); /* fd must have been opened at act_obj_t creation! */ -+ char filedata[FILE_ID_SIZE]; -+ const int r = read(act->fd, filedata, FILE_ID_SIZE); -+ if(r == FILE_ID_SIZE) { -+ get_file_id_hash(filedata, sizeof(filedata), act->file_id, sizeof(act->file_id)); -+ } else { -+ DBGPRINTF("getFileID partial or error read, ret %d\n", r); -+ } -+ DBGPRINTF("getFileID for '%s', file_id_hash '%s'\n", act->name, act->file_id); -+} -+ - /* this generates a state file name suitable for the given file. To avoid - * malloc calls, it must be passed a buffer which should be MAXFNAME large. - * Note: the buffer is not necessarily populated ... always ONLY use the -@@ -1060,7 +1135,7 @@ - { - DBGPRINTF("getStateFileName for '%s'\n", act->name); - snprintf((char*)buf, lenbuf - 1, "imfile-state:%lld", (long long) act->ino); -- DBGPRINTF("getStateFileName: stat file name now is %s\n", buf); -+ DBGPRINTF("getStateFileName: state file name now is %s\n", buf); - return buf; - } - -@@ -1136,18 +1209,45 @@ - const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances? - - uchar *const statefn = getStateFileName(act, statefile, sizeof(statefile)); -+ getFileID(act); - -- getFullStateFileName(statefn, pszSFNam, sizeof(pszSFNam)); -+ getFullStateFileName(statefn, act->file_id, pszSFNam, sizeof(pszSFNam)); - DBGPRINTF("trying to open state for '%s', state file '%s'\n", act->name, pszSFNam); - - /* check if the file exists */ - fd = open((char*)pszSFNam, O_CLOEXEC | O_NOCTTY | O_RDONLY, 0600); - if(fd < 0) { - if(errno == ENOENT) { -- DBGPRINTF("NO state file (%s) exists for '%s' - trying to see if " -- "old-style file exists\n", pszSFNam, act->name); -- CHKiRet(OLD_openFileWithStateFile(act)); -- FINALIZE; -+ if(act->file_id[0] != '\0') { -+ const char *pszSFNamHash = strdup((const char*)pszSFNam); -+ CHKmalloc(pszSFNamHash); -+ DBGPRINTF("state file %s for %s does not exist - trying to see if " -+ "inode-only file exists\n", pszSFNam, act->name); -+ getFullStateFileName(statefn, "", pszSFNam, sizeof(pszSFNam)); -+ fd = open((char*)pszSFNam, O_CLOEXEC | O_NOCTTY | O_RDONLY, 0600); -+ if(fd >= 0) { -+ dbgprintf("found inode-only state file, renaming it now that we " -+ "know the file_id, new name: %s\n", pszSFNamHash); -+ /* we now can use identify the file, so let's rename it */ -+ if(rename((const char*)pszSFNam, pszSFNamHash) != 0) { -+ LogError(errno, RS_RET_IO_ERROR, -+ "imfile error trying to rename state file for '%s' - " -+ "ignoring this error, usually this means a file no " -+ "longer file is left over, but this may also cause " -+ "some real trouble. Still the best we can do ", -+ act->name); -+ free((void*) pszSFNamHash); -+ ABORT_FINALIZE(RS_RET_IO_ERROR); -+ } -+ } -+ free((void*) pszSFNamHash); -+ } -+ if(fd < 0) { -+ DBGPRINTF("state file %s for %s does not exist - trying to see if " -+ "old-style file exists\n", pszSFNam, act->name); -+ CHKiRet(OLD_openFileWithStateFile(act)); -+ FINALIZE; -+ } - } else { - LogError(errno, RS_RET_IO_ERROR, - "imfile error trying to access state file for '%s'", -@@ -1156,6 +1256,7 @@ - } - } - -+ DBGPRINTF("opened state file %s for %s\n", pszSFNam, act->name); - CHKiRet(strm.Construct(&act->pStrm)); - - struct json_object *jval; -@@ -1289,6 +1390,7 @@ - { - int64 strtOffs; - DEFiRet; -+ int64_t startOffs = 0; - int nProcessed = 0; - - DBGPRINTF("pollFileReal enter, pStrm %p, name '%s'\n", act->pStrm, act->name); -@@ -1301,6 +1403,7 @@ - CHKiRet(openFile(act)); /* open file */ - } - -+ startOffs = act->pStrm->iCurrOffs; - /* loop below will be exited when strmReadLine() returns EOF */ - while(glbl.GetGlobalInputTermState() == 0) { - if(inst->maxLinesAtOnce != 0 && nProcessed >= inst->maxLinesAtOnce) -@@ -1313,6 +1416,11 @@ - inst->escapeLF, &strtOffs)); - } - ++nProcessed; -+ if(startOffs < FILE_ID_SIZE && act->pStrm->iCurrOffs >= FILE_ID_SIZE) { -+ dbgprintf("initiating state file write as sufficient data is now present; file=%s\n", act->name); -+ persistStrmState(act); -+ startOffs = act->pStrm->iCurrOffs; /* disable check */ -+ } - runModConf->bHadFileData = 1; /* this is just a flag, so set it and forget it */ - CHKiRet(enqLine(act, *pCStr, strtOffs)); /* process line */ - rsCStrDestruct(pCStr); /* discard string (must be done by us!) */ -@@ -2122,7 +2230,8 @@ - uchar statefname[MAXFNAME]; - - uchar *const statefn = getStateFileName(act, statefile, sizeof(statefile)); -- getFullStateFileName(statefn, statefname, sizeof(statefname)); -+ getFileID(act); -+ getFullStateFileName(statefn, act->file_id, statefname, sizeof(statefname)); - DBGPRINTF("persisting state for '%s', state file '%s'\n", act->name, statefname); - - struct json_object *jval = NULL; -diff --git a/plugins/imfile/siphash.c b/plugins/imfile/siphash.c -new file mode 100644 -index 0000000000..8d5fac7343 ---- /dev/null -+++ b/plugins/imfile/siphash.c -@@ -0,0 +1,185 @@ -+/* SipHash reference C implementation -+ * -+ * Copyright (c) 2012-2016 Jean-Philippe Aumasson -+ * -+ * Copyright (c) 2012-2014 Daniel J. Bernstein -+ * -+ * Slightly adapted by rsyslog in regard to build system and code style -+ * check. -+ * -+ * To the extent possible under law, the author(s) have dedicated all copyright -+ * and related and neighboring rights to this software to the public domain -+ * worldwide. This software is distributed without any warranty. -+ * -+ * You should have received a copy of the CC0 Public Domain Dedication along -+ * with -+ * this software. If not, see -+ * . -+ * -+ * For details on siphash see https://131002.net/siphash/ -+ */ -+#include -+#include -+#include -+#include -+ -+/* default: SipHash-2-4 */ -+#define cROUNDS 2 -+#define dROUNDS 4 -+ -+#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) -+ -+#define U32TO8_LE(p, v) \ -+ (p)[0] = (uint8_t)((v)); \ -+ (p)[1] = (uint8_t)((v) >> 8); \ -+ (p)[2] = (uint8_t)((v) >> 16); \ -+ (p)[3] = (uint8_t)((v) >> 24); -+ -+#define U64TO8_LE(p, v) \ -+ U32TO8_LE((p), (uint32_t)((v))); \ -+ U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); -+ -+#define U8TO64_LE(p) \ -+ (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ -+ ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ -+ ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ -+ ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) -+ -+#define SIPROUND \ -+ do { \ -+ v0 += v1; \ -+ v1 = ROTL(v1, 13); \ -+ v1 ^= v0; \ -+ v0 = ROTL(v0, 32); \ -+ v2 += v3; \ -+ v3 = ROTL(v3, 16); \ -+ v3 ^= v2; \ -+ v0 += v3; \ -+ v3 = ROTL(v3, 21); \ -+ v3 ^= v0; \ -+ v2 += v1; \ -+ v1 = ROTL(v1, 17); \ -+ v1 ^= v2; \ -+ v2 = ROTL(v2, 32); \ -+ } while (0) -+ -+#ifdef DEBUG -+#define TRACE \ -+ do { \ -+ printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32), \ -+ (uint32_t)v0); \ -+ printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32), \ -+ (uint32_t)v1); \ -+ printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32), \ -+ (uint32_t)v2); \ -+ printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32), \ -+ (uint32_t)v3); \ -+ } while (0) -+#else -+#define TRACE -+#endif -+ -+extern int rs_siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, -+ uint8_t *out, const size_t outlen); /* avoid compiler warning */ -+#if defined(__clang__) -+#pragma GCC diagnostic ignored "-Wunknown-attributes" -+#endif -+int -+#if defined(__clang__) -+__attribute__((no_sanitize("unsigned-integer-overflow"))) -+#endif -+rs_siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, -+ uint8_t *out, const size_t outlen) { -+ -+ uint64_t v0 = 0x736f6d6570736575ULL; -+ uint64_t v1 = 0x646f72616e646f6dULL; -+ uint64_t v2 = 0x6c7967656e657261ULL; -+ uint64_t v3 = 0x7465646279746573ULL; -+ uint64_t k0 = U8TO64_LE(k); -+ uint64_t k1 = U8TO64_LE(k + 8); -+ uint64_t m; -+ int i; -+ const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); -+ const int left = inlen & 7; -+ uint64_t b = ((uint64_t)inlen) << 56; -+ assert((outlen == 8) || (outlen == 16)); -+ v3 ^= k1; -+ v2 ^= k0; -+ v1 ^= k1; -+ v0 ^= k0; -+ -+ if (outlen == 16) -+ v1 ^= 0xee; -+ -+ for (; in != end; in += 8) { -+ m = U8TO64_LE(in); -+ v3 ^= m; -+ -+ TRACE; -+ for (i = 0; i < cROUNDS; ++i) -+ SIPROUND; -+ -+ v0 ^= m; -+ } -+ -+ switch (left) { -+ case 7: -+ b |= ((uint64_t)in[6]) << 48; -+ /*FALLTHROUGH*/ -+ case 6: -+ b |= ((uint64_t)in[5]) << 40; -+ /*FALLTHROUGH*/ -+ case 5: -+ b |= ((uint64_t)in[4]) << 32; -+ /*FALLTHROUGH*/ -+ case 4: -+ b |= ((uint64_t)in[3]) << 24; -+ /*FALLTHROUGH*/ -+ case 3: -+ b |= ((uint64_t)in[2]) << 16; -+ /*FALLTHROUGH*/ -+ case 2: -+ b |= ((uint64_t)in[1]) << 8; -+ /*FALLTHROUGH*/ -+ case 1: -+ b |= ((uint64_t)in[0]); -+ break; -+ case 0: -+ default: -+ break; -+ } -+ -+ v3 ^= b; -+ -+ TRACE; -+ for (i = 0; i < cROUNDS; ++i) -+ SIPROUND; -+ -+ v0 ^= b; -+ -+ if (outlen == 16) -+ v2 ^= 0xee; -+ else -+ v2 ^= 0xff; -+ -+ TRACE; -+ for (i = 0; i < dROUNDS; ++i) -+ SIPROUND; -+ -+ b = v0 ^ v1 ^ v2 ^ v3; -+ U64TO8_LE(out, b); -+ -+ if (outlen == 8) -+ return 0; -+ -+ v1 ^= 0xdd; -+ -+ TRACE; -+ for (i = 0; i < dROUNDS; ++i) -+ SIPROUND; -+ -+ b = v0 ^ v1 ^ v2 ^ v3; -+ U64TO8_LE(out + 8, b); -+ -+ return 0; -+} ---- a/plugins/imfile/imfile.c -+++ b/plugins/imfile/imfile.c -@@ -182,6 +182,7 @@ struct act_obj_s { - time_t timeoutBase; /* what time to calculate the timeout against? */ - /* file dynamic data */ - char file_id[FILE_ID_HASH_SIZE]; /* file id for this entry, once we could obtain it */ -+ char file_id_prev[FILE_ID_HASH_SIZE]; /* previous file id for this entry, set if changed */ - int in_move; /* workaround for inotify move: if set, state file must not be deleted */ - ino_t ino; /* current inode nbr */ - int fd; /* fd to file in order to obtain file_id (needs to be preserved across move) */ -@@ -727,6 +728,7 @@ act_obj_add(fs_edge_t *const edge, const char *const name, const int is_file, - act->ino = ino; - act->fd = fd; - act->file_id[0] = '\0'; -+ act->file_id_prev[0] = '\0'; - act->is_symlink = is_symlink; - if (source) { /* we are target of symlink */ - CHKmalloc(act->source_name = strdup(source)); -@@ -1378,28 +1380,13 @@ openFileWithStateFile(act_obj_t *const act) - if(fd < 0) { - if(errno == ENOENT) { - if(act->file_id[0] != '\0') { -- const char *pszSFNamHash = strdup((const char*)pszSFNam); -- CHKmalloc(pszSFNamHash); - DBGPRINTF("state file %s for %s does not exist - trying to see if " - "inode-only file exists\n", pszSFNam, act->name); - getFullStateFileName(statefn, "", pszSFNam, sizeof(pszSFNam)); - fd = open((char*)pszSFNam, O_CLOEXEC | O_NOCTTY | O_RDONLY, 0600); - if(fd >= 0) { -- dbgprintf("found inode-only state file, renaming it now that we " -- "know the file_id, new name: %s\n", pszSFNamHash); -- /* we now can use identify the file, so let's rename it */ -- if(rename((const char*)pszSFNam, pszSFNamHash) != 0) { -- LogError(errno, RS_RET_IO_ERROR, -- "imfile error trying to rename state file for '%s' - " -- "ignoring this error, usually this means a file no " -- "longer file is left over, but this may also cause " -- "some real trouble. Still the best we can do ", -- act->name); -- free((void*) pszSFNamHash); -- ABORT_FINALIZE(RS_RET_IO_ERROR); -- } -+ dbgprintf("found inode-only state file, will be renamed at next persist\n"); - } -- free((void*) pszSFNamHash); - } - if(fd < 0) { - DBGPRINTF("state file %s for %s does not exist - trying to see if " -@@ -2609,6 +2596,28 @@ atomicWriteStateFile(const char *fn, const char *content) - RETiRet; - } - -+static void -+removeOldStatefile(const uchar *statefn, const char *hashToDelete) -+{ -+ int ret; -+ uchar statefname[MAXFNAME]; -+ -+ getFullStateFileName(statefn, hashToDelete, statefname, sizeof(statefname)); -+ ret = unlink((const char*)statefname); -+ if(ret != 0) { -+ if (errno != ENOENT) { -+ LogError(errno, RS_RET_IO_ERROR, -+ "imfile error trying to delete old state file: '%s' - ignoring this " -+ "error, usually this means a file no longer file is left over, but " -+ "this may also cause some real trouble. Still the best we can do ", -+ statefname); -+ } else { -+ DBGPRINTF("trying to delete no longer valid statefile '%s' which no " -+ "longer exists (probably already deleted)\n", statefname); -+ } -+ } -+} -+ - - /* This function persists information for a specific file being monitored. - * To do so, it simply persists the stream object. We do NOT abort on error -@@ -2660,6 +2664,15 @@ persistStrmState(act_obj_t *const act) - CHKiRet(atomicWriteStateFile((const char*)statefname, jstr)); - json_object_put(json); - -+ /* check for presence of inode-only statefile and delete if exitsts */ -+ if (act->file_id[0] != '\0') { -+ removeOldStatefile(statefn, ""); -+ } -+ /* file-id changed (truncated?), remove the old hash statefile */ -+ if (strncmp((const char *)act->file_id_prev, (const char *)act->file_id, FILE_ID_HASH_SIZE)) { -+ removeOldStatefile(statefn, act->file_id_prev); -+ } -+ - finalize_it: - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "imfile: could not persist state " diff --git a/SPECS/rsyslog.spec b/SPECS/rsyslog.spec index 4473e21..c3743e7 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: 41%{?dist}.4 +Release: 52%{?dist} License: (GPLv3+ and ASL 2.0) Group: System Environment/Daemons URL: http://www.rsyslog.com/ @@ -115,8 +115,18 @@ Patch52: rsyslog-8.24.0-doc-rhbz1625935-mmkubernetes-CRI-O.patch Patch53: rsyslog-8.24.0-rhbz1656860-imfile-buffer-overflow.patch Patch54: rsyslog-8.24.0-rhbz1725067-imjournal-memleak.patch -Patch55: rsyslog-8.24.0-rhbz1746497-ratelimiter-segfault.patch -Patch56: rsyslog-8.24.0-rhbz1805675-file-id.patch +Patch55: rsyslog-8.24.0-doc-rhbz1696686-imjournal-fsync.patch +Patch56: rsyslog-8.24.0-rhbz1696686-imjournal-fsync.patch +Patch57: rsyslog-8.24.0-rhbz1684236-omelastic-sigsegv.patch +Patch58: rsyslog-8.24.0-doc-rhbz1309698-imudp-case-sensitive-option.patch +Patch59: rsyslog-8.24.0-rhbz1309698-imudp-case-sensitive-option.patch +Patch60: rsyslog-8.24.0-rhbz1627799-cert-chains.patch +Patch61: rsyslog-8.24.0-rhbz1744682-ratelimiter-segfault.patch +Patch62: rsyslog-8.24.0-rhbz1549706-corrupt-property-crash.patch +Patch63: rsyslog-8.24.0-rhbz1768320-pmaixfw-CVE.patch +Patch64: rsyslog-8.24.0-rhbz1768323-pmcisco-CVE.patch +Patch65: rsyslog-8.24.0-rhbz1763746-file-id.patch +Patch66: rsyslog-8.24.0-rhbz1600171-omelastic-ES6.patch %package crypto Summary: Encryption support @@ -348,6 +358,8 @@ container metadata. %patch40 -p1 %patch41 -p1 %patch52 -p1 +%patch55 -p1 +%patch58 -p1 #regenerate the docs mv build/searchindex.js searchindex_backup.js sphinx-build -b html source build @@ -422,8 +434,18 @@ mv build doc %patch53 -p1 -b .imfile-buffer-overflow %patch54 -p1 -b .imjournal-memleak -%patch55 -p1 -b .ratelimit-crash -%patch56 -p1 -b .file_id-fix +#%patch55 is applied right after doc setup +%patch56 -p1 -b .imjournal-fsync +%patch57 -p1 -b .elastic-sigsegv +#%patch58 is applied right after doc setup +%patch59 -p1 -b .udp-case-sensitive +%patch60 -p1 -b .cert-chains +%patch61 -p1 -b .ratelimit-crash +%patch62 -p1 -b .corrupt-property +%patch63 -p1 -b .pmAIX-CVE +%patch64 -p1 -b .pmCisco-CVE +%patch65 -p1 -b .file-id +%patch66 -p1 -b .omelastic-ES6 autoreconf @@ -683,28 +705,62 @@ done %{_libdir}/rsyslog/mmkubernetes.so %changelog -* Tue Mar 03 2020 Jiri Vymazal - 8.24.0-41.4 -RHEL 7.7.z ERRATUM -- edited patch fixing hashed file_ids for imfile statefiles - resolves: rhbz#1805675 - -* Fri Feb 21 2020 Jiri Vymazal - 8.24.0-41.3 -RHEL 7.7.z ERRATUM -- added patch fixing hash file_id feature to properly monitor files - after rotation - resolves: rhbz#1805675 - -* Mon Sep 23 2019 Jiri Vymazal - 8.24.0-41.2 -RHEL 7.7.z ERRATUM -- edited imjournal memleaks patch to fix introduced regression - resolves: rhbz#1752424 - -* Mon Sep 02 2019 Jiri Vymazal - 8.24.0-41.1 -RHEL 7.7.z ERRATUM -- added patch resolving possible segfault in core-ratelimiter - resolves: rhbz#1746497 - -* Tue Jul 23 2019 Jiri Vymazal - 8.24.0-41 +* Wed Nov 27 2019 Jiri Vymazal - 8.24.0-52 +RHEL 7.8 ERRATUM +- edited patch file ID for imfile to not log useless errors + also improved file-id behavior to adress newly found problems + resolves: rhbz#1763746 + +* Thu Nov 07 2019 Jiri Vymazal - 8.24.0-49 +RHEL 7.8 ERRATUM +- fixed fsync patch to actually revognize the new option + resolves: rhbz#1696686 (failedQA) + +* Wed Nov 06 2019 Jiri Vymazal - 8.24.0-48 +RHEL 7.8 ERRATUM +- added patch resolving crash on wrong MsgProperty + resolves: rhbz#1549706 +- added patch resolving CVE in pmaixforward module + resolves: rhbz#1768320 +- added patch resolving CVE in pmcisconames module + resolves: rhbz#1768323 +- added patch implementing file ID for imfile + resolves: rhbz#1763746 +- added patch fixing omelasticsearch with ES 6.X + resolves: rhbz#1600171 + +* Thu Sep 05 2019 Jiri Vymazal - 8.24.0-47 +RHEL 7.8 ERRATUM +- edited imfile truncation detection patch with reression fix + resolves: rhbz#1744856 + +* Wed Aug 28 2019 Jiri Vymazal - 8.24.0-46 +RHEL 7.8 ERRATUM +- Support Intermediate Certificate Chains in rsyslog + resolves: rhbz#1627799 +- fixed WorAroundJournalBug patch to not cause leaks + resolves: rhbz#1744617 +- added patch fixing possible segfault in rate-limiter + resolves: rhbz#1744682 + +* Mon Aug 12 2019 Jiri Vymazal - 8.24.0-45 +RHEL 7.8 ERRATUM +- fixed fsync patch according to covscan results + resolves: rhbz#1696686 + +* Fri Aug 09 2019 Jiri Vymazal - 8.24.0-44 +RHEL 7.8 ERRATUM +- added patch and doc-patch for new caseSensitive imUDP/TCP option + resolves: rhbz#1309698 + +* Fri Aug 02 2019 Jiri Vymazal - 8.24.0-41 +RHEL 7.8 ERRATUM +- added patch and doc-patch with new "fsync" imjournal option + resolves: rhbz#1696686 +- added patch resolving omelasticsearch crash on "nothing" reply + resolves: rhbz#1684236 + +* Mon Jul 01 2019 Jiri Vymazal - 8.24.0-39 RHEL 7.7.z ERRATUM - added patch resolving memory leaks in imjournal resolves: rhbz#1725067