From 9eda222ac8b53d5b3ed10ee1f2af8739d9e9adfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 29 Mar 2022 21:06:54 +0200 Subject: [PATCH v2] 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 | 20 ++++++++++++++++++++ test/test-config.92.in | 4 ++++ 6 files changed, 49 insertions(+), 4 deletions(-) create mode 100755 test/test-0092.sh create mode 100644 test/test-config.92.in Index: logrotate-3.18.1/logrotate.c =================================================================== --- logrotate-3.18.1.orig/logrotate.c +++ logrotate-3.18.1/logrotate.c @@ -2581,6 +2581,9 @@ static int writeState(const char *stateF 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,15 +2917,17 @@ static int readState(const char *stateFi static int lockState(const char *stateFilename, int skip_state_lock) { + struct stat sb; + int lockFd = open(stateFilename, O_RDWR | O_CLOEXEC); if (lockFd == -1) { if (errno == ENOENT) { 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)); @@ -2940,6 +2945,22 @@ static int lockState(const char *stateFi stateFilename); close(lockFd); 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) { Index: logrotate-3.18.1/logrotate.spec.in =================================================================== --- logrotate-3.18.1.orig/logrotate.spec.in +++ logrotate-3.18.1/logrotate.spec.in @@ -41,7 +41,6 @@ install -p -m 644 examples/logrotate.con 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 Index: logrotate-3.18.1/test/Makefile.am =================================================================== --- logrotate-3.18.1.orig/test/Makefile.am +++ logrotate-3.18.1/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 Index: logrotate-3.18.1/test/test-0087.sh =================================================================== --- logrotate-3.18.1.orig/test/test-0087.sh +++ logrotate-3.18.1/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 & Index: logrotate-3.18.1/test/test-0092.sh =================================================================== --- /dev/null +++ logrotate-3.18.1/test/test-0092.sh @@ -0,0 +1,20 @@ +#!/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 <