Race condition in tdb_runtime_check_for_robust_mutexes()

Jeremy Allison jra at samba.org
Fri Mar 25 18:50:15 UTC 2016


On Wed, Mar 23, 2016 at 01:02:48PM +0200, Uri Simchoni wrote:
> Here's a patch to fix the issue. I don't have confirmation that it
> fixes the issue but would like to continue the discussion on:
> a. Whether this is the right direction or should we eliminate the
> signal handler as Ralph suggested.
> b. The use of sigprocmask without #ifdefs, as opposed to installing
> and uninstalling the signal handler - it's hard as it is to get
> those things right, and I wonder whether we target envs which don't
> support sigprocmask. fork() hasn't #ifdefs around it ... :)

OK, I like this patch as clearly we need to make
the assignment to tdb_robust_mutex_pid atomic.

+1 from me.

> From 2a13235ca562c737633fdb69a8d93209d31a12bf Mon Sep 17 00:00:00 2001
> From: Uri Simchoni <uri at samba.org>
> Date: Wed, 23 Mar 2016 12:44:28 +0200
> Subject: [PATCH] tdb: avoid a race condition when checking for robust mutexes
> 
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=11808
> 
> Signed-off-by: Uri Simchoni <uri at samba.org>
> ---
>  lib/tdb/common/mutex.c | 33 ++++++++++++++++++++++++++++++---
>  1 file changed, 30 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/tdb/common/mutex.c b/lib/tdb/common/mutex.c
> index fae43d4..7fff452 100644
> --- a/lib/tdb/common/mutex.c
> +++ b/lib/tdb/common/mutex.c
> @@ -776,6 +776,8 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
>  	char c = 0;
>  	bool ok;
>  	int status;
> +	sigset_t block_sigmask, save_sigmask;
> +	pid_t child_pid;
>  	static bool initialized;
>  
>  	if (initialized) {
> @@ -833,6 +835,17 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
>  		goto cleanup_ma;
>  	}
>  
> +	/* block SIGCHLD so that forking and assigning to
> +	 * tdb_robust_mutex_pid is atomic
> +	 */
> +	sigemptyset(&block_sigmask);
> +	if (sigaddset(&block_sigmask, SIGCHLD) < 0) {
> +		goto cleanup_ma;
> +	}
> +	if (sigprocmask(SIG_BLOCK, &block_sigmask, &save_sigmask) < 0) {
> +		goto cleanup_ma;
> +	}
> +
>  	tdb_robust_mutex_pid = fork();
>  	if (tdb_robust_mutex_pid == 0) {
>  		size_t nwritten;
> @@ -853,7 +866,14 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
>  		/* leave locked */
>  		_exit(0);
>  	}
> -	if (tdb_robust_mutex_pid == -1) {
> +	child_pid = tdb_robust_mutex_pid;
> +	ret = sigprocmask(SIG_SETMASK, &save_sigmask, NULL);
> +	if (ret != 0) {
> +		/* we can't keep running with SIGCHLD blocked */
> +		abort();
> +	}
> +
> +	if (child_pid == -1) {
>  		goto cleanup_sig_child;
>  	}
>  	close(pipe_down[0]);
> @@ -887,11 +907,18 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
>  		pid_t pid;
>  
>  		errno = 0;
> -		pid = waitpid(tdb_robust_mutex_pid, &status, 0);
> -		if (pid == tdb_robust_mutex_pid) {
> +		pid = waitpid(child_pid, &status, 0);
> +		if (pid == child_pid) {
>  			tdb_robust_mutex_pid = -1;
>  			break;
>  		}
> +		/* if the signal handler collected the child
> +		 * for us, waitpid() returns with ECHILD
> +		 * and tdb_robust_mutex_pid is -1
> +		 */
> +		if (tdb_robust_mutex_pid == -1) {
> +			break;
> +		}
>  		if (pid == -1 && errno != EINTR) {
>  			goto cleanup_child;
>  		}
> -- 
> 2.5.0
> 




More information about the samba-technical mailing list