>From e1144d5321f87bc72e6fb29b40cf7728125aa926 Mon Sep 17 00:00:00 2001
From: Bart Van Assche <bart.vanassche@sandisk.com>
Date: Wed, 17 Aug 2016 09:58:09 -0700
Subject: [PATCH 3/3] libmultipath/checkers/tur: Fix race related to thread
termination
Since the tur thread is a detached thread, all data structures
associated with that thread are freed once the thread stops. Avoid
that pthread_cancel() triggers a use-after-free by protecting
pthread_cancel() calls with the same spinlock that protects ct->thread.
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
---
libmultipath/checkers/tur.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
@@ -3,6 +3,7 @@
*
* Copyright (c) 2004 Christophe Varoqui
*/
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -98,10 +99,11 @@ void libcheck_free (struct checker * c)
ct->holders--;
holders = ct->holders;
thread = ct->thread;
- pthread_spin_unlock(&ct->hldr_lock);
if (holders)
pthread_cancel(thread);
- else
+ pthread_spin_unlock(&ct->hldr_lock);
+
+ if (!holders)
cleanup_context(ct);
c->context = NULL;
}
@@ -207,6 +209,7 @@ void cleanup_func(void *data)
int holders;
struct tur_checker_context *ct = data;
pthread_spin_lock(&ct->hldr_lock);
+ assert(ct->holders > 0);
ct->holders--;
holders = ct->holders;
ct->thread = 0;
@@ -310,7 +313,12 @@ libcheck_check (struct checker * c)
if (tur_check_async_timeout(c)) {
condlog(3, "%d:%d: tur checker timeout",
TUR_DEVT(ct));
- pthread_cancel(ct->thread);
+
+ pthread_spin_lock(&ct->hldr_lock);
+ if (ct->holders > 0)
+ pthread_cancel(ct->thread);
+ pthread_spin_unlock(&ct->hldr_lock);
+
ct->running = 0;
MSG(c, MSG_TUR_TIMEOUT);
tur_status = PATH_TIMEOUT;
@@ -349,9 +357,9 @@ libcheck_check (struct checker * c)
if (r) {
pthread_spin_lock(&ct->hldr_lock);
ct->holders--;
+ ct->thread = 0;
pthread_spin_unlock(&ct->hldr_lock);
pthread_mutex_unlock(&ct->lock);
- ct->thread = 0;
condlog(3, "%d:%d: failed to start tur thread, using"
" sync mode", TUR_DEVT(ct));
return tur_check(c->fd, c->timeout, c->message);
--
2.9.2