Version in base suite: 3.18.0-2 Base version: logrotate_3.18.0-2 Target version: logrotate_3.18.0-2+deb11u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/l/logrotate/logrotate_3.18.0-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/l/logrotate/logrotate_3.18.0-2+deb11u1.dsc changelog | 16 + patches/applied-upstream/Add-more-testcases-for-stricter-configuration-parsin.patch | 144 +++++++++ patches/applied-upstream/Do-not-lock-state-file-dev-null.patch | 48 +++ patches/applied-upstream/Do-not-use-incorrect-stat-information.patch | 143 +++++++++ patches/applied-upstream/Do-not-warn-on-key-value-pair-separated-by-only-an-e.patch | 33 ++ patches/applied-upstream/Fix-full_write-on-incomplete-write.patch | 51 +++ patches/applied-upstream/Log-error-on-keyword-parse-failure.patch | 27 + patches/applied-upstream/Log-if-keyword-is-not-properly-separated.patch | 34 ++ patches/applied-upstream/Remove-invalid-configuration-on-error.patch | 41 ++ patches/applied-upstream/config.c-enforce-stricter-parsing-of-config-files.patch | 143 +++++++++ patches/applied-upstream/drop-world-readable-permission-on-state-file.patch | 56 +++ patches/applied-upstream/skip-locking-if-state-file-is-world-readable.patch | 152 ++++++++++ patches/debian/replace-ELF-header-in-test-case.patch | 19 + patches/series | 12 14 files changed, 919 insertions(+) diff -Nru logrotate-3.18.0/debian/changelog logrotate-3.18.0/debian/changelog --- logrotate-3.18.0/debian/changelog 2021-02-28 16:37:19.000000000 +0000 +++ logrotate-3.18.0/debian/changelog 2022-01-30 16:29:14.000000000 +0000 @@ -1,3 +1,19 @@ +logrotate (3.18.0-2+deb11u1) bullseye; urgency=medium + + * d/patches: cherry-pick upstream fixes: + - skip locking if state file is world-readable (CVE-2022-1348) + + - more strict configuration parsing to avoid parsing + parts of foreign files, e.g. core dumps, (see #1002022) + + - do not use incorrect stat information when verifying an olddir + configuration after creating the olddir + + - advance pointer in full_write on incomplete write to avoid data + corruption + + -- Christian Göttsche Sun, 30 Jan 2022 17:29:14 +0100 + logrotate (3.18.0-2) unstable; urgency=medium * d/patches: cherry-pick relevant commits for Bullseye diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/Add-more-testcases-for-stricter-configuration-parsin.patch logrotate-3.18.0/debian/patches/applied-upstream/Add-more-testcases-for-stricter-configuration-parsin.patch --- logrotate-3.18.0/debian/patches/applied-upstream/Add-more-testcases-for-stricter-configuration-parsin.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/Add-more-testcases-for-stricter-configuration-parsin.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,144 @@ +From: =?utf-8?q?Christian_G=C3=B6ttsche?= +Date: Mon, 13 Dec 2021 21:47:16 +0100 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/9cbc22b91caff6cfbd1378737c62276bd9ffe3e7 +Subject: Add more testcases for stricter configuration parsing + +--- + test/Makefile.am | 4 +++- + test/test-0102.sh | 5 +++++ + test/test-0103.sh | 5 +++++ + test/test-0104.sh | 19 +++++++++++++++++++ + test/test-0105.sh | 25 +++++++++++++++++++++++++ + test/test-config.104.in | 8 ++++++++ + test/test-config.105.in | 8 ++++++++ + 7 files changed, 73 insertions(+), 1 deletion(-) + create mode 100755 test/test-0104.sh + create mode 100755 test/test-0105.sh + create mode 100644 test/test-config.104.in + create mode 100644 test/test-config.105.in + +diff --git a/test/Makefile.am b/test/Makefile.am +index 319ba2f..d3ccd1b 100644 +--- a/test/Makefile.am ++++ b/test/Makefile.am +@@ -90,7 +90,9 @@ TEST_CASES = \ + test-0100.sh \ + test-0101.sh \ + test-0102.sh \ +- test-0103.sh ++ test-0103.sh \ ++ test-0104.sh \ ++ test-0105.sh + + EXTRA_DIST = \ + compress \ +diff --git a/test/test-0102.sh b/test/test-0102.sh +index d2550a5..367bde9 100755 +--- a/test/test-0102.sh ++++ b/test/test-0102.sh +@@ -14,3 +14,8 @@ if [ $? -eq 0 ]; then + echo "No error, but there should be one." + exit 3 + fi ++ ++checkoutput < +Date: Mon, 17 Jan 2022 17:39:08 +0100 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/c7078c2b393fce376d79317a9a03de8b8e404cde +Subject: Do not lock state file /dev/null + +#395 introduced /dev/null as supported state file path for cases when no +state file is desired. +lockState() tries to open and lock the state file to avoid issues with +concurrent instances, see #295. +Locking the character file /dev/null might either be not supported, e.g. +on Debian GNU/Hurd (hurd-i386), nor not allowed, e.g. by SELinux. +--- + logrotate.8.in | 2 ++ + logrotate.c | 8 +++++++- + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/logrotate.8.in b/logrotate.8.in +index ef9dcdd..30e78e5 100644 +--- a/logrotate.8.in ++++ b/logrotate.8.in +@@ -75,6 +75,8 @@ if \fBlogrotate\fR is being run as a different user for various sets of + log files. To prevent parallel execution \fBlogrotate\fR by default + acquires a lock on the state file, if it cannot be acquired \fBlogrotate\fR + will exit with value 3. The default state file is \fI@STATE_FILE_PATH@\fR. ++If \fI/dev/null\fR is given as the state file, then \fBlogrotate\fR will ++not try to lock or write the state file. + + .TP + \fB\-\-skip-state-lock\fR +diff --git a/logrotate.c b/logrotate.c +index bffcbf4..322e3af 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -2913,7 +2913,13 @@ static int readState(const char *stateFilename) + + static int lockState(const char *stateFilename, int skip_state_lock) + { +- int lockFd = open(stateFilename, O_RDWR | O_CLOEXEC); ++ int lockFd; ++ ++ if (!strcmp(stateFilename, "/dev/null")) { ++ return 0; ++ } ++ ++ lockFd = open(stateFilename, O_RDWR | O_CLOEXEC); + if (lockFd == -1) { + if (errno == ENOENT) { + message(MESS_DEBUG, "Creating stub state file: %s\n", diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/Do-not-use-incorrect-stat-information.patch logrotate-3.18.0/debian/patches/applied-upstream/Do-not-use-incorrect-stat-information.patch --- logrotate-3.18.0/debian/patches/applied-upstream/Do-not-use-incorrect-stat-information.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/Do-not-use-incorrect-stat-information.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,143 @@ +From: =?utf-8?q?Christian_G=C3=B6ttsche?= +Date: Wed, 2 Jun 2021 16:24:23 +0200 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/ec9a60aa458d15256056a6a86da13c281a595840 +Subject: Do not use incorrect stat information + +Do not the device number of the configuration file when verifying an +olddir configuration after creating the olddir. + +Use different stat structs with more distinct names to avoid misuses. +--- + config.c | 38 ++++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 14 deletions(-) + +diff --git a/config.c b/config.c +index ebadb86..bbdbc45 100644 +--- a/config.c ++++ b/config.c +@@ -961,7 +961,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + char **scriptDest = NULL; + struct logInfo *newlog = defConfig; + char *start, *chptr; +- struct stat sb; ++ struct stat sb_config; + int state = STATE_DEFAULT; + int logerror = 0; + /* to check if incompatible criteria are specified */ +@@ -988,13 +988,13 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + message(MESS_ERROR, "Could not lock file %s for reading\n", + configFile); + } +- if (fstat(fd, &sb)) { ++ if (fstat(fd, &sb_config)) { + message(MESS_ERROR, "fstat of %s failed: %s\n", configFile, + strerror(errno)); + close(fd); + return 1; + } +- if (!S_ISREG(sb.st_mode)) { ++ if (!S_ISREG(sb_config.st_mode)) { + message(MESS_DEBUG, + "Ignoring %s because it's not a regular file.\n", + configFile); +@@ -1010,13 +1010,13 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + } + + if (getuid() == ROOT_UID) { +- if ((sb.st_mode & 07533) != 0400) { ++ if ((sb_config.st_mode & 07533) != 0400) { + message(MESS_DEBUG, + "Potentially dangerous mode on %s: 0%o\n", +- configFile, (unsigned) (sb.st_mode & 07777)); ++ configFile, (unsigned) (sb_config.st_mode & 07777)); + } + +- if (sb.st_mode & 0022) { ++ if (sb_config.st_mode & 0022) { + message(MESS_ERROR, + "Ignoring %s because it is writable by group or others.\n", + configFile); +@@ -1024,7 +1024,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + return 0; + } + +- if (sb.st_uid != ROOT_UID) { ++ if (sb_config.st_uid != ROOT_UID) { + message(MESS_ERROR, + "Ignoring %s because the file owner is wrong (should be root or user with uid 0).\n", + configFile); +@@ -1033,7 +1033,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + } + } + +- length = (size_t)sb.st_size; ++ length = (size_t)sb_config.st_size; + + if (length > 0xffffff) { + message(MESS_ERROR, "file %s too large, probably not a config file.\n", +@@ -1804,10 +1804,11 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + + for (glob_count = 0; glob_count < globResult.gl_pathc; glob_count++) { + struct logInfo *log; ++ struct stat sb_glob; + + /* if we glob directories we can get false matches */ +- if (!lstat(globResult.gl_pathv[glob_count], &sb) && +- S_ISDIR(sb.st_mode)) { ++ if (!lstat(globResult.gl_pathv[glob_count], &sb_glob) && ++ S_ISDIR(sb_glob.st_mode)) { + continue; + } + +@@ -1871,7 +1872,8 @@ duperror: + char *ld; + char *dirpath; + const char *dirName; +- struct stat sb2; ++ struct stat sb_logdir; ++ struct stat sb_olddir; + + dirpath = strdup(newlog->files[j]); + if (dirpath == NULL) { +@@ -1880,7 +1882,7 @@ duperror: + } + + dirName = dirname(dirpath); +- if (stat(dirName, &sb2)) { ++ if (stat(dirName, &sb_logdir)) { + if (!(newlog->flags & LOG_FLAG_MISSINGOK)) { + message(MESS_ERROR, + "%s:%d error verifying log file " +@@ -1916,7 +1918,7 @@ duperror: + dirName = newlog->oldDir; + } + +- if (stat(dirName, &sb)) { ++ if (stat(dirName, &sb_olddir)) { + if (errno == ENOENT && (newlog->flags & LOG_FLAG_OLDDIRCREATE)) { + int ret; + if (newlog->flags & LOG_FLAG_SU) { +@@ -1937,6 +1939,14 @@ duperror: + free(ld); + goto error; + } ++ ++ if (stat(dirName, &sb_olddir) != 0) { ++ message(MESS_ERROR, "%s:%d error verifying created olddir " ++ "path %s: %s\n", configFile, lineNum, ++ dirName, strerror(errno)); ++ free(ld); ++ goto error; ++ } + } + else { + message(MESS_ERROR, "%s:%d error verifying olddir " +@@ -1949,7 +1959,7 @@ duperror: + + free(ld); + +- if (sb.st_dev != sb2.st_dev ++ if (sb_logdir.st_dev != sb_olddir.st_dev + && !(newlog->flags & (LOG_FLAG_COPYTRUNCATE | LOG_FLAG_COPY | LOG_FLAG_TMPFILENAME))) { + message(MESS_ERROR, + "%s:%d olddir %s and log file %s " diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/Do-not-warn-on-key-value-pair-separated-by-only-an-e.patch logrotate-3.18.0/debian/patches/applied-upstream/Do-not-warn-on-key-value-pair-separated-by-only-an-e.patch --- logrotate-3.18.0/debian/patches/applied-upstream/Do-not-warn-on-key-value-pair-separated-by-only-an-e.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/Do-not-warn-on-key-value-pair-separated-by-only-an-e.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,33 @@ +From: =?utf-8?q?Christian_G=C3=B6ttsche?= +Date: Mon, 26 Jul 2021 19:35:00 +0200 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/a98c38bc867ec59e00625b48262bb3334c8f5728 +Subject: Do not warn on key value pair separated by only an equal sign + +Do not warn if a configuration directive is specified with the key and +value separated by just an equal sign, like: + + size=+2048k + +The warning is intended for the usage of: + + size2048k + +Fixes: 2b588b5e ("Log if keyword is not properly separated") +Fixes: #410 +--- + config.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/config.c b/config.c +index ca32cd6..ee10b4f 100644 +--- a/config.c ++++ b/config.c +@@ -1097,7 +1097,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + configFile, lineNum); + continue; + } +- if (!isspace((unsigned char)*start)) { ++ if (!isspace((unsigned char)*start) && *start != '=') { + message(MESS_NORMAL, "%s:%d keyword '%s' not properly" + " separated, found %#x\n", + configFile, lineNum, key, *start); diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/Fix-full_write-on-incomplete-write.patch logrotate-3.18.0/debian/patches/applied-upstream/Fix-full_write-on-incomplete-write.patch --- logrotate-3.18.0/debian/patches/applied-upstream/Fix-full_write-on-incomplete-write.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/Fix-full_write-on-incomplete-write.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,51 @@ +From: =?utf-8?q?Christian_G=C3=B6ttsche?= +Date: Sat, 7 Aug 2021 18:22:11 +0200 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/eb7ec2b9112b229cccfe94c675eb5aabf6ad2baa +Subject: Fix full_write on incomplete write + +Currently on an incomplete write(2) the subsequent write(2) will again +use the same starting position in the given buffer, which was already +successfully written, leading to data corruption. + +Found by clang-13 + + logrotate.c:1140:17: warning: variable 'ptr' set but not used [-Wunused-but-set-variable] + const char *ptr = (const char *) buf; + ^ + +Also check for EINTR only on write(2) failure. +Also use `unsigned char *` to signal handling bytes, not a string. + +Fixes: f1dc0d9 ("Allow rotation of sparse files with copytruncate") +--- + logrotate.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/logrotate.c b/logrotate.c +index 88003db..bffcbf4 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -1080,18 +1080,18 @@ static int is_nul (void const *buf, size_t bufsize) + static size_t full_write(int fd, const void *buf, size_t count) + { + size_t total = 0; +- const char *ptr = (const char *) buf; ++ const unsigned char *ptr = (const unsigned char *) buf; + + while (count > 0) + { + size_t n_rw; + for (;;) + { +- n_rw = (size_t)write (fd, buf, count); +- if (errno == EINTR) ++ n_rw = (size_t)write (fd, ptr, count); ++ if (n_rw == (size_t) -1 && errno == EINTR) + continue; +- else +- break; ++ ++ break; + } + if (n_rw == (size_t) -1) + break; diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/Log-error-on-keyword-parse-failure.patch logrotate-3.18.0/debian/patches/applied-upstream/Log-error-on-keyword-parse-failure.patch --- logrotate-3.18.0/debian/patches/applied-upstream/Log-error-on-keyword-parse-failure.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/Log-error-on-keyword-parse-failure.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,27 @@ +From: =?utf-8?q?Christian_G=C3=B6ttsche?= +Date: Tue, 20 Apr 2021 17:41:12 +0200 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/326179a901b0a8d10e902cae0abab0c68d7abc98 +Subject: Log error on keyword parse failure + +isolateWord() only fails on OOM and EOF. +--- + config.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/config.c b/config.c +index b0ccdb5..ebadb86 100644 +--- a/config.c ++++ b/config.c +@@ -1092,8 +1092,11 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + if (isalpha((unsigned char)*start)) { + free(key); + key = isolateWord(&start, &buf, length); +- if (key == NULL) ++ if (key == NULL) { ++ message(MESS_ERROR, "%s:%d failed to parse keyword\n", ++ configFile, lineNum); + continue; ++ } + if (!isspace((unsigned char)*start)) { + message(MESS_NORMAL, "%s:%d keyword '%s' not properly" + " separated, found %#x\n", diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/Log-if-keyword-is-not-properly-separated.patch logrotate-3.18.0/debian/patches/applied-upstream/Log-if-keyword-is-not-properly-separated.patch --- logrotate-3.18.0/debian/patches/applied-upstream/Log-if-keyword-is-not-properly-separated.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/Log-if-keyword-is-not-properly-separated.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,34 @@ +From: =?utf-8?q?Christian_G=C3=B6ttsche?= +Date: Tue, 20 Apr 2021 17:41:10 +0200 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/2b588b5ec2e5c27bee857c4abeddafa6a9602ebc +Subject: Log if keyword is not properly separated + +The man page states + Values are separated from directives by whitespace and/or an + optional =. + +But logrotate does accept no separator, like + rotate7 + +Log those occurrences with a normal severity, as this usage is not +intended. +--- + config.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/config.c b/config.c +index df2d90b..b0ccdb5 100644 +--- a/config.c ++++ b/config.c +@@ -1094,6 +1094,11 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + key = isolateWord(&start, &buf, length); + if (key == NULL) + continue; ++ if (!isspace((unsigned char)*start)) { ++ message(MESS_NORMAL, "%s:%d keyword '%s' not properly" ++ " separated, found %#x\n", ++ configFile, lineNum, key, *start); ++ } + if (!strcmp(key, "compress")) { + newlog->flags |= LOG_FLAG_COMPRESS; + } else if (!strcmp(key, "nocompress")) { diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/Remove-invalid-configuration-on-error.patch logrotate-3.18.0/debian/patches/applied-upstream/Remove-invalid-configuration-on-error.patch --- logrotate-3.18.0/debian/patches/applied-upstream/Remove-invalid-configuration-on-error.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/Remove-invalid-configuration-on-error.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,41 @@ +From: =?utf-8?q?Christian_G=C3=B6ttsche?= +Date: Tue, 22 Jun 2021 19:32:14 +0200 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/ec05c1b54919e60c5c686bb866f67591d2977f25 +Subject: Remove invalid configuration on error + +After failing while parsing an invalid configuration file, like: + + /some/path + +remove the erroneous configuration structure from the internal list. + +Else one might see: + + reading config file config.tmp + error: config.tmp:1 missing '{' after log files definition + Reading state from file: state.tmp + error: error opening state file state.tmp: No such file or directory + Allocating hash table for state file, size 64 entries + + Handling 1 logs + + rotating pattern: (null) forced from command line (no old logs will be kept) + empty log files are rotated, old logs are removed + No logs found. Rotation not needed. +--- + config.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/config.c b/config.c +index bbdbc45..ca32cd6 100644 +--- a/config.c ++++ b/config.c +@@ -2113,6 +2113,8 @@ next_state: ; + close(fd); + return logerror; + error: ++ if (newlog != defConfig) ++ freeTailLogs(1); + /* free is a NULL-safe operation */ + free(key); + munmap(buf, length); diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/config.c-enforce-stricter-parsing-of-config-files.patch logrotate-3.18.0/debian/patches/applied-upstream/config.c-enforce-stricter-parsing-of-config-files.patch --- logrotate-3.18.0/debian/patches/applied-upstream/config.c-enforce-stricter-parsing-of-config-files.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/config.c-enforce-stricter-parsing-of-config-files.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,143 @@ +From: Felix Wilhelm +Date: Thu, 21 Oct 2021 09:47:57 +0000 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/124e4ca6532b0fe823fa2ec145294547b3aaeb4b +Subject: config.c: enforce stricter parsing of config files + +Abort parsing of config files that contain invalid lines. +This makes it harder to abuse logrotate for privilege escalation +attacks where an attacker can partially control a privileged file write. +--- + config.c | 7 ++++--- + test/Makefile.am | 4 +++- + test/test-0102.sh | 16 ++++++++++++++++ + test/test-0103.sh | 16 ++++++++++++++++ + test/test-config.102.in | 10 ++++++++++ + test/test-config.103.in | 12 ++++++++++++ + 6 files changed, 61 insertions(+), 4 deletions(-) + create mode 100755 test/test-0102.sh + create mode 100755 test/test-0103.sh + create mode 100644 test/test-config.102.in + create mode 100644 test/test-config.103.in + +diff --git a/config.c b/config.c +index ee10b4f..f1c53e4 100644 +--- a/config.c ++++ b/config.c +@@ -1095,12 +1095,13 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) + if (key == NULL) { + message(MESS_ERROR, "%s:%d failed to parse keyword\n", + configFile, lineNum); +- continue; ++ RAISE_ERROR(); + } + if (!isspace((unsigned char)*start) && *start != '=') { +- message(MESS_NORMAL, "%s:%d keyword '%s' not properly" ++ message(MESS_ERROR, "%s:%d keyword '%s' not properly" + " separated, found %#x\n", + configFile, lineNum, key, *start); ++ RAISE_ERROR(); + } + if (!strcmp(key, "compress")) { + newlog->flags |= LOG_FLAG_COMPRESS; +@@ -1977,7 +1978,7 @@ duperror: + message(MESS_ERROR, "%s:%d lines must begin with a keyword " + "or a filename (possibly in double quotes)\n", + configFile, lineNum); +- state = STATE_SKIP_LINE; ++ RAISE_ERROR(); + } + break; + case STATE_SKIP_LINE: +diff --git a/test/Makefile.am b/test/Makefile.am +index 914fe65..319ba2f 100644 +--- a/test/Makefile.am ++++ b/test/Makefile.am +@@ -88,7 +88,9 @@ TEST_CASES = \ + test-0087.sh \ + test-0088.sh \ + test-0100.sh \ +- test-0101.sh ++ test-0101.sh \ ++ test-0102.sh \ ++ test-0103.sh + + EXTRA_DIST = \ + compress \ +diff --git a/test/test-0102.sh b/test/test-0102.sh +new file mode 100755 +index 0000000..d2550a5 +--- /dev/null ++++ b/test/test-0102.sh +@@ -0,0 +1,16 @@ ++#!/bin/sh ++ ++. ./test-common.sh ++ ++cleanup 102 ++ ++# ------------------------------- Test 102 ------------------------------------ ++# test invalid config file with binary content ++preptest test.log 102 1 ++ ++$RLR test-config.102 --force ++ ++if [ $? -eq 0 ]; then ++ echo "No error, but there should be one." ++ exit 3 ++fi +diff --git a/test/test-0103.sh b/test/test-0103.sh +new file mode 100755 +index 0000000..bccd8ed +--- /dev/null ++++ b/test/test-0103.sh +@@ -0,0 +1,16 @@ ++#!/bin/sh ++ ++. ./test-common.sh ++ ++cleanup 103 ++ ++# ------------------------------- Test 103 ------------------------------------ ++# test invalid config file with unknown keywords ++preptest test.log 103 1 ++ ++$RLR test-config.103 --force ++ ++if [ $? -eq 0 ]; then ++ echo "No error, but there should be one." ++ exit 3 ++fi +diff --git a/test/test-config.102.in b/test/test-config.102.in +new file mode 100644 +index 0000000..cbca4c4 +--- /dev/null ++++ b/test/test-config.102.in +@@ -0,0 +1,10 @@ ++ELF ++ ++&DIR&/test.log { ++ daily ++ size=0 ++ ++firstaction ++ /bin/sh -c "echo test123" ++ endscript ++} +diff --git a/test/test-config.103.in b/test/test-config.103.in +new file mode 100644 +index 0000000..ef4d19c +--- /dev/null ++++ b/test/test-config.103.in +@@ -0,0 +1,12 @@ ++random noise ++a b c d ++a::x ++ ++&DIR&/test.log { ++ daily ++ size=0 ++ ++firstaction ++ /bin/sh -c "echo test123" ++ endscript ++} diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/drop-world-readable-permission-on-state-file.patch logrotate-3.18.0/debian/patches/applied-upstream/drop-world-readable-permission-on-state-file.patch --- logrotate-3.18.0/debian/patches/applied-upstream/drop-world-readable-permission-on-state-file.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/drop-world-readable-permission-on-state-file.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,56 @@ +From: Kamil Dudka +Date: Wed, 25 May 2022 09:55:02 +0200 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/addbd293242b0b78aa54f054e6c1d249451f137d +Subject: drop world-readable permission on state file + +... even when ACLs are enabled. This is a follow-up to the fix +of CVE-2022-1348. It has no impact on security but makes the state +file locking work again in more cases. + +Closes: https://github.com/logrotate/logrotate/pull/446 +--- + logrotate.c | 10 +++++++--- + test/test-0048.sh | 1 + + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/logrotate.c b/logrotate.c +index 5f1b328..d110d54 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -2513,6 +2513,7 @@ static int writeState(const char *stateFilename) + struct tm now; + time_t now_time, last_time; + char *prevCtx; ++ int force_mode = 0; + + localtime_r(&nowSecs, &now); + +@@ -2580,10 +2581,13 @@ static int writeState(const char *stateFilename) + + close(fdcurr); + +- /* drop world-readable flag to prevent others from locking */ +- sb.st_mode &= ~(mode_t)S_IROTH; ++ if (sb.st_mode & (mode_t)S_IROTH) { ++ /* drop world-readable flag to prevent others from locking */ ++ sb.st_mode &= ~(mode_t)S_IROTH; ++ force_mode = 1; ++ } + +- fdsave = createOutputFile(tmpFilename, O_RDWR | O_CREAT | O_TRUNC, &sb, prev_acl, 0); ++ fdsave = createOutputFile(tmpFilename, O_RDWR | O_CREAT | O_TRUNC, &sb, prev_acl, force_mode); + #ifdef WITH_ACL + if (prev_acl) { + acl_free(prev_acl); +diff --git a/test/test-0048.sh b/test/test-0048.sh +index 62d606b..06b255a 100755 +--- a/test/test-0048.sh ++++ b/test/test-0048.sh +@@ -18,6 +18,7 @@ cat > state << EOF + logrotate state -- version 2 + EOF + ++chmod 0640 state + setfacl -m u:nobody:rwx state + + $RLR test-config.48 diff -Nru logrotate-3.18.0/debian/patches/applied-upstream/skip-locking-if-state-file-is-world-readable.patch logrotate-3.18.0/debian/patches/applied-upstream/skip-locking-if-state-file-is-world-readable.patch --- logrotate-3.18.0/debian/patches/applied-upstream/skip-locking-if-state-file-is-world-readable.patch 1970-01-01 00:00:00.000000000 +0000 +++ logrotate-3.18.0/debian/patches/applied-upstream/skip-locking-if-state-file-is-world-readable.patch 2022-01-30 16:29:14.000000000 +0000 @@ -0,0 +1,152 @@ +From: =?utf-8?q?Christian_G=C3=B6ttsche?= +Date: Tue, 29 Mar 2022 21:06:54 +0200 +Applied-Upstream: https://github.com/logrotate/logrotate/commit/1f76a381e2caa0603ae3dbc51ed0f1aa0d6658b9 +Subject: skip locking if state file is world-readable + +Fixes: CVE-2022-1348 - potential DoS from unprivileged users via the state file +Bug: https://bugzilla.redhat.com/CVE-2022-1348 +--- + logrotate.c | 24 ++++++++++++++++++++++-- + logrotate.spec.in | 3 +-- + test/Makefile.am | 1 + + test/test-0087.sh | 1 + + test/test-0092.sh | 19 +++++++++++++++++++ + test/test-config.92.in | 4 ++++ + 6 files changed, 48 insertions(+), 4 deletions(-) + create mode 100755 test/test-0092.sh + create mode 100644 test/test-config.92.in + +diff --git a/logrotate.c b/logrotate.c +index 322e3af..5f1b328 100644 +--- a/logrotate.c ++++ b/logrotate.c +@@ -2580,6 +2580,9 @@ static int writeState(const char *stateFilename) + + close(fdcurr); + ++ /* drop world-readable flag to prevent others from locking */ ++ sb.st_mode &= ~(mode_t)S_IROTH; ++ + fdsave = createOutputFile(tmpFilename, O_RDWR | O_CREAT | O_TRUNC, &sb, prev_acl, 0); + #ifdef WITH_ACL + if (prev_acl) { +@@ -2914,6 +2917,7 @@ static int readState(const char *stateFilename) + static int lockState(const char *stateFilename, int skip_state_lock) + { + int lockFd; ++ struct stat sb; + + if (!strcmp(stateFilename, "/dev/null")) { + return 0; +@@ -2925,9 +2929,9 @@ static int lockState(const char *stateFilename, int skip_state_lock) + message(MESS_DEBUG, "Creating stub state file: %s\n", + stateFilename); + +- /* create a stub state file with mode 0644 */ ++ /* create a stub state file with mode 0640 */ + lockFd = open(stateFilename, O_CREAT | O_EXCL | O_WRONLY, +- S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); ++ S_IWUSR | S_IRUSR | S_IRGRP); + if (lockFd == -1) { + message(MESS_ERROR, "error creating stub state file %s: %s\n", + stateFilename, strerror(errno)); +@@ -2947,6 +2951,22 @@ static int lockState(const char *stateFilename, int skip_state_lock) + return 0; + } + ++ if (fstat(lockFd, &sb) == -1) { ++ message(MESS_ERROR, "error stat()ing state file %s: %s\n", ++ stateFilename, strerror(errno)); ++ close(lockFd); ++ return 1; ++ } ++ ++ if (sb.st_mode & S_IROTH) { ++ message(MESS_ERROR, "state file %s is world-readable and thus can" ++ " be locked from other unprivileged users." ++ " Skipping lock acquisition...\n", ++ stateFilename); ++ close(lockFd); ++ return 0; ++ } ++ + if (flock(lockFd, LOCK_EX | LOCK_NB) == -1) { + if (errno == EWOULDBLOCK) { + message(MESS_ERROR, "state file %s is already locked\n" +diff --git a/logrotate.spec.in b/logrotate.spec.in +index 92e1d97..3caabf2 100644 +--- a/logrotate.spec.in ++++ b/logrotate.spec.in +@@ -41,7 +41,6 @@ install -p -m 644 examples/logrotate.conf $RPM_BUILD_ROOT%{_sysconfdir}/logrotat + install -p -m 644 examples/btmp $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/btmp + install -p -m 644 examples/wtmp $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/wtmp + install -p -m 755 examples/logrotate.cron $RPM_BUILD_ROOT%{_sysconfdir}/cron.daily/logrotate +-touch $RPM_BUILD_ROOT%{_localstatedir}/lib/logrotate.status + + %clean + rm -rf $RPM_BUILD_ROOT +@@ -55,4 +54,4 @@ rm -rf $RPM_BUILD_ROOT + %attr(0755, root, root) %{_sysconfdir}/cron.daily/logrotate + %attr(0644, root, root) %config(noreplace) %{_sysconfdir}/logrotate.conf + %attr(0755, root, root) %{_sysconfdir}/logrotate.d +-%attr(0644, root, root) %verify(not size md5 mtime) %config(noreplace) %{_localstatedir}/lib/logrotate.status ++%ghost %attr(0640, root, root) %verify(not size md5 mtime) %{_localstatedir}/lib/logrotate.status +diff --git a/test/Makefile.am b/test/Makefile.am +index d3ccd1b..f1a0062 100644 +--- a/test/Makefile.am ++++ b/test/Makefile.am +@@ -87,6 +87,7 @@ TEST_CASES = \ + test-0086.sh \ + test-0087.sh \ + test-0088.sh \ ++ test-0092.sh \ + test-0100.sh \ + test-0101.sh \ + test-0102.sh \ +diff --git a/test/test-0087.sh b/test/test-0087.sh +index 91e5266..aeff2c6 100755 +--- a/test/test-0087.sh ++++ b/test/test-0087.sh +@@ -8,6 +8,7 @@ cleanup 87 + preptest test.log 87 1 + + touch state ++chmod 0640 state + + $RLR test-config.87 -f & + +diff --git a/test/test-0092.sh b/test/test-0092.sh +new file mode 100755 +index 0000000..be52e14 +--- /dev/null ++++ b/test/test-0092.sh +@@ -0,0 +1,19 @@ ++#!/bin/sh ++ ++. ./test-common.sh ++ ++# check state file locking ++cleanup 92 ++ ++preptest test.log 92 1 ++ ++touch state ++chmod 0644 state ++flock state -c "sleep 10" & ++ ++$RLR -f test-config.92 || exit 23 ++ ++checkoutput < +Date: Sun, 30 Jan 2022 17:16:48 +0100 +Subject: replace ELF header in test case + +Reduces the noise from Lintian and avoid interferences with dbgsym package. +--- + test/test-config.102.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/test-config.102.in b/test/test-config.102.in +index cbca4c4..8641be4 100644 +--- a/test/test-config.102.in ++++ b/test/test-config.102.in +@@ -1,4 +1,4 @@ +-ELF ++<<<< + + &DIR&/test.log { + daily diff -Nru logrotate-3.18.0/debian/patches/series logrotate-3.18.0/debian/patches/series --- logrotate-3.18.0/debian/patches/series 2021-02-28 16:37:19.000000000 +0000 +++ logrotate-3.18.0/debian/patches/series 2022-01-30 16:29:14.000000000 +0000 @@ -2,5 +2,17 @@ applied-upstream/Only-attempt-to-set-user-group-if-running-as-root.patch applied-upstream/logrotate.8-make-the-var-log-news-example-consistent.patch applied-upstream/Fix-a-typo-in-the-example-logrotate.conf.patch +applied-upstream/Log-if-keyword-is-not-properly-separated.patch +applied-upstream/Log-error-on-keyword-parse-failure.patch +applied-upstream/Do-not-use-incorrect-stat-information.patch +applied-upstream/Remove-invalid-configuration-on-error.patch +applied-upstream/Do-not-warn-on-key-value-pair-separated-by-only-an-e.patch +applied-upstream/Fix-full_write-on-incomplete-write.patch +applied-upstream/config.c-enforce-stricter-parsing-of-config-files.patch +applied-upstream/Add-more-testcases-for-stricter-configuration-parsin.patch +applied-upstream/Do-not-lock-state-file-dev-null.patch +applied-upstream/skip-locking-if-state-file-is-world-readable.patch +applied-upstream/drop-world-readable-permission-on-state-file.patch debian/skip-cronjob-when-running-with-systemd.patch debian/logrotate.conf-disable-dateext-on-Debian.patch +debian/replace-ELF-header-in-test-case.patch