joystick: Allow libudev to be disabled at runtime Device enumeration via libudev can fail in a container for two reasons: * the netlink protocol between udevd and libudev is considered private, so there is no API guarantee that the version of libudev in a container will understand netlink messages from a dissimilar version of udevd on the host system; * the netlink protocol between udevd and libudev relies for security on being able to check the uid of each message, but in a container with a user namespace where host uid 0 is not mapped, the libudev client cannot distinguish between messages from host uid 0 and messages from a different, malicious user on the host To make this easier to experiment with, always compile the fallback code path even if libudev is disabled. libudev remains the default if enabled at compile time, but the fallback code path can be forced. Signed-off-by: Simon McVittie <smcv@collabora.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index e41e5d9..0d10799 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -84,6 +84,19 @@
#define DEBUG_INPUT_EVENTS 1
#endif
+typedef enum
+{
+ ENUMERATION_UNSET,
+ ENUMERATION_LIBUDEV,
+ ENUMERATION_FALLBACK
+} EnumerationMethod;
+
+#if SDL_USE_LIBUDEV
+static EnumerationMethod enumeration_method = ENUMERATION_UNSET;
+#else
+const EnumerationMethod enumeration_method = ENUMERATION_FALLBACK;
+#endif
+
static int MaybeAddDevice(const char *path);
#if SDL_USE_LIBUDEV
static int MaybeRemoveDevice(const char *path);
@@ -108,10 +121,8 @@ static SDL_joylist_item *SDL_joylist = NULL;
static SDL_joylist_item *SDL_joylist_tail = NULL;
static int numjoysticks = 0;
-#if !SDL_USE_LIBUDEV
static Uint32 last_joy_detect_time;
static time_t last_input_dir_mtime;
-#endif
#define test_bit(nr, addr) \
(((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
@@ -147,15 +158,8 @@ IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *nam
#endif /* SDL_JOYSTICK_HIDAPI */
static int
-IsJoystick(int fd, char **name_return, SDL_JoystickGUID *guid)
+GuessIsJoystick(int fd)
{
- struct input_id inpid;
- Uint16 *guid16 = (Uint16 *)guid->data;
- char *name;
- char product_string[128];
-
-#if !SDL_USE_LIBUDEV
- /* When udev is enabled we only get joystick devices here, so there's no need to test them */
unsigned long evbit[NBITS(EV_MAX)] = { 0 };
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
@@ -170,7 +174,22 @@ IsJoystick(int fd, char **name_return, SDL_JoystickGUID *guid)
test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
return 0;
}
-#endif
+
+ return 1;
+}
+
+static int
+IsJoystick(int fd, char **name_return, SDL_JoystickGUID *guid)
+{
+ struct input_id inpid;
+ Uint16 *guid16 = (Uint16 *)guid->data;
+ char *name;
+ char product_string[128];
+
+ /* When udev is enabled we only get joystick devices here, so there's no need to test them */
+ if (enumeration_method == ENUMERATION_FALLBACK && !GuessIsJoystick(fd)) {
+ return 0;
+ }
if (ioctl(fd, EVIOCGID, &inpid) < 0) {
return 0;
@@ -484,11 +503,8 @@ static void SteamControllerDisconnectedCallback(int device_instance)
}
static void
-LINUX_JoystickDetect(void)
+LINUX_FallbackJoystickDetect(void)
{
-#if SDL_USE_LIBUDEV
- SDL_UDEV_Poll();
-#else
const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */
Uint32 now = SDL_GetTicks();
@@ -519,7 +535,20 @@ LINUX_JoystickDetect(void)
last_joy_detect_time = now;
}
+}
+
+static void
+LINUX_JoystickDetect(void)
+{
+#if SDL_USE_LIBUDEV
+ if (enumeration_method == ENUMERATION_LIBUDEV) {
+ SDL_UDEV_Poll();
+ }
+ else
#endif
+ {
+ LINUX_FallbackJoystickDetect();
+ }
HandlePendingRemovals();
@@ -529,6 +558,17 @@ LINUX_JoystickDetect(void)
static int
LINUX_JoystickInit(void)
{
+#if SDL_USE_LIBUDEV
+ if (enumeration_method == ENUMERATION_UNSET) {
+ if (SDL_getenv("SDL_JOYSTICK_DISABLE_UDEV") != NULL) {
+ enumeration_method = ENUMERATION_FALLBACK;
+ }
+ else {
+ enumeration_method = ENUMERATION_LIBUDEV;
+ }
+ }
+#endif
+
/* First see if the user specified one or more joysticks to use */
if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
char *envcopy, *envpath, *delim;
@@ -549,26 +589,30 @@ LINUX_JoystickInit(void)
SteamControllerDisconnectedCallback);
#if SDL_USE_LIBUDEV
- if (SDL_UDEV_Init() < 0) {
- return SDL_SetError("Could not initialize UDEV");
- }
-
- /* Set up the udev callback */
- if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
- SDL_UDEV_Quit();
- return SDL_SetError("Could not set up joystick <-> udev callback");
- }
+ if (enumeration_method == ENUMERATION_LIBUDEV) {
+ if (SDL_UDEV_Init() < 0) {
+ return SDL_SetError("Could not initialize UDEV");
+ }
- /* Force a scan to build the initial device list */
- SDL_UDEV_Scan();
-#else
- /* Force immediate joystick detection */
- last_joy_detect_time = 0;
- last_input_dir_mtime = 0;
+ /* Set up the udev callback */
+ if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
+ SDL_UDEV_Quit();
+ return SDL_SetError("Could not set up joystick <-> udev callback");
+ }
- /* Report all devices currently present */
- LINUX_JoystickDetect();
+ /* Force a scan to build the initial device list */
+ SDL_UDEV_Scan();
+ }
+ else
#endif
+ {
+ /* Force immediate joystick detection */
+ last_joy_detect_time = 0;
+ last_input_dir_mtime = 0;
+
+ /* Report all devices currently present */
+ LINUX_JoystickDetect();
+ }
return 0;
}
@@ -1191,8 +1235,10 @@ LINUX_JoystickQuit(void)
numjoysticks = 0;
#if SDL_USE_LIBUDEV
- SDL_UDEV_DelCallback(joystick_udev_callback);
- SDL_UDEV_Quit();
+ if (enumeration_method == ENUMERATION_LIBUDEV) {
+ SDL_UDEV_DelCallback(joystick_udev_callback);
+ SDL_UDEV_Quit();
+ }
#endif
SDL_QuitSteamControllers();