SDL: Check for device disconnection in HIDAPI_JoystickOpen() (4aab2)

From 4aab2342e9aabc7e506952dbe5e021f3d3604929 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.

(cherry picked from commit 435e7ce663b7e568086c5dc0fb1bb889e41a3ed1)
 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 c0e5cd5d7d36..6eefe71ea27e 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -1436,6 +1436,12 @@ static int HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index)
     device->updating = SDL_FALSE;
+    /* 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);