From 68a439d76d9dad091c7bf0272d56fe394848cffe Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 19 2018 17:04:29 +0000 Subject: import cronie-1.4.11-20.el7_6 --- diff --git a/SOURCES/cronie-1.4.11-race-on-crontab-modification.patch b/SOURCES/cronie-1.4.11-race-on-crontab-modification.patch new file mode 100644 index 0000000..6374b96 --- /dev/null +++ b/SOURCES/cronie-1.4.11-race-on-crontab-modification.patch @@ -0,0 +1,114 @@ +diff -ru cronie-1.4.11/src/database.c cronie-1.4.11_patched/src/database.c +--- cronie-1.4.11/src/database.c 2018-10-19 15:29:55.630225195 +0200 ++++ cronie-1.4.11_patched/src/database.c 2018-10-19 15:32:14.552093860 +0200 +@@ -48,6 +48,7 @@ + #include "pathnames.h" + + #define TMAX(a,b) ((a)>(b)?(a):(b)) ++#define TMIN(a,b) ((a)<(b)?(a):(b)) + + /* size of the event structure, not counting name */ + #define EVENT_SIZE (sizeof (struct inotify_event)) +@@ -237,6 +238,8 @@ + if ((crontab_fd = check_open(tabname, uname, pw, &mtime)) == -1) + goto next_crontab; + ++ mtime = TMIN(new_db->mtime, mtime); ++ + Debug(DLOAD, ("\t%s:", fname)); + + if (old_db != NULL) +@@ -261,7 +264,7 @@ + * we finish with the crontab... + */ + Debug(DLOAD, (" [delete old data]")); +- unlink_user(old_db, u); ++ unlink_user(old_db, u); + free_user(u); + log_it(fname, getpid(), "RELOAD", tabname, 0); + } +@@ -328,18 +331,18 @@ + cron_db new_db; + DIR_T *dp; + DIR *dir; +- struct timeval time; ++ struct timeval timev; + fd_set rfds; + int retval; + char buf[BUF_LEN]; + pid_t pid = getpid(); +- time.tv_sec = 0; +- time.tv_usec = 0; ++ timev.tv_sec = 0; ++ timev.tv_usec = 0; + + FD_ZERO(&rfds); + FD_SET(old_db->ifd, &rfds); + +- retval = select(old_db->ifd + 1, &rfds, NULL, NULL, &time); ++ retval = select(old_db->ifd + 1, &rfds, NULL, NULL, &timev); + if (retval == -1) { + if (errno != EINTR) + log_it("CRON", pid, "INOTIFY", "select failed", errno); +@@ -348,6 +351,7 @@ + else if (FD_ISSET(old_db->ifd, &rfds)) { + new_db.head = new_db.tail = NULL; + new_db.ifd = old_db->ifd; ++ new_db.mtime = time(NULL) - 1; + while ((retval = read(old_db->ifd, buf, sizeof (buf))) == -1 && + errno == EINTR) ; + +@@ -452,14 +456,17 @@ + DIR *dir; + pid_t pid = getpid(); + int is_local = 0; ++ time_t now; + + Debug(DLOAD, ("[%ld] load_database()\n", (long) pid)); + +- /* before we start loading any data, do a stat on SPOOL_DIR +- * so that if anything changes as of this moment (i.e., before we've +- * cached any of the database), we'll see the changes next time. +- */ +- if (stat(SPOOL_DIR, &statbuf) < OK) { ++ now = time(NULL); ++ ++ /* before we start loading any data, do a stat on SPOOL_DIR ++ * so that if anything changes as of this moment (i.e., before we've ++ * cached any of the database), we'll see the changes next time. ++ */ ++ if (stat(SPOOL_DIR, &statbuf) < OK) { + log_it("CRON", pid, "STAT FAILED", SPOOL_DIR, errno); + statbuf.st_mtime = 0; + } +@@ -492,13 +499,17 @@ + * Note that old_db->mtime is initialized to 0 in main(), and + * so is guaranteed to be different than the stat() mtime the first + * time this function is called. ++ * ++ * We also use now - 1 as the upper bound of timestamp to avoid race, ++ * when a crontab is updated twice in a single second when we are ++ * just reading it. + */ +- if (old_db->mtime == TMAX(crond_stat.st_mtime, +- TMAX(statbuf.st_mtime, syscron_stat.st_mtime)) ++ if (old_db->mtime == TMIN(now - 1, TMAX(crond_stat.st_mtime, ++ TMAX(statbuf.st_mtime, syscron_stat.st_mtime))) + ) { + Debug(DLOAD, ("[%ld] spool dir mtime unch, no load needed.\n", + (long) pid)); +- return 0; ++ return 0; + } + + /* something's different. make a new database, moving unchanged +@@ -506,8 +517,7 @@ + * actually changed. Whatever is left in the old database when + * we're done is chaff -- crontabs that disappeared. + */ +- new_db.mtime = TMAX(crond_stat.st_mtime, +- TMAX(statbuf.st_mtime, syscron_stat.st_mtime)); ++ new_db.mtime = now - 1; + new_db.head = new_db.tail = NULL; + #if defined WITH_INOTIFY + new_db.ifd = old_db->ifd; diff --git a/SPECS/cronie.spec b/SPECS/cronie.spec index a9259c9..fc9da10 100644 --- a/SPECS/cronie.spec +++ b/SPECS/cronie.spec @@ -6,7 +6,7 @@ Summary: Cron daemon for executing programs at set times Name: cronie Version: 1.4.11 -Release: 19%{?dist} +Release: 20%{?dist} License: MIT and BSD and ISC and GPLv2+ Group: System Environment/Base URL: https://github.com/cronie-crond/cronie @@ -27,6 +27,7 @@ Patch11: cronie-1.4.11-man-file.patch Patch12: cronie-1.4.11-selinux-user.patch Patch13: cronie-1.4.11-no-pam.patch Patch14: cronie-1.4.11-empty-var.patch +Patch15: cronie-1.4.11-race-on-crontab-modification.patch Requires: dailyjobs @@ -106,6 +107,7 @@ extra features. %patch12 -p1 -b .selinux-user %patch13 -p1 -b .no-pam %patch14 -p1 -b .empty-var +%patch15 -p1 -b .race-cond %build %configure \ @@ -230,6 +232,11 @@ exit 0 %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/cron.d/dailyjobs %changelog +* Tue Oct 23 2018 Marcel Plch - 1.4.11-20 +- Fix race condition when crontab is modified the same second + before and after reading the crontab +- Resolves: rhbz#1638691 + * Mon Oct 16 2017 Tomáš Mráz - 1.4.11-19 - fix URL and source URL of the package (#1501726)