Lock thread_pool.wait_mutex before forking to avoid a race condition between rad_fork...
authorJames Rouzier <jrouzier@inverse.ca>
Tue, 28 Oct 2014 21:13:43 +0000 (17:13 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 28 Oct 2014 21:41:11 +0000 (17:41 -0400)
There is a race condition that can occur under high load where a child is reaped before being added to the waiters list.

src/main/threads.c

index 011721c..636d688 100644 (file)
@@ -1258,6 +1258,7 @@ pid_t rad_fork(void)
        /*
         *      Fork & save the PID for later reaping.
         */
+       pthread_mutex_lock(&thread_pool.wait_mutex);
        child_pid = fork();
        if (child_pid > 0) {
                int rcode;
@@ -1268,9 +1269,7 @@ pid_t rad_fork(void)
 
                tf->pid = child_pid;
 
-               pthread_mutex_lock(&thread_pool.wait_mutex);
                rcode = fr_hash_table_insert(thread_pool.waiters, tf);
-               pthread_mutex_unlock(&thread_pool.wait_mutex);
 
                if (!rcode) {
                        ERROR("Failed to store PID, creating what will be a zombie process %d",
@@ -1278,6 +1277,12 @@ pid_t rad_fork(void)
                        free(tf);
                }
        }
+       /*
+        *      Do not unlock in child process
+        */
+       if(child_pid != 0 ) {
+               pthread_mutex_unlock(&thread_pool.wait_mutex);
+       }
 
        /*
         *      Return whatever we were told.