]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Jun 2024 12:32:53 +0000 (14:32 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Jun 2024 12:32:53 +0000 (14:32 +0200)
added patches:
input-try-trimming-too-long-modalias-strings.patch

queue-5.4/input-try-trimming-too-long-modalias-strings.patch [new file with mode: 0644]
queue-5.4/series

diff --git a/queue-5.4/input-try-trimming-too-long-modalias-strings.patch b/queue-5.4/input-try-trimming-too-long-modalias-strings.patch
new file mode 100644 (file)
index 0000000..f041724
--- /dev/null
@@ -0,0 +1,212 @@
+From 0774d19038c496f0c3602fb505c43e1b2d8eed85 Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Mon, 29 Apr 2024 14:50:41 -0700
+Subject: Input: try trimming too long modalias strings
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+commit 0774d19038c496f0c3602fb505c43e1b2d8eed85 upstream.
+
+If an input device declares too many capability bits then modalias
+string for such device may become too long and not fit into uevent
+buffer, resulting in failure of sending said uevent. This, in turn,
+may prevent userspace from recognizing existence of such devices.
+
+This is typically not a concern for real hardware devices as they have
+limited number of keys, but happen with synthetic devices such as
+ones created by xen-kbdfront driver, which creates devices as being
+capable of delivering all possible keys, since it doesn't know what
+keys the backend may produce.
+
+To deal with such devices input core will attempt to trim key data,
+in the hope that the rest of modalias string will fit in the given
+buffer. When trimming key data it will indicate that it is not
+complete by placing "+," sign, resulting in conversions like this:
+
+old: k71,72,73,74,78,7A,7B,7C,7D,8E,9E,A4,AD,E0,E1,E4,F8,174,
+new: k71,72,73,74,78,7A,7B,7C,+,
+
+This should allow existing udev rules continue to work with existing
+devices, and will also allow writing more complex rules that would
+recognize trimmed modalias and check input device characteristics by
+other means (for example by parsing KEY= data in uevent or parsing
+input device sysfs attributes).
+
+Note that the driver core may try adding more uevent environment
+variables once input core is done adding its own, so when forming
+modalias we can not use the entire available buffer, so we reduce
+it by somewhat an arbitrary amount (96 bytes).
+
+Reported-by: Jason Andryuk <jandryuk@gmail.com>
+Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
+Tested-by: Jason Andryuk <jandryuk@gmail.com>
+Link: https://lore.kernel.org/r/ZjAWMQCJdrxZkvkB@google.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
+---
+
+---
+ drivers/input/input.c |  105 ++++++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 90 insertions(+), 15 deletions(-)
+
+--- a/drivers/input/input.c
++++ b/drivers/input/input.c
+@@ -1358,19 +1358,19 @@ static int input_print_modalias_bits(cha
+                                    char name, unsigned long *bm,
+                                    unsigned int min_bit, unsigned int max_bit)
+ {
+-      int len = 0, i;
++      int bit = min_bit;
++      int len = 0;
+       len += snprintf(buf, max(size, 0), "%c", name);
+-      for (i = min_bit; i < max_bit; i++)
+-              if (bm[BIT_WORD(i)] & BIT_MASK(i))
+-                      len += snprintf(buf + len, max(size - len, 0), "%X,", i);
++      for_each_set_bit_from(bit, bm, max_bit)
++              len += snprintf(buf + len, max(size - len, 0), "%X,", bit);
+       return len;
+ }
+-static int input_print_modalias(char *buf, int size, struct input_dev *id,
+-                              int add_cr)
++static int input_print_modalias_parts(char *buf, int size, int full_len,
++                                    struct input_dev *id)
+ {
+-      int len;
++      int len, klen, remainder, space;
+       len = snprintf(buf, max(size, 0),
+                      "input:b%04Xv%04Xp%04Xe%04X-",
+@@ -1379,8 +1379,49 @@ static int input_print_modalias(char *bu
+       len += input_print_modalias_bits(buf + len, size - len,
+                               'e', id->evbit, 0, EV_MAX);
+-      len += input_print_modalias_bits(buf + len, size - len,
++
++      /*
++       * Calculate the remaining space in the buffer making sure we
++       * have place for the terminating 0.
++       */
++      space = max(size - (len + 1), 0);
++
++      klen = input_print_modalias_bits(buf + len, size - len,
+                               'k', id->keybit, KEY_MIN_INTERESTING, KEY_MAX);
++      len += klen;
++
++      /*
++       * If we have more data than we can fit in the buffer, check
++       * if we can trim key data to fit in the rest. We will indicate
++       * that key data is incomplete by adding "+" sign at the end, like
++       * this: * "k1,2,3,45,+,".
++       *
++       * Note that we shortest key info (if present) is "k+," so we
++       * can only try to trim if key data is longer than that.
++       */
++      if (full_len && size < full_len + 1 && klen > 3) {
++              remainder = full_len - len;
++              /*
++               * We can only trim if we have space for the remainder
++               * and also for at least "k+," which is 3 more characters.
++               */
++              if (remainder <= space - 3) {
++                      int i;
++                      /*
++                       * We are guaranteed to have 'k' in the buffer, so
++                       * we need at least 3 additional bytes for storing
++                       * "+," in addition to the remainder.
++                       */
++                      for (i = size - 1 - remainder - 3; i >= 0; i--) {
++                              if (buf[i] == 'k' || buf[i] == ',') {
++                                      strcpy(buf + i + 1, "+,");
++                                      len = i + 3; /* Not counting '\0' */
++                                      break;
++                              }
++                      }
++              }
++      }
++
+       len += input_print_modalias_bits(buf + len, size - len,
+                               'r', id->relbit, 0, REL_MAX);
+       len += input_print_modalias_bits(buf + len, size - len,
+@@ -1396,12 +1437,25 @@ static int input_print_modalias(char *bu
+       len += input_print_modalias_bits(buf + len, size - len,
+                               'w', id->swbit, 0, SW_MAX);
+-      if (add_cr)
+-              len += snprintf(buf + len, max(size - len, 0), "\n");
+-
+       return len;
+ }
++static int input_print_modalias(char *buf, int size, struct input_dev *id)
++{
++      int full_len;
++
++      /*
++       * Printing is done in 2 passes: first one figures out total length
++       * needed for the modalias string, second one will try to trim key
++       * data in case when buffer is too small for the entire modalias.
++       * If the buffer is too small regardless, it will fill as much as it
++       * can (without trimming key data) into the buffer and leave it to
++       * the caller to figure out what to do with the result.
++       */
++      full_len = input_print_modalias_parts(NULL, 0, 0, id);
++      return input_print_modalias_parts(buf, size, full_len, id);
++}
++
+ static ssize_t input_dev_show_modalias(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+@@ -1409,7 +1463,9 @@ static ssize_t input_dev_show_modalias(s
+       struct input_dev *id = to_input_dev(dev);
+       ssize_t len;
+-      len = input_print_modalias(buf, PAGE_SIZE, id, 1);
++      len = input_print_modalias(buf, PAGE_SIZE, id);
++      if (len < PAGE_SIZE - 2)
++              len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+       return min_t(int, len, PAGE_SIZE);
+ }
+@@ -1584,6 +1640,23 @@ static int input_add_uevent_bm_var(struc
+       return 0;
+ }
++/*
++ * This is a pretty gross hack. When building uevent data the driver core
++ * may try adding more environment variables to kobj_uevent_env without
++ * telling us, so we have no idea how much of the buffer we can use to
++ * avoid overflows/-ENOMEM elsewhere. To work around this let's artificially
++ * reduce amount of memory we will use for the modalias environment variable.
++ *
++ * The potential additions are:
++ *
++ * SEQNUM=18446744073709551615 - (%llu - 28 bytes)
++ * HOME=/ (6 bytes)
++ * PATH=/sbin:/bin:/usr/sbin:/usr/bin (34 bytes)
++ *
++ * 68 bytes total. Allow extra buffer - 96 bytes
++ */
++#define UEVENT_ENV_EXTRA_LEN  96
++
+ static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
+                                        struct input_dev *dev)
+ {
+@@ -1593,9 +1666,11 @@ static int input_add_uevent_modalias_var
+               return -ENOMEM;
+       len = input_print_modalias(&env->buf[env->buflen - 1],
+-                                 sizeof(env->buf) - env->buflen,
+-                                 dev, 0);
+-      if (len >= (sizeof(env->buf) - env->buflen))
++                                 (int)sizeof(env->buf) - env->buflen -
++                                      UEVENT_ENV_EXTRA_LEN,
++                                 dev);
++      if (len >= ((int)sizeof(env->buf) - env->buflen -
++                                      UEVENT_ENV_EXTRA_LEN))
+               return -ENOMEM;
+       env->buflen += len;
index 3a37b8a9b6531be17ece769cdd2d5a1686935997..1d6a25b7bd32ce8399b93a4c71823f6fda7e3c11 100644 (file)
@@ -54,3 +54,4 @@ xhci-set-correct-transferred-length-for-cancelled-bulk-transfers.patch
 xhci-apply-reset-resume-quirk-to-etron-ej188-xhci-host.patch
 xhci-apply-broken-streams-quirk-to-etron-ej188-xhci-host.patch
 scsi-mpt3sas-avoid-test-set_bit-operating-in-non-allocated-memory.patch
+input-try-trimming-too-long-modalias-strings.patch