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-rhbz1696686-imjournal-fsync.patch b/SOURCES/rsyslog-8.24.0-rhbz1696686-imjournal-fsync.patch index 0f30b02..430dbd1 100644 --- a/SOURCES/rsyslog-8.24.0-rhbz1696686-imjournal-fsync.patch +++ b/SOURCES/rsyslog-8.24.0-rhbz1696686-imjournal-fsync.patch @@ -7,8 +7,8 @@ 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 | 38 +++++++++++++++---- - 1 file changed, 30 insertions(+), 8 deletitions(-) + 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 @@ -30,6 +30,16 @@ index 5739bf408c..6c8829243a 100644 } 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) { 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-rhbz1778841-serialize-crash-race.patch b/SOURCES/rsyslog-8.24.0-rhbz1778841-serialize-crash-race.patch new file mode 100644 index 0000000..b917c03 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1778841-serialize-crash-race.patch @@ -0,0 +1,33 @@ +From: Jiri Vymazal +Date: Wed, 18 Dec 2019 09:48:15 +0100 +Subject: [PATCH] Fix race condition related to libfastjson when using DA queue + +Rsyslogd aborts when writing to disk queue from multiple workers simultaneously. +It is assumed that libfastjson is not thread-safe. +Resolve libfastjson race condition when writing to disk queue. + +see also https://github.com/rsyslog/rsyslog/issues/4099 +--- + runtime/msg.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/runtime/msg.c b/runtime/msg.c +index b5c17cfdd4..f9da40005f 100644 +--- a/runtime/msg.c ++++ b/runtime/msg.c +@@ -1211,11 +1211,15 @@ static rsRetVal MsgSerialize(smsg_t *pThis, strm_t *pStrm) + psz = pThis->pszStrucData; + CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszStrucData"), PROPTYPE_PSZ, (void*) psz)); + if(pThis->json != NULL) { ++ MsgLock(pThis); + psz = (uchar*) json_object_get_string(pThis->json); ++ MsgUnlock(pThis); + CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("json"), PROPTYPE_PSZ, (void*) psz)); + } + if(pThis->localvars != NULL) { ++ MsgLock(pThis); + psz = (uchar*) json_object_get_string(pThis->localvars); ++ MsgUnlock(pThis); + CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("localvars"), PROPTYPE_PSZ, (void*) psz)); + } + diff --git a/SOURCES/rsyslog-8.24.0-rhbz1806493-imfile-file_id.patch b/SOURCES/rsyslog-8.24.0-rhbz1806493-imfile-file_id.patch new file mode 100644 index 0000000..b972d02 --- /dev/null +++ b/SOURCES/rsyslog-8.24.0-rhbz1806493-imfile-file_id.patch @@ -0,0 +1,37 @@ +From 0c69ec76d8cac47bcfa78abae86229ad63c92b0b Mon Sep 17 00:00:00 2001 +From: Jiri Vymazal +Date: Tue, 21 Jan 2020 13:58:14 +0100 +Subject: [PATCH] Fixed saving of old file_id for statefiles + +Previously we saved old file_id unconditionally, which led to not +deleting old statefiles if files changes without rsyslog running. +Now it should work correctly. +--- + plugins/imfile/imfile.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c +index 908bb5901c..5ad44f6c59 100644 +--- a/plugins/imfile/imfile.c ++++ b/plugins/imfile/imfile.c +@@ -1258,8 +1258,8 @@ get_file_id_hash(const char *data, size_t lendata, + */ + 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); ++ char tmp_id[FILE_ID_HASH_SIZE]; ++ strncpy(tmp_id, (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]; +@@ -1270,6 +1270,9 @@ getFileID(act_obj_t *const act) + } else { + DBGPRINTF("getFileID partial or error read, ret %d\n", r); + } ++ if (strncmp(tmp_id, act->file_id, FILE_ID_HASH_SIZE)) {/* save the old id for cleaning purposes */ ++ strncpy(act->file_id_prev, tmp_id, FILE_ID_HASH_SIZE); ++ } + DBGPRINTF("getFileID for '%s', file_id_hash '%s'\n", act->name, act->file_id); + } + diff --git a/SPECS/rsyslog.spec b/SPECS/rsyslog.spec index 3274359..4cd06f2 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: 47%{?dist} +Release: 53%{?dist} License: (GPLv3+ and ASL 2.0) Group: System Environment/Daemons URL: http://www.rsyslog.com/ @@ -122,6 +122,14 @@ 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 + +Patch67: rsyslog-8.24.0-rhbz1806493-imfile-file_id.patch +Patch68: rsyslog-8.24.0-rhbz1778841-serialize-crash-race.patch %package crypto Summary: Encryption support @@ -436,6 +444,14 @@ mv build doc %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 + +%patch67 -p1 -b .file-id_2 +%patch68 -p1 -b .serialize_race autoreconf @@ -695,6 +711,37 @@ done %{_libdir}/rsyslog/mmkubernetes.so %changelog +* Thu Mar 26 2020 Jiri Vymazal - 8.24.0-53 +RHEL 7.9 ERRATUM +- one more fix for file ID patch to extend to offline behavior + resolves: rhbz#1806493 +- added patch resoving race in serialization resulting in crash + resolves: rhbz#1778841 + +* 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