Minor robustness fixes for debugging.
[exim.git] / src / src / exim_lock.c
index 15f0d285c7c6e02d4d06a731a3689863b25e9b47..0c60ce107c5ae8c8095f4fc62185d788f1940b70 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/exim_lock.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */
+/* $Cambridge: exim/src/src/exim_lock.c,v 1.4 2010/05/29 12:11:48 pdp Exp $ */
 
 /* A program to lock a file exactly as Exim would, for investigation of
 interlocking problems.
@@ -310,7 +310,8 @@ if (use_lockfile)
 for (j = 0; j < lock_retries; j++)
   {
   int sleep_before_retry = TRUE;
-  struct stat statbuf, ostatbuf;
+  struct stat statbuf, ostatbuf, lstatbuf, statbuf2;
+  int mbx_tmp_oflags;
 
   /* Try to build a lock file if so configured */
 
@@ -329,7 +330,7 @@ for (j = 0; j < lock_retries; j++)
     /* Apply hitching post algorithm. */
 
     if ((rc = link(hitchname, lockname)) != 0) fstat(hd, &statbuf);
-    close(hd);
+    (void)close(hd);
     unlink(hitchname);
 
     if (rc != 0 && statbuf.st_nlink != 2)
@@ -431,7 +432,11 @@ for (j = 0; j < lock_retries; j++)
         }
       }
 
-    md = open(tempname, O_RDWR | O_CREAT, 0600);
+    mbx_tmp_oflags = O_RDWR | O_CREAT;
+#ifdef O_NOFOLLOW
+    mbx_tmp_oflags |= O_NOFOLLOW;
+#endif
+    md = open(tempname, mbx_tmp_oflags, 0600);
     if (md < 0)
       {
       printf("exim_lock: failed to create mbx lock file %s: %s\n",
@@ -439,7 +444,31 @@ for (j = 0; j < lock_retries; j++)
       goto CLEAN_UP;
       }
 
-    chmod (tempname, 0600);
+    /* security fixes from 2010-05 */
+    if (lstat(tempname, &lstatbuf) < 0)
+      {
+      printf("exim_lock: failed to lstat(%s) after opening it: %s\n",
+          tempname, strerror(errno));
+      goto CLEAN_UP;
+      }
+    if (fstat(md, &statbuf2) < 0)
+      {
+      printf("exim_lock: failed to fstat() open fd of \"%s\": %s\n",
+          tempname, strerror(errno));
+      goto CLEAN_UP;
+      }
+    if ((statbuf2.st_nlink > 1) ||
+        (lstatbuf.st_nlink > 1) ||
+        (!S_ISREG(lstatbuf.st_mode)) ||
+        (lstatbuf.st_dev != statbuf2.st_dev) ||
+        (lstatbuf.st_ino != statbuf2.st_ino))
+      {
+      printf("exim_lock: race condition exploited against us when "
+          "locking \"%s\"\n", tempname);
+      goto CLEAN_UP;
+      }
+
+    (void)chmod(tempname, 0600);
 
     if (apply_lock(md, F_WRLCK, use_fcntl, lock_fcntl_timeout, use_flock,
         lock_flock_timeout) >= 0)
@@ -551,12 +580,12 @@ if (restore_times)
   struct stat strestore;
   struct utimbuf ut;
   stat(filename, &strestore);
-  system(command);
+  (void)system(command);
   ut.actime = strestore.st_atime;
   ut.modtime = strestore.st_mtime;
   utime(filename, &ut);
   }
-else system(command);
+else (void)system(command);
 
 /* Remove the locks and exit. Unlink the /tmp file if we can get an exclusive
 lock on the mailbox. This should be a non-blocking lock call, as there is no