[Libguestfs] [nbdkit PATCH] nbd: Fix race during close

Richard W.M. Jones rjones at redhat.com
Thu Nov 8 10:50:19 UTC 2018


On Wed, Nov 07, 2018 at 08:22:30PM -0600, Eric Blake wrote:
> ThreadSanitizer [1] pointed out that in the nbd plugin, nbd_close() can
> attempt close() in the main thread while the worker thread is still
> attempting to start a read().  Normally, if the read() loses the race,
> it will get a harmless EBADF that exits the worker thread (which is what
> we want, as we are closing the connection anyway); but if another
> connection happens to start in that window, we could end up read()ing
> from the fd opened by the new connection, with disastrous results on the
> second connection.
> 
> [1] ./configure CXFLAGS=-fsanitize=thread LDFLAGS=-fsanitize=thread
> 
> Commits c70616f8 and 430f8141 tried to clean up deadlock during
> shutdown, but missed that without some sort of locking, a
> close-before-read was still possible. Swap lines so that pthread_join()
> now serves as the locking to ensure close is not attempted while
> another thread may be about to use the fd.
> 
> Thanks: Richard W.M. Jones
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
> 
> It took me a while to decipher how ThreadSanitizer actually tests
> this race, which gets reported as a Write guarded by a mutex [caused
> by close()] racing with an earlier Read [caused by read()].  I
> finally realized that linking with libtsan installs wrappers around
> the syscalls for read(), close(), etc. where the wrappers create an
> underlying mutex and read/write operations on sentinel memory, so that
> it can then reuse its memory race analysis it has for more typical
> data races.  The wrappers thus cause odd-looking reports for fd races
> (the report ends up claiming that Thread 1 performing close() lost a
> race to Thread 2 performing read() - even though the ACTUAL data race
> is only a bug when Thread 2 loses the race and read()s on an fd
> close()d by Thread 1 and possibly reused by Thread 3 in the meantime).
> 
>  plugins/nbd/nbd.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/plugins/nbd/nbd.c b/plugins/nbd/nbd.c
> index b9a4523..9130642 100644
> --- a/plugins/nbd/nbd.c
> +++ b/plugins/nbd/nbd.c
> @@ -575,9 +575,9 @@ nbd_close (void *handle)
>      nbd_request_raw (h, 0, NBD_CMD_DISC, 0, 0, 0, NULL);
>      shutdown (h->fd, SHUT_WR);
>    }
> -  close (h->fd);
>    if ((errno = pthread_join (h->reader, NULL)))
>      nbdkit_debug ("failed to join reader thread: %m");
> +  close (h->fd);
>    pthread_mutex_destroy (&h->write_lock);
>    pthread_mutex_destroy (&h->trans_lock);
>    free (h);
> -- 

Well spotted :-)  Thanks.

ACK.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://libguestfs.org




More information about the Libguestfs mailing list