From e1144d5321f87bc72e6fb29b40cf7728125aa926 Mon Sep 17 00:00:00 2001 From: Bart Van Assche 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 --- libmultipath/checkers/tur.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c index c014b65..f724350 100644 --- a/libmultipath/checkers/tur.c +++ b/libmultipath/checkers/tur.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004 Christophe Varoqui */ +#include #include #include #include @@ -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