about summary refs log tree commit homepage
path: root/svc.c
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-10-12 07:00:58 +0000
committerEric Wong <normalperson@yhbt.net>2013-10-12 07:24:11 +0000
commite8217a1fe0cf341b7219a426f23e02cb44281301 (patch)
tree1d278c304ffdced66de855fad07ac2413336740e /svc.c
parenta4126a4bef3708c6f3b63f8a8877a3ce2213470b (diff)
downloadcmogstored-e8217a1fe0cf341b7219a426f23e02cb44281301.tar.gz
readdir on the same DIR pointer is undefined if DIR was inherited by
multiple children.  Using the reentrant readdir_r would not have
helped, since the underlying file descriptor and kernel file handle
were still shared (and we need rewinddir, too).

This readdir usage bug existed in cmogstored since the earliest
releases, but was harmless until the cmogstored 1.3 series.

This misuse of readdir lead to hitting a leftover call to free().
So this bug only manifested since
commit 1fab1e7a7f03f3bc0abb1b5181117f2d4605ce3b
(svc: implement top-level by_mog_devid hash)

Fortunately, these bugs only affect users of the undocumented
multi-process feature (not just multi-threaded).
Diffstat (limited to 'svc.c')
-rw-r--r--svc.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/svc.c b/svc.c
index 4a44493..86f69db 100644
--- a/svc.c
+++ b/svc.c
@@ -69,6 +69,35 @@ static void svc_once(void)
         atexit(svc_atexit);
 }
 
+bool mog_svc_atfork_child(void *svc_ptr, void *parent)
+{
+        struct mog_svc *svc = svc_ptr;
+        pid_t ppid = *((pid_t *)parent);
+        const char *failfn;
+
+        if (closedir(svc->dir) < 0) {
+                failfn = "closedir";
+                goto err;
+        }
+
+        svc->dir = opendir(svc->docroot);
+        if (svc->dir == NULL) {
+                failfn = "opendir";
+                goto err;
+        }
+
+        svc->docroot_fd = dirfd(svc->dir);
+        if (svc->docroot_fd < 0) {
+                failfn = "dirfd";
+                goto err;
+        }
+        return true;
+err:
+        syslog(LOG_ERR, "%s(%s) failed with: %m", failfn, svc->docroot);
+        kill(ppid, SIGTERM);
+        return false;
+}
+
 struct mog_svc * mog_svc_new(const char *docroot)
 {
         struct mog_svc *svc;