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 <mplch@redhat.com> - 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 <tmraz@redhat.com> - 1.4.11-19
 - fix URL and source URL of the package (#1501726)