Package: daemon
Version: 0.6.3-1
Severity: grave
Tags: patch

Among the code paths in libslack that are responsible for handling PID
files, there is a chance for race conditions: If a daemon process is
stopped and another instance that uses the same PID file is immediately
started, the new instance's attempt to create and lock the PID file my
coincide with the clean-up of the instance that is shutting down
(including unlinking "its" PID file.) If this happens, the freshly
started instance will hold a lock on a file that has been deleted. Later
attempts to stop it using the --stop parameter will fail.

I reported the bug to the upstream author and have since successfully
tested the fix attached below that was provided by him. Please consider
including it in the package.

Thanks,
-Hilko

-- System Information:
Debian Release: squeeze/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.32-4-amd64 (SMP w/2 CPU cores)
Locale: LANG=C, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages daemon depends on:
ii  libc6                         2.10.2-8   Embedded GNU C Library: Shared lib

daemon recommends no packages.

daemon suggests no packages.

-- no debconf information

diff --git a/libslack/daemon.c b/libslack/daemon.c
index 899cec4..f6c9298 100644
--- a/libslack/daemon.c
+++ b/libslack/daemon.c
@@ -617,7 +617,9 @@ C<errno> set appropriately.
 static int daemon_lock_pidfile(char *pidfile)
 {
        mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+       struct stat statbuf_fd[1], statbuf_fs[1];
        int pid_fd;
+       start:
 
        /* This is broken over NFS (Linux). So pidfiles must reside locally. */
 
@@ -634,11 +636,63 @@ static int daemon_lock_pidfile(char *pidfile)
                */
 
                if ((pid_fd = open(pidfile, O_RDWR)) == -1)
+               {
+                       /*
+                       ** We couldn't open the file. That means that it existed
+                       ** a moment ago but has been since been deleted. Maybe 
if
+                       ** we try again now, it'll work (unless another process 
is
+                       ** about to re-create it before we do, that is).
+                       */
+
+                       if (errno == ENOENT)
+                               goto start;
+
                        return -1;
+               }
        }
 
        if (fcntl_lock(pid_fd, F_SETLK, F_WRLCK, SEEK_SET, 0, 0) == -1)
+       {
+               close(pid_fd);
+               return -1;
+       }
+
+       /*
+       ** The pidfile may have been unlinked, after we opened, it by another 
daemon
+       ** process that was dying between the last open() and the fcntl(). 
There's
+       ** no use hanging on to a locked file that doesn't exist (and there's
+       ** nothing to stop another daemon process from creating and locking a
+       ** new instance of the file. So, if the pidfile has been deleted, we
+       ** abandon this lock and start again. Note that it may have been deleted
+       ** and subsequently re-created by yet another daemon process just 
starting
+       ** up so check that that hasn't happened as well by comparing inode
+       ** numbers. If it has, we also abandon this lock and start again.
+       */
+
+       if (fstat(pid_fd, statbuf_fd) == -1)
+       {
+               /* This shouldn't happen */
+               close(pid_fd);
+               return -1;
+       }
+
+       if (stat(pidfile, statbuf_fs) == -1)
+       {
+               /* The pidfile has been unlinked so we start again */
+               if (errno == ENOENT)
+               {
+                       close(pid_fd);
+                       goto start;
+               }
+               close(pid_fd);
                return -1;
+       }
+       else if (statbuf_fd->st_ino != statbuf_fs->st_ino)
+       {
+               /* The pidfile has been unlinked and re-created so we start 
again */
+               close(pid_fd);
+               goto start;
+       }
 
        return pid_fd;
 }



-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to