Fixed bug 4486 - Segfault when pressing a trigger on the Steam Controller (Linux)
authorSam Lantinga <slouken@libsdl.org>
Wed, 12 Jun 2019 10:32:36 -0700
changeset 12846c54ce7eddcbe
parent 12845 5b0bc0ed588a
child 12847 baae9331abc0
Fixed bug 4486 - Segfault when pressing a trigger on the Steam Controller (Linux)

Matteo Beniamino

Pressing a trigger button on a Steam Controller causes a segmentation fault both with stable version and latest mercurial head on Linux. I'm using the recent hid_steam kernel module with lizard_mode disabled (that is no keyboard/mouse emulation). I suspect this is what's happening: the driver exposes two hats. The two hats have indices 0 and 2. Inside linux/SDL_sysjoystick.c two hats are allocated in allocate_hatdata for joystick->hwdata->hats. In HandleHat function the hat parameter (that can be 2) is directly used as the index of the array that only has two elements, causing an out of bounds access. SDL is not expecting to have "holes" between hats indices.

The index 2 is calculated in HandleInputEvents() as (ABS_HAT2X - ABS_HAT0X) / 2 where ABS_HAT2X is the value associated to the hat inside the hid_steam module.
src/joystick/linux/SDL_sysjoystick.c
src/joystick/linux/SDL_sysjoystick_c.h
     1.1 --- a/src/joystick/linux/SDL_sysjoystick.c	Wed Jun 12 07:55:48 2019 -0700
     1.2 +++ b/src/joystick/linux/SDL_sysjoystick.c	Wed Jun 12 10:32:36 2019 -0700
     1.3 @@ -609,17 +609,18 @@
     1.4          for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
     1.5              if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
     1.6                  struct input_absinfo absinfo;
     1.7 +                int hat_index = (i - ABS_HAT0X) / 2;
     1.8  
     1.9                  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
    1.10                      continue;
    1.11                  }
    1.12  #ifdef DEBUG_INPUT_EVENTS
    1.13 -                printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
    1.14 +                printf("Joystick has hat %d\n", hat_index);
    1.15                  printf("Values = { %d, %d, %d, %d, %d }\n",
    1.16                         absinfo.value, absinfo.minimum, absinfo.maximum,
    1.17                         absinfo.fuzz, absinfo.flat);
    1.18  #endif /* DEBUG_INPUT_EVENTS */
    1.19 -                ++joystick->nhats;
    1.20 +                joystick->hwdata->hats_indices[joystick->nhats++] = hat_index;
    1.21              }
    1.22          }
    1.23          if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
    1.24 @@ -762,7 +763,7 @@
    1.25          {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
    1.26      };
    1.27  
    1.28 -    the_hat = &stick->hwdata->hats[hat];
    1.29 +    the_hat = &stick->hwdata->hats[stick->hwdata->hats_indices[hat]];
    1.30      if (value < 0) {
    1.31          value = 0;
    1.32      } else if (value == 0) {
     2.1 --- a/src/joystick/linux/SDL_sysjoystick_c.h	Wed Jun 12 07:55:48 2019 -0700
     2.2 +++ b/src/joystick/linux/SDL_sysjoystick_c.h	Wed Jun 12 10:32:36 2019 -0700
     2.3 @@ -62,6 +62,8 @@
     2.4  
     2.5      /* Steam Controller support */
     2.6      SDL_bool m_bSteamController;
     2.7 +    /* 4 = (ABS_HAT3X-ABS_HAT0X)/2 (see input-event-codes.h in kernel) */
     2.8 +    int hats_indices[4];
     2.9  };
    2.10  
    2.11  #endif /* SDL_sysjoystick_c_h_ */