Date: Tue, 31 Jan 2012 11:49:32 -0500 From: John Baldwin <jhb@freebsd.org> To: current@freebsd.org Subject: Race between cron and crontab Message-ID: <201201311149.32760.jhb@freebsd.org>
index | next in thread | raw e-mail
A co-worker ran into a race between updating a cron tab via crontab(8) and
cron(8) yesterday. Specifically, cron(8) failed to notice that a crontab was
updated. The problem is that 1) by default our filesystems only use second
granularity for timestamps and 2) cron only caches the seconds portion of a
file's timestamp when checking for changes anyway. This means that cron can
miss updates to a spool directory if multiple updates to the directory are
performed within a single second and cron wakes up to scan the spool directory
within the same second and scans it before all of the updates are complete.
Specifically, when replacing a crontab, crontab(8) first creates a temporary
file in /var/cron/tabs and then uses a rename to install it followed by
touching the spool directory to update its modification time. However, the
creation of the temporary file already changes the modification time of the
directory, and cron may "miss" the rename if it scans the directory in between
the creation of the temporary file and the rename.
The "fix" I am planning to use locally is to simply force crontab(8) to sleep
for a second before it touches the spool directory, thus ensuring that it the
touch of the spool directory will use a later modification time than the
creation of the temporary file.
Note that crontab -r is not affected by this race as it only does one atomic
update to the directory (unlink()).
Index: crontab.c
===================================================================
--- crontab.c (revision 225431)
+++ crontab.c (working copy)
@@ -604,6 +604,15 @@ replace_cmd() {
log_it(RealUser, Pid, "REPLACE", User);
+ /*
+ * Creating the 'tn' temp file has already updated the
+ * modification time of the spool directory. Sleep for a
+ * second to ensure that poke_daemon() sets a later
+ * modification time. Otherwise, this can race with the cron
+ * daemon scanning for updated crontabs.
+ */
+ sleep(1);
+
poke_daemon();
return (0);
--
John Baldwin
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201311149.32760.jhb>
