Merge branch 'for-6.6/devm-fixes' into for-linus
authorBenjamin Tissoires <bentiss@kernel.org>
Thu, 31 Aug 2023 08:37:00 +0000 (10:37 +0200)
committerBenjamin Tissoires <bentiss@kernel.org>
Thu, 31 Aug 2023 08:37:00 +0000 (10:37 +0200)
Fix a wrong devm attachment to the input device which
now triggers a use after free with a recent devm change
by Rahul Rameshbabu.

.mailmap
MAINTAINERS
drivers/hid/hid-cp2112.c
drivers/hid/hid-input.c
include/linux/hid.h
include/linux/string_choices.h

index 1bce47a..cea6991 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -119,6 +119,9 @@ Daniel Borkmann <daniel@iogearbox.net> <dborkmann@redhat.com>
 Daniel Borkmann <daniel@iogearbox.net> <dborkman@redhat.com>
 Daniel Borkmann <daniel@iogearbox.net> <dxchgb@gmail.com>
 David Brownell <david-b@pacbell.net>
+David Rheinsberg <david@readahead.eu> <dh.herrmann@gmail.com>
+David Rheinsberg <david@readahead.eu> <dh.herrmann@googlemail.com>
+David Rheinsberg <david@readahead.eu> <david.rheinsberg@gmail.com>
 David Woodhouse <dwmw2@shinybook.infradead.org>
 Dengcheng Zhu <dzhu@wavecomp.com> <dczhu@mips.com>
 Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@gmail.com>
index 3be1bdf..23f3456 100644 (file)
@@ -21778,7 +21778,7 @@ F:      Documentation/admin-guide/ufs.rst
 F:     fs/ufs/
 
 UHID USERSPACE HID IO DRIVER
-M:     David Rheinsberg <david.rheinsberg@gmail.com>
+M:     David Rheinsberg <david@readahead.eu>
 L:     linux-input@vger.kernel.org
 S:     Maintained
 F:     drivers/hid/uhid.c
@@ -22902,7 +22902,7 @@ S:      Maintained
 F:     drivers/rtc/rtc-sd3078.c
 
 WIIMOTE HID DRIVER
-M:     David Rheinsberg <david.rheinsberg@gmail.com>
+M:     David Rheinsberg <david@readahead.eu>
 L:     linux-input@vger.kernel.org
 S:     Maintained
 F:     drivers/hid/hid-wiimote*
index 27cadad..54c33a2 100644 (file)
  *   https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf
  */
 
-#include <linux/gpio/consumer.h>
-#include <linux/gpio/machine.h>
+#include <linux/bitops.h>
 #include <linux/gpio/driver.h>
 #include <linux/hid.h>
 #include <linux/hidraw.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/nls.h>
+#include <linux/string_choices.h>
 #include <linux/usb/ch9.h>
 #include "hid-ids.h"
 
@@ -31,6 +31,8 @@
 #define CP2112_GPIO_CONFIG_LENGTH              5
 #define CP2112_GPIO_GET_LENGTH                 2
 #define CP2112_GPIO_SET_LENGTH                 3
+#define CP2112_GPIO_MAX_GPIO                   8
+#define CP2112_GPIO_ALL_GPIO_MASK              GENMASK(7, 0)
 
 enum {
        CP2112_GPIO_CONFIG              = 0x02,
@@ -163,19 +165,17 @@ struct cp2112_device {
        atomic_t read_avail;
        atomic_t xfer_avail;
        struct gpio_chip gc;
-       struct irq_chip irq;
        u8 *in_out_buffer;
        struct mutex lock;
 
-       struct gpio_desc *desc[8];
        bool gpio_poll;
        struct delayed_work gpio_poll_worker;
        unsigned long irq_mask;
        u8 gpio_prev_state;
 };
 
-static int gpio_push_pull = 0xFF;
-module_param(gpio_push_pull, int, S_IRUGO | S_IWUSR);
+static int gpio_push_pull = CP2112_GPIO_ALL_GPIO_MASK;
+module_param(gpio_push_pull, int, 0644);
 MODULE_PARM_DESC(gpio_push_pull, "GPIO push-pull configuration bitmask");
 
 static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -197,7 +197,7 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
                goto exit;
        }
 
-       buf[1] &= ~(1 << offset);
+       buf[1] &= ~BIT(offset);
        buf[2] = gpio_push_pull;
 
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
@@ -227,8 +227,8 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        mutex_lock(&dev->lock);
 
        buf[0] = CP2112_GPIO_SET;
-       buf[1] = value ? 0xff : 0;
-       buf[2] = 1 << offset;
+       buf[1] = value ? CP2112_GPIO_ALL_GPIO_MASK : 0;
+       buf[2] = BIT(offset);
 
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf,
                                 CP2112_GPIO_SET_LENGTH, HID_FEATURE_REPORT,
@@ -532,15 +532,13 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
        hid_dbg(hdev, "I2C %d messages\n", num);
 
        if (num == 1) {
+               hid_dbg(hdev, "I2C %s %#04x len %d\n",
+                       str_read_write(msgs->flags & I2C_M_RD), msgs->addr, msgs->len);
                if (msgs->flags & I2C_M_RD) {
-                       hid_dbg(hdev, "I2C read %#04x len %d\n",
-                               msgs->addr, msgs->len);
                        read_length = msgs->len;
                        read_buf = msgs->buf;
                        count = cp2112_read_req(buf, msgs->addr, msgs->len);
                } else {
-                       hid_dbg(hdev, "I2C write %#04x len %d\n",
-                               msgs->addr, msgs->len);
                        count = cp2112_i2c_write_req(buf, msgs->addr,
                                                     msgs->buf, msgs->len);
                }
@@ -648,7 +646,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
        int ret;
 
        hid_dbg(hdev, "%s addr 0x%x flags 0x%x cmd 0x%x size %d\n",
-               read_write == I2C_SMBUS_WRITE ? "write" : "read",
+               str_write_read(read_write == I2C_SMBUS_WRITE),
                addr, flags, command, size);
 
        switch (size) {
@@ -895,7 +893,7 @@ static ssize_t name##_show(struct device *kdev, \
        int ret = cp2112_get_usb_config(hdev, &cfg); \
        if (ret) \
                return ret; \
-       return scnprintf(buf, PAGE_SIZE, format, ##__VA_ARGS__); \
+       return sysfs_emit(buf, format, ##__VA_ARGS__); \
 } \
 static DEVICE_ATTR_RW(name);
 
@@ -946,18 +944,10 @@ CP2112_CONFIG_ATTR(release_version, ({
 
 #undef CP2112_CONFIG_ATTR
 
-struct cp2112_pstring_attribute {
-       struct device_attribute attr;
-       unsigned char report;
-};
-
-static ssize_t pstr_store(struct device *kdev,
-                         struct device_attribute *kattr, const char *buf,
-                         size_t count)
+static ssize_t pstr_store(struct device *kdev, struct device_attribute *kattr,
+                         const char *buf, size_t count, int number)
 {
        struct hid_device *hdev = to_hid_device(kdev);
-       struct cp2112_pstring_attribute *attr =
-               container_of(kattr, struct cp2112_pstring_attribute, attr);
        struct cp2112_string_report report;
        int ret;
 
@@ -965,7 +955,7 @@ static ssize_t pstr_store(struct device *kdev,
 
        ret = utf8s_to_utf16s(buf, count, UTF16_LITTLE_ENDIAN,
                              report.string, ARRAY_SIZE(report.string));
-       report.report = attr->report;
+       report.report = number;
        report.length = ret * sizeof(report.string[0]) + 2;
        report.type = USB_DT_STRING;
 
@@ -983,17 +973,15 @@ static ssize_t pstr_store(struct device *kdev,
        return count;
 }
 
-static ssize_t pstr_show(struct device *kdev,
-                        struct device_attribute *kattr, char *buf)
+static ssize_t pstr_show(struct device *kdev, struct device_attribute *kattr,
+                        char *buf, int number)
 {
        struct hid_device *hdev = to_hid_device(kdev);
-       struct cp2112_pstring_attribute *attr =
-               container_of(kattr, struct cp2112_pstring_attribute, attr);
        struct cp2112_string_report report;
        u8 length;
        int ret;
 
-       ret = cp2112_hid_get(hdev, attr->report, (u8 *)&report.contents,
+       ret = cp2112_hid_get(hdev, number, (u8 *)&report.contents,
                             sizeof(report.contents), HID_FEATURE_REPORT);
        if (ret < 3) {
                hid_err(hdev, "error reading %s string: %d\n", kattr->attr.name,
@@ -1018,10 +1006,16 @@ static ssize_t pstr_show(struct device *kdev,
 }
 
 #define CP2112_PSTR_ATTR(name, _report) \
-static struct cp2112_pstring_attribute dev_attr_##name = { \
-       .attr = __ATTR(name, (S_IWUSR | S_IRUGO), pstr_show, pstr_store), \
-       .report = _report, \
-};
+static ssize_t name##_store(struct device *kdev, struct device_attribute *kattr, \
+                           const char *buf, size_t count) \
+{ \
+       return pstr_store(kdev, kattr, buf, count, _report); \
+} \
+static ssize_t name##_show(struct device *kdev, struct device_attribute *kattr, char *buf) \
+{ \
+       return pstr_show(kdev, kattr, buf, _report); \
+} \
+static DEVICE_ATTR_RW(name);
 
 CP2112_PSTR_ATTR(manufacturer, CP2112_MANUFACTURER_STRING);
 CP2112_PSTR_ATTR(product,      CP2112_PRODUCT_STRING);
@@ -1036,9 +1030,9 @@ static const struct attribute_group cp2112_attr_group = {
                &dev_attr_max_power.attr,
                &dev_attr_power_mode.attr,
                &dev_attr_release_version.attr,
-               &dev_attr_manufacturer.attr.attr,
-               &dev_attr_product.attr.attr,
-               &dev_attr_serial.attr.attr,
+               &dev_attr_manufacturer.attr,
+               &dev_attr_product.attr,
+               &dev_attr_serial.attr,
                NULL
        }
 };
@@ -1063,7 +1057,7 @@ static void chmod_sysfs_attrs(struct hid_device *hdev)
        }
 
        for (attr = cp2112_attr_group.attrs; *attr; ++attr) {
-               umode_t mode = (buf[1] & 1) ? S_IWUSR | S_IRUGO : S_IRUGO;
+               umode_t mode = (buf[1] & 1) ? 0644 : 0444;
                ret = sysfs_chmod_file(&hdev->dev.kobj, *attr, mode);
                if (ret < 0)
                        hid_err(hdev, "error chmoding sysfs file %s\n",
@@ -1080,16 +1074,20 @@ static void cp2112_gpio_irq_mask(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct cp2112_device *dev = gpiochip_get_data(gc);
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
-       __clear_bit(d->hwirq, &dev->irq_mask);
+       __clear_bit(hwirq, &dev->irq_mask);
+       gpiochip_disable_irq(gc, hwirq);
 }
 
 static void cp2112_gpio_irq_unmask(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct cp2112_device *dev = gpiochip_get_data(gc);
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
-       __set_bit(d->hwirq, &dev->irq_mask);
+       gpiochip_enable_irq(gc, hwirq);
+       __set_bit(hwirq, &dev->irq_mask);
 }
 
 static void cp2112_gpio_poll_callback(struct work_struct *work)
@@ -1098,7 +1096,6 @@ static void cp2112_gpio_poll_callback(struct work_struct *work)
                                                 gpio_poll_worker.work);
        struct irq_data *d;
        u8 gpio_mask;
-       u8 virqs = (u8)dev->irq_mask;
        u32 irq_type;
        int irq, virq, ret;
 
@@ -1109,15 +1106,10 @@ static void cp2112_gpio_poll_callback(struct work_struct *work)
                goto exit;
 
        gpio_mask = ret;
-
-       while (virqs) {
-               virq = ffs(virqs) - 1;
-               virqs &= ~BIT(virq);
-
-               if (!dev->gc.to_irq)
-                       break;
-
-               irq = dev->gc.to_irq(&dev->gc, virq);
+       for_each_set_bit(virq, &dev->irq_mask, CP2112_GPIO_MAX_GPIO) {
+               irq = irq_find_mapping(dev->gc.irq.domain, virq);
+               if (!irq)
+                       continue;
 
                d = irq_get_irq_data(irq);
                if (!d)
@@ -1175,6 +1167,7 @@ static void cp2112_gpio_irq_shutdown(struct irq_data *d)
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct cp2112_device *dev = gpiochip_get_data(gc);
 
+       cp2112_gpio_irq_mask(d);
        cancel_delayed_work_sync(&dev->gpio_poll_worker);
 }
 
@@ -1183,50 +1176,17 @@ static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type)
        return 0;
 }
 
-static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
-                                             int pin)
-{
-       int ret;
-
-       if (dev->desc[pin])
-               return -EINVAL;
-
-       dev->desc[pin] = gpiochip_request_own_desc(&dev->gc, pin,
-                                                  "HID/I2C:Event",
-                                                  GPIO_ACTIVE_HIGH,
-                                                  GPIOD_IN);
-       if (IS_ERR(dev->desc[pin])) {
-               dev_err(dev->gc.parent, "Failed to request GPIO\n");
-               return PTR_ERR(dev->desc[pin]);
-       }
-
-       ret = cp2112_gpio_direction_input(&dev->gc, pin);
-       if (ret < 0) {
-               dev_err(dev->gc.parent, "Failed to set GPIO to input dir\n");
-               goto err_desc;
-       }
-
-       ret = gpiochip_lock_as_irq(&dev->gc, pin);
-       if (ret) {
-               dev_err(dev->gc.parent, "Failed to lock GPIO as interrupt\n");
-               goto err_desc;
-       }
-
-       ret = gpiod_to_irq(dev->desc[pin]);
-       if (ret < 0) {
-               dev_err(dev->gc.parent, "Failed to translate GPIO to IRQ\n");
-               goto err_lock;
-       }
-
-       return ret;
-
-err_lock:
-       gpiochip_unlock_as_irq(&dev->gc, pin);
-err_desc:
-       gpiochip_free_own_desc(dev->desc[pin]);
-       dev->desc[pin] = NULL;
-       return ret;
-}
+static const struct irq_chip cp2112_gpio_irqchip = {
+       .name = "cp2112-gpio",
+       .irq_startup = cp2112_gpio_irq_startup,
+       .irq_shutdown = cp2112_gpio_irq_shutdown,
+       .irq_ack = cp2112_gpio_irq_ack,
+       .irq_mask = cp2112_gpio_irq_mask,
+       .irq_unmask = cp2112_gpio_irq_unmask,
+       .irq_set_type = cp2112_gpio_irq_type,
+       .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
 
 static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
@@ -1333,21 +1293,12 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
        dev->gc.set                     = cp2112_gpio_set;
        dev->gc.get                     = cp2112_gpio_get;
        dev->gc.base                    = -1;
-       dev->gc.ngpio                   = 8;
+       dev->gc.ngpio                   = CP2112_GPIO_MAX_GPIO;
        dev->gc.can_sleep               = 1;
        dev->gc.parent                  = &hdev->dev;
 
-       dev->irq.name = "cp2112-gpio";
-       dev->irq.irq_startup = cp2112_gpio_irq_startup;
-       dev->irq.irq_shutdown = cp2112_gpio_irq_shutdown;
-       dev->irq.irq_ack = cp2112_gpio_irq_ack;
-       dev->irq.irq_mask = cp2112_gpio_irq_mask;
-       dev->irq.irq_unmask = cp2112_gpio_irq_unmask;
-       dev->irq.irq_set_type = cp2112_gpio_irq_type;
-       dev->irq.flags = IRQCHIP_MASK_ON_SUSPEND;
-
        girq = &dev->gc.irq;
-       girq->chip = &dev->irq;
+       gpio_irq_chip_set_chip(girq, &cp2112_gpio_irqchip);
        /* The event comes from the outside so no parent handler */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
@@ -1389,7 +1340,6 @@ err_hid_stop:
 static void cp2112_remove(struct hid_device *hdev)
 {
        struct cp2112_device *dev = hid_get_drvdata(hdev);
-       int i;
 
        sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
        i2c_del_adapter(&dev->adap);
@@ -1399,11 +1349,6 @@ static void cp2112_remove(struct hid_device *hdev)
                cancel_delayed_work_sync(&dev->gpio_poll_worker);
        }
 
-       for (i = 0; i < ARRAY_SIZE(dev->desc); i++) {
-               gpiochip_unlock_as_irq(&dev->gc, i);
-               gpiochip_free_own_desc(dev->desc[i]);
-       }
-
        gpiochip_remove(&dev->gc);
        /* i2c_del_adapter has finished removing all i2c devices from our
         * adapter. Well behaved devices should no longer call our cp2112_xfer
index 851ee86..40a5645 100644 (file)
@@ -988,6 +988,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        return;
 
                case 0x3c: /* Invert */
+                       device->quirks &= ~HID_QUIRK_NOINVERT;
                        map_key_clear(BTN_TOOL_RUBBER);
                        break;
 
@@ -1013,9 +1014,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x45: /* ERASER */
                        /*
                         * This event is reported when eraser tip touches the surface.
-                        * Actual eraser (BTN_TOOL_RUBBER) is set by Invert usage when
-                        * tool gets in proximity.
+                        * Actual eraser (BTN_TOOL_RUBBER) is set and released either
+                        * by Invert if tool reports proximity or by Eraser directly.
                         */
+                       if (!test_bit(BTN_TOOL_RUBBER, input->keybit)) {
+                               device->quirks |= HID_QUIRK_NOINVERT;
+                               set_bit(BTN_TOOL_RUBBER, input->keybit);
+                       }
                        map_key_clear(BTN_TOUCH);
                        break;
 
@@ -1580,6 +1585,15 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                else if (report->tool != BTN_TOOL_RUBBER)
                        /* value is off, tool is not rubber, ignore */
                        return;
+               else if (*quirks & HID_QUIRK_NOINVERT &&
+                        !test_bit(BTN_TOUCH, input->key)) {
+                       /*
+                        * There is no invert to release the tool, let hid_input
+                        * send BTN_TOUCH with scancode and release the tool after.
+                        */
+                       hid_report_release_tool(report, input, BTN_TOOL_RUBBER);
+                       return;
+               }
 
                /* let hid-input set BTN_TOUCH */
                break;
index 39e21e3..be9e16c 100644 (file)
@@ -360,6 +360,7 @@ struct hid_item {
 #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18)
 #define HID_QUIRK_HAVE_SPECIAL_DRIVER          BIT(19)
 #define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20)
+#define HID_QUIRK_NOINVERT                     BIT(21)
 #define HID_QUIRK_FULLSPEED_INTERVAL           BIT(28)
 #define HID_QUIRK_NO_INIT_REPORTS              BIT(29)
 #define HID_QUIRK_NO_IGNORE                    BIT(30)
@@ -555,9 +556,9 @@ struct hid_input {
        struct hid_report *report;
        struct input_dev *input;
        const char *name;
-       bool registered;
        struct list_head reports;       /* the list of reports */
        unsigned int application;       /* application usage for this input */
+       bool registered;
 };
 
 enum hid_type {
index 4812022..3c10919 100644 (file)
@@ -30,6 +30,7 @@ static inline const char *str_read_write(bool v)
 {
        return v ? "read" : "write";
 }
+#define str_write_read(v)              str_read_write(!(v))
 
 static inline const char *str_on_off(bool v)
 {