From 435e7ce663b7e568086c5dc0fb1bb889e41a3ed1 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[EMAIL REDACTED]>
Date: Tue, 17 Oct 2023 21:41:30 -0500
Subject: [PATCH] Check for device disconnection in HIDAPI_JoystickOpen()
HIDAPI joystick drivers may call HIDAPI_JoystickDisconnected() in their
UpdateDevice() function during HIDAPI_JoystickOpen(). If they do this
today, the opened joystick will end up partially initialized (no name,
path, mapping GUID, etc.) because HIDAPI_GetDeviceByIndex() will no
longer be able to find the SDL_HIDAPI_Device for the removed joystick.
Worse still, joystick->hwdata->device becomes a dangling freed pointer
the next time HIDAPI_UpdateDeviceList() is called. This leads to a UAF
when the application or SDL calls SDL_JoystickClose() on this joystick.
Fix all this by checking if the device no longer has any associated
joysticks after calling UpdateDevice() and failing the open call if so.
---
src/joystick/hidapi/SDL_hidapijoystick.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index 06e6d2607a0c..7fa7da96a7dd 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -1440,6 +1440,12 @@ static int HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index)
device->updating = SDL_FALSE;
SDL_UnlockMutex(device->dev_lock);
+ /* UpdateDevice() may have called HIDAPI_JoystickDisconnected() if the device went away */
+ if (device->num_joysticks == 0) {
+ SDL_free(hwdata);
+ return SDL_SetError("HIDAPI device disconnected while opening");
+ }
+
if (!device->driver->OpenJoystick(device, joystick)) {
/* The open failed, mark this device as disconnected and update devices */
HIDAPI_JoystickDisconnected(device, joystickID);