From ce59e6ea12852f25025fef5ef42da9e271049a59 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 6 Jun 2016 17:43:23 +0200 Subject: core: Fix unlocked access to timeout_flags There is a race between handle_timeout() and the completion functions. When one thread is in handle_timeout() and another thread wakes up from a poll(), there exists a window where the transfer has been cancelled, but USBI_TRANSFER_TIMED_OUT is not yet set in timeout_flags. Therefore, usbi_handle_transfer_completion() is sometimes called with LIBUSB_TRANSFER_CANCELLED instead of the expected LIBUSB_TRANSFER_TIMED_OUT. timeout_flags is protected by the flying_transfers_lock, this commit makes usbi_handle_transfer_cancellation() take that lock before checking for USBI_TRANSFER_TIMED_OUT in timeout_flags, fixing this. Reported-by: Joost Muller Signed-off-by: Hans de Goede --- libusb/io.c | 9 ++++++++- libusb/version_nano.h | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libusb/io.c b/libusb/io.c index aa6cfca..b3f7df0 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -1684,8 +1684,15 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, * will attempt to take the lock. */ int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer) { + struct libusb_context *ctx = ITRANSFER_CTX(transfer); + uint8_t timed_out; + + usbi_mutex_lock(&ctx->flying_transfers_lock); + timed_out = transfer->timeout_flags & USBI_TRANSFER_TIMED_OUT; + usbi_mutex_unlock(&ctx->flying_transfers_lock); + /* if the URB was cancelled due to timeout, report timeout to the user */ - if (transfer->timeout_flags & USBI_TRANSFER_TIMED_OUT) { + if (timed_out) { usbi_dbg("detected timeout cancellation"); return usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT); } diff --git a/libusb/version_nano.h b/libusb/version_nano.h index 6995b33..bb7624f 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11135 +#define LIBUSB_NANO 11137 -- cgit v1.2.1