diff --git a/SOURCES/logrotate-3.8.6-config-error.patch b/SOURCES/logrotate-3.8.6-config-error.patch new file mode 100644 index 0000000..6231284 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-config-error.patch @@ -0,0 +1,225 @@ +From 71c2315b76ef0d5408bfa37c31ad1b5a27e2b3e7 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Wed, 7 Dec 2016 10:39:55 +0100 +Subject: [PATCH 1/4] config.c: skip a duplicated log entry but continue + reading + +... other entries which are not duplicated. + +Closes #81 + +Upstream-commit: 06ede862d319efc98942536cba11bdfdbdc9cc72 +Signed-off-by: Kamil Dudka +--- + config.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/config.c b/config.c +index 2a610de..aaf4fbb 100644 +--- a/config.c ++++ b/config.c +@@ -1389,7 +1389,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + + newlog->files = NULL; + newlog->numFiles = 0; +- for (argNum = 0; argNum < argc && logerror != 1; argNum++) { ++ for (argNum = 0; argNum < argc; argNum++) { + if (globerr_msg) { + free(globerr_msg); + globerr_msg = NULL; +@@ -1672,7 +1672,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + + munmap(buf, (size_t) length); + close(fd); +- return 0; ++ return logerror; + error: + if (key) + free(key); +-- +2.20.1 + + +From 9915dc4c4bf84b1ff16f34d7d34178098a03cf7c Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 2 Jan 2017 20:35:17 +0100 +Subject: [PATCH 2/4] config.c: recover from failures of readConfigFile() + +Closes #81 + +Upstream-commit: 56598fd1e9338b45ba3e1bda1b91522e75b40e06 +Signed-off-by: Kamil Dudka +--- + config.c | 30 ++++++++++++++---------------- + 1 file changed, 14 insertions(+), 16 deletions(-) + +diff --git a/config.c b/config.c +index aaf4fbb..203b3e3 100644 +--- a/config.c ++++ b/config.c +@@ -510,8 +510,8 @@ static void freeTailLogs(int num) + static int readConfigPath(const char *path, struct logInfo *defConfig) + { + struct stat sb; +- int here, oldnumlogs, result = 1; +- struct logInfo defConfigBackup; ++ int here, result = 1; ++ struct logInfo defConfigBackup; + + if (stat(path, &sb)) { + message(MESS_ERROR, "cannot stat %s: %s\n", path, strerror(errno)); +@@ -588,11 +588,9 @@ static int readConfigPath(const char *path, struct logInfo *defConfig) + + for (i = 0; i < files_count; ++i) { + assert(namelist[i] != NULL); +- oldnumlogs = numLogs; + copyLogInfo(&defConfigBackup, defConfig); + if (readConfigFile(namelist[i], defConfig)) { + message(MESS_ERROR, "found error in file %s, skipping\n", namelist[i]); +- freeTailLogs(numLogs - oldnumlogs); + freeLogInfo(defConfig); + copyLogInfo(defConfig, &defConfigBackup); + freeLogInfo(&defConfigBackup); +@@ -609,10 +607,8 @@ static int readConfigPath(const char *path, struct logInfo *defConfig) + close(here); + free_2d_array(namelist, files_count); + } else { +- oldnumlogs = numLogs; + copyLogInfo(&defConfigBackup, defConfig); + if (readConfigFile(path, defConfig)) { +- freeTailLogs(numLogs - oldnumlogs); + freeLogInfo(defConfig); + copyLogInfo(defConfig, &defConfigBackup); + } else { +@@ -678,10 +674,8 @@ int readAllConfigPaths(const char **paths) + } + + for (file = paths; *file; file++) { +- if (readConfigPath(*file, &defConfig)) { ++ if (readConfigPath(*file, &defConfig)) + result = 1; +- break; +- } + } + free_2d_array(tabooExts, tabooCount); + freeLogInfo(&defConfig); +@@ -1207,17 +1201,21 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + &buf, length)) != NULL) { + + message(MESS_DEBUG, "including %s\n", key); +- if (++recursion_depth > MAX_NESTING) { ++ if (recursion_depth >= MAX_NESTING) { + message(MESS_ERROR, "%s:%d include nesting too deep\n", + configFile, lineNum); +- --recursion_depth; +- goto error; +- } +- if (readConfigPath(key, newlog)) { +- --recursion_depth; +- goto error; ++ logerror = 1; ++ continue; + } ++ ++ ++recursion_depth; ++ rv = readConfigPath(key, newlog); + --recursion_depth; ++ ++ if (rv) { ++ logerror = 1; ++ continue; ++ } + } + else continue; + } else if (!strcmp(key, "olddir")) { +-- +2.20.1 + + +From ed099a0321e799d4be72f9096532bb976680aad8 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Thu, 12 Jan 2017 08:44:39 +0100 +Subject: [PATCH 3/4] config.c: propagate errors from readConfigFile() properly + +Closes #81 + +Upstream-commit: 6a75cdeab61a29ea99d49a85461f597c1d8d055c +Signed-off-by: Kamil Dudka +--- + config.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/config.c b/config.c +index 203b3e3..72981b0 100644 +--- a/config.c ++++ b/config.c +@@ -510,7 +510,7 @@ static void freeTailLogs(int num) + static int readConfigPath(const char *path, struct logInfo *defConfig) + { + struct stat sb; +- int here, result = 1; ++ int here, result = 0; + struct logInfo defConfigBackup; + + if (stat(path, &sb)) { +@@ -594,9 +594,8 @@ static int readConfigPath(const char *path, struct logInfo *defConfig) + freeLogInfo(defConfig); + copyLogInfo(defConfig, &defConfigBackup); + freeLogInfo(&defConfigBackup); ++ result = 1; + continue; +- } else { +- result = 0; + } + freeLogInfo(&defConfigBackup); + } +@@ -611,8 +610,7 @@ static int readConfigPath(const char *path, struct logInfo *defConfig) + if (readConfigFile(path, defConfig)) { + freeLogInfo(defConfig); + copyLogInfo(defConfig, &defConfigBackup); +- } else { +- result = 0; ++ result = 1; + } + freeLogInfo(&defConfigBackup); + } +-- +2.20.1 + + +From 58f8efbfde9d0ff2d8fbb0cef30ed842928835cd Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Thu, 12 Jan 2017 08:50:55 +0100 +Subject: [PATCH 4/4] do not treat errors in reading configuration as fatal + +Closes #81 + +Upstream-commit: 74b788f790990d5958314df5f908a6fc5eaeccdd +Signed-off-by: Kamil Dudka +--- + logrotate.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/logrotate.c b/logrotate.c +index 976210e..459e01e 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -2417,12 +2417,10 @@ int main(int argc, const char **argv) + selinux_enforce = security_getenforce(); + #endif + +- TAILQ_INIT(&logs); ++ TAILQ_INIT(&logs); + +- if (readAllConfigPaths(files)) { +- poptFreeContext(optCon); +- exit(1); +- } ++ if (readAllConfigPaths(files)) ++ rc = 1; + + poptFreeContext(optCon); + nowSecs = time(NULL); +-- +2.20.1 + diff --git a/SOURCES/logrotate-3.8.6-rename-existing.patch b/SOURCES/logrotate-3.8.6-rename-existing.patch new file mode 100644 index 0000000..15d8b43 --- /dev/null +++ b/SOURCES/logrotate-3.8.6-rename-existing.patch @@ -0,0 +1,206 @@ +From def2d2aebad1a6d1b149780181943e0cafa63bdc Mon Sep 17 00:00:00 2001 +From: Mathieu Parent +Date: Tue, 8 Mar 2016 16:56:50 +0100 +Subject: [PATCH 1/3] createOutputFile: rename already existing file + +See https://bugs.debian.org/734688 + +Closes #23 + +Upstream-commit: fc1c3eff61edf8e9f0a4bfa980f3a6030a6b271f +Signed-off-by: Kamil Dudka +--- + logrotate.c | 20 ++++++++++++++++++-- + test/test | 26 ++++++++++++++++++++++++++ + test/test-config.72.in | 7 +++++++ + 3 files changed, 51 insertions(+), 2 deletions(-) + create mode 100644 test/test-config.72.in + +diff --git a/logrotate.c b/logrotate.c +index f13d140..976210e 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -395,8 +395,24 @@ static int runScript(struct logInfo *log, char *logfn, char *script) + int createOutputFile(char *fileName, int flags, struct stat *sb, acl_type acl, int force_mode) + { + int fd; +- struct stat sb_create; +- int acl_set = 0; ++ struct stat sb_create; ++ int acl_set = 0; ++ ++ if (stat(fileName, &sb_create) == 0) { ++ /* the destination file already exists, while it should not */ ++ struct tm now = *localtime(&nowSecs); ++ size_t fileName_size = strlen(fileName); ++ char* backupName = alloca(fileName_size + sizeof("-YYYYMMDDHH.backup")); ++ strncpy(backupName, fileName, fileName_size); ++ size_t date_size=strftime(backupName+fileName_size, 12, "-%Y%m%d%H", &now); ++ strncpy(backupName+fileName_size+date_size, ".backup\0", 8); ++ message(MESS_ERROR, "destination %s already exists, renaming to %s\n", fileName, backupName); ++ if (rename(fileName, backupName) != 0) { ++ message(MESS_ERROR, "error renaming already existing output file %s to %s: %s\n", ++ fileName, backupName, strerror(errno)); ++ return -1; ++ } ++ } + + fd = open(fileName, (flags | O_EXCL | O_NOFOLLOW), + (S_IRUSR | S_IWUSR) & sb->st_mode); +diff --git a/test/test b/test/test +index bcdfe05..b47ac6a 100755 +--- a/test/test ++++ b/test/test +@@ -1586,6 +1586,32 @@ EOF + rm -rf testdir adir + rm -rf testdir bdir + ++cleanup 72 ++ ++# ------------------------------- Test 72 ------------------------------------ ++preptest test.log 72 2 ++ ++$RLR test-config.72 --force ++ ++checkoutput < test.log.1.gz ++ ++$RLR test-config.72 --force ++dt="$(date +%Y%m%d%H)" ++ ++checkoutput < +Date: Mon, 17 Oct 2016 17:59:31 +0200 +Subject: [PATCH 2/3] createOutputFile: eliminate stat/open TOCTOU race + +Upstream-commit: aff4a30807218a52b6b5f200c5aa0eea335547ba +Signed-off-by: Kamil Dudka +--- + logrotate.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/logrotate.c b/logrotate.c +index 976210e..fdc81ac 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -394,11 +394,18 @@ static int runScript(struct logInfo *log, char *logfn, char *script) + + int createOutputFile(char *fileName, int flags, struct stat *sb, acl_type acl, int force_mode) + { +- int fd; ++ int fd = -1; + struct stat sb_create; + int acl_set = 0; ++ int i; ++ ++ for (i = 0; i < 2; ++i) { ++ fd = open(fileName, (flags | O_EXCL | O_NOFOLLOW), ++ (S_IRUSR | S_IWUSR) & sb->st_mode); ++ ++ if ((fd >= 0) || (errno != EEXIST)) ++ break; + +- if (stat(fileName, &sb_create) == 0) { + /* the destination file already exists, while it should not */ + struct tm now = *localtime(&nowSecs); + size_t fileName_size = strlen(fileName); +@@ -412,11 +419,9 @@ int createOutputFile(char *fileName, int flags, struct stat *sb, acl_type acl, i + fileName, backupName, strerror(errno)); + return -1; + } ++ /* existing file renamed, try it once again */ + } + +- fd = open(fileName, (flags | O_EXCL | O_NOFOLLOW), +- (S_IRUSR | S_IWUSR) & sb->st_mode); +- + if (fd < 0) { + message(MESS_ERROR, "error creating output file %s: %s\n", + fileName, strerror(errno)); +-- +2.20.1 + + +From 86d67f5769575104add7846b822069008c912b3c Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 17 Oct 2016 18:13:32 +0200 +Subject: [PATCH 3/3] createOutputFile: improve code readability + +Upstream-commit: 5ecd908033a481c1e127ba583697d6662ffea4a3 +Signed-off-by: Kamil Dudka +--- + logrotate.c | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/logrotate.c b/logrotate.c +index fdc81ac..5b0df30 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -409,14 +409,24 @@ int createOutputFile(char *fileName, int flags, struct stat *sb, acl_type acl, i + /* the destination file already exists, while it should not */ + struct tm now = *localtime(&nowSecs); + size_t fileName_size = strlen(fileName); +- char* backupName = alloca(fileName_size + sizeof("-YYYYMMDDHH.backup")); +- strncpy(backupName, fileName, fileName_size); +- size_t date_size=strftime(backupName+fileName_size, 12, "-%Y%m%d%H", &now); +- strncpy(backupName+fileName_size+date_size, ".backup\0", 8); +- message(MESS_ERROR, "destination %s already exists, renaming to %s\n", fileName, backupName); ++ size_t buf_size = fileName_size + sizeof("-YYYYMMDDHH.backup"); ++ char *backupName = alloca(buf_size); ++ char *ptr = backupName; ++ ++ /* construct backupName starting with fileName */ ++ strcpy(ptr, fileName); ++ ptr += fileName_size; ++ buf_size -= fileName_size; ++ ++ /* append the -YYYYMMDDHH time stamp and the .backup suffix */ ++ ptr += strftime(ptr, buf_size, "-%Y%m%d%H", &now); ++ strcpy(ptr, ".backup"); ++ ++ message(MESS_ERROR, "destination %s already exists, renaming to %s\n", ++ fileName, backupName); + if (rename(fileName, backupName) != 0) { +- message(MESS_ERROR, "error renaming already existing output file %s to %s: %s\n", +- fileName, backupName, strerror(errno)); ++ message(MESS_ERROR, "error renaming already existing output file" ++ " %s to %s: %s\n", fileName, backupName, strerror(errno)); + return -1; + } + /* existing file renamed, try it once again */ +-- +2.20.1 + diff --git a/SPECS/logrotate.spec b/SPECS/logrotate.spec index 1c61f5d..d689299 100644 --- a/SPECS/logrotate.spec +++ b/SPECS/logrotate.spec @@ -1,7 +1,7 @@ Summary: Rotates, compresses, removes and mails system log files Name: logrotate Version: 3.8.6 -Release: 17%{?dist} +Release: 19%{?dist} License: GPL+ Group: System Environment/Base URL: https://github.com/logrotate/logrotate @@ -54,6 +54,12 @@ Patch19: logrotate-3.8.6-monthly-dst.patch # fix #1374550 - unlink destination file when rotation fails Patch20: logrotate-3.8.6-unlink-on-failure.patch +# fix #1631218 - rename already existing file +Patch21: logrotate-3.8.6-rename-existing.patch + +# fix #1680436 - do not treat errors in reading configuration as fatal +Patch22: logrotate-3.8.6-config-error.patch + Requires: coreutils >= 5.92 popt BuildRequires: libselinux-devel popt-devel libacl-devel acl BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -92,6 +98,8 @@ log files on your system. %patch18 -p1 %patch19 -p1 %patch20 -p1 +%patch21 -p1 +%patch22 -p1 %build make %{?_smp_mflags} RPM_OPT_FLAGS="$RPM_OPT_FLAGS" WITH_SELINUX=yes WITH_ACL=yes @@ -140,6 +148,13 @@ rm -rf $RPM_BUILD_ROOT %config(noreplace) %{_sysconfdir}/rwtab.d/logrotate %changelog +* Wed Aug 07 2019 Kamil Dudka - 3.8.6-19 +- related #1631218 - eliminate a time-of-check/time-of-use race condition + +* Tue Aug 06 2019 Kamil Dudka - 3.8.6-18 +- fix #1680436 - do not treat errors in reading configuration as fatal +- fix #1631218 - rename already existing file + * Fri Jun 15 2018 Kamil Dudka - 3.8.6-17 - fix #1374550 - unlink destination file when rotation fails