blob: f62e05ca78a6be1c0f55bb5dba9121ab421e1391 [file] [log] [blame]
commit d5240ff3e8485745e10b498236834177cd99edb9
Author: Fletcher Woodruff <fletcherw@chromium.org>
Date: Mon Jun 29 13:23:23 2020 -0600
usb: fix race condition in usb_conn_acquire
If we do not have an available usb connection at the start of
usb_conn_acquire, we sleep and poll for several seconds until a
connection becomes available.
However, this check is done without holding the pool_manage_lock. This
allows for a race condition where we read num_avail and get a non-zero
value, but then some other thread acquires the pool_manage_lock first
and claims that free interface, causing us to error out when we then try
to claim the interface.
To fix this, acquire the pool_manage_lock before checking num_avail. This way,
when we exit our poll loop that waits for an available interface, we will be
certain that interface will continue to be available until we claim it.
diff --git a/src/usb.c b/src/usb.c
index 905b90b..9412bb0 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -656,19 +656,6 @@ struct usb_conn_t *usb_conn_acquire(struct usb_sock_t *usb)
{
int i;
- if (usb->num_avail <= 0) {
- NOTE("All USB interfaces busy, waiting ...");
- for (i = 0; i < 30 && usb->num_avail <= 0; i ++) {
- if (get_terminate(&g_options))
- return NULL;
- usleep(100000);
- }
- if (usb->num_avail <= 0) {
- ERR("Timed out waiting for a free USB interface");
- return NULL;
- }
- }
-
struct usb_conn_t *conn = calloc(1, sizeof(*conn));
if (conn == NULL) {
ERR("Failed to alloc space for usb connection");
@@ -677,6 +664,23 @@ struct usb_conn_t *usb_conn_acquire(struct usb_sock_t *usb)
sem_wait(&usb->pool_manage_lock);
{
+ if (usb->num_avail <= 0) {
+ NOTE("All USB interfaces busy, waiting ...");
+ for (i = 0; i < 30 && usb->num_avail <= 0; i ++) {
+ if (get_terminate(&g_options))
+ goto acquire_error;
+
+ // Release the lock while we sleep.
+ sem_post(&usb->pool_manage_lock);
+ usleep(100000);
+ sem_wait(&usb->pool_manage_lock);
+ }
+ if (usb->num_avail <= 0) {
+ ERR("Timed out waiting for a free USB interface");
+ goto acquire_error;
+ }
+ }
+
conn->parent = usb;
uint32_t slot = usb->num_taken;