Commit cee5aa1f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid

Pull HID fixes from Jiri Kosina:

 - fixes for a couple potential memory corruption problems (the HW would
   have to be manufactured to be deliberately evil to trigger those)
   found by Ben Hawkes
 - fix for potential infinite loop when using sysfs interface of
   logitech driver, from Simon Wood
 - a couple more simple driver fixes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  HID: fix a couple of off-by-ones
  HID: logitech: perform bounds checking on device_id early enough
  HID: logitech: fix bounds checking on LED report size
  HID: logitech: Prevent possibility of infinite loop when using /sys interface
  HID: rmi: print an error if F11 is not found instead of stopping the device
  HID: hid-sensor-hub: use devm_ functions consistently
  HID: huion: Use allocated buffer for DMA
  HID: huion: Fail on parameter retrieval errors
parents e9d99a1d 4ab25786
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { if (*rsize >= 18 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n"); hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n");
rdesc[11] = rdesc[16] = 0xff; rdesc[11] = rdesc[16] = 0xff;
rdesc[12] = rdesc[17] = 0x03; rdesc[12] = rdesc[17] = 0x03;
......
...@@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = { ...@@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = {
0xC0 /* End Collection */ 0xC0 /* End Collection */
}; };
/* Parameter indices */
enum huion_prm {
HUION_PRM_X_LM = 1,
HUION_PRM_Y_LM = 2,
HUION_PRM_PRESSURE_LM = 4,
HUION_PRM_RESOLUTION = 5,
HUION_PRM_NUM
};
/* Driver data */ /* Driver data */
struct huion_drvdata { struct huion_drvdata {
__u8 *rdesc; __u8 *rdesc;
...@@ -115,7 +124,12 @@ static int huion_tablet_enable(struct hid_device *hdev) ...@@ -115,7 +124,12 @@ static int huion_tablet_enable(struct hid_device *hdev)
int rc; int rc;
struct usb_device *usb_dev = hid_to_usb_dev(hdev); struct usb_device *usb_dev = hid_to_usb_dev(hdev);
struct huion_drvdata *drvdata = hid_get_drvdata(hdev); struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
__le16 buf[6]; __le16 *buf = NULL;
size_t len;
s32 params[HUION_PH_ID_NUM];
s32 resolution;
__u8 *p;
s32 v;
/* /*
* Read string descriptor containing tablet parameters. The specific * Read string descriptor containing tablet parameters. The specific
...@@ -123,65 +137,79 @@ static int huion_tablet_enable(struct hid_device *hdev) ...@@ -123,65 +137,79 @@ static int huion_tablet_enable(struct hid_device *hdev)
* driver traffic. * driver traffic.
* NOTE: This enables fully-functional tablet mode. * NOTE: This enables fully-functional tablet mode.
*/ */
len = HUION_PRM_NUM * sizeof(*buf);
buf = kmalloc(len, GFP_KERNEL);
if (buf == NULL) {
hid_err(hdev, "failed to allocate parameter buffer\n");
rc = -ENOMEM;
goto cleanup;
}
rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + 0x64, (USB_DT_STRING << 8) + 0x64,
0x0409, buf, sizeof(buf), 0x0409, buf, len,
USB_CTRL_GET_TIMEOUT); USB_CTRL_GET_TIMEOUT);
if (rc == -EPIPE) if (rc == -EPIPE) {
hid_warn(hdev, "device parameters not found\n"); hid_err(hdev, "device parameters not found\n");
else if (rc < 0) rc = -ENODEV;
hid_warn(hdev, "failed to get device parameters: %d\n", rc); goto cleanup;
else if (rc != sizeof(buf)) } else if (rc < 0) {
hid_warn(hdev, "invalid device parameters\n"); hid_err(hdev, "failed to get device parameters: %d\n", rc);
else { rc = -ENODEV;
s32 params[HUION_PH_ID_NUM]; goto cleanup;
s32 resolution; } else if (rc != len) {
__u8 *p; hid_err(hdev, "invalid device parameters\n");
s32 v; rc = -ENODEV;
goto cleanup;
}
/* Extract device parameters */ /* Extract device parameters */
params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]); params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]); params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]); params[HUION_PH_ID_PRESSURE_LM] =
resolution = le16_to_cpu(buf[5]); le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
if (resolution == 0) { resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
params[HUION_PH_ID_X_PM] = 0; if (resolution == 0) {
params[HUION_PH_ID_Y_PM] = 0; params[HUION_PH_ID_X_PM] = 0;
} else { params[HUION_PH_ID_Y_PM] = 0;
params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] * } else {
1000 / resolution; params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] * 1000 / resolution;
1000 / resolution; params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
} 1000 / resolution;
}
/* Allocate fixed report descriptor */ /* Allocate fixed report descriptor */
drvdata->rdesc = devm_kmalloc(&hdev->dev, drvdata->rdesc = devm_kmalloc(&hdev->dev,
sizeof(huion_tablet_rdesc_template), sizeof(huion_tablet_rdesc_template),
GFP_KERNEL); GFP_KERNEL);
if (drvdata->rdesc == NULL) { if (drvdata->rdesc == NULL) {
hid_err(hdev, "failed to allocate fixed rdesc\n"); hid_err(hdev, "failed to allocate fixed rdesc\n");
return -ENOMEM; rc = -ENOMEM;
} goto cleanup;
drvdata->rsize = sizeof(huion_tablet_rdesc_template); }
drvdata->rsize = sizeof(huion_tablet_rdesc_template);
/* Format fixed report descriptor */ /* Format fixed report descriptor */
memcpy(drvdata->rdesc, huion_tablet_rdesc_template, memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
drvdata->rsize); drvdata->rsize);
for (p = drvdata->rdesc; for (p = drvdata->rdesc;
p <= drvdata->rdesc + drvdata->rsize - 4;) { p <= drvdata->rdesc + drvdata->rsize - 4;) {
if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D && if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
p[3] < sizeof(params)) { p[3] < sizeof(params)) {
v = params[p[3]]; v = params[p[3]];
put_unaligned(cpu_to_le32(v), (s32 *)p); put_unaligned(cpu_to_le32(v), (s32 *)p);
p += 4; p += 4;
} else { } else {
p++; p++;
}
} }
} }
return 0; rc = 0;
cleanup:
kfree(buf);
return rc;
} }
static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id) static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
......
...@@ -300,7 +300,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -300,7 +300,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
* - change the button usage range to 4-7 for the extra * - change the button usage range to 4-7 for the extra
* buttons * buttons
*/ */
if (*rsize >= 74 && if (*rsize >= 75 &&
rdesc[61] == 0x05 && rdesc[62] == 0x08 && rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
rdesc[63] == 0x19 && rdesc[64] == 0x08 && rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
rdesc[65] == 0x29 && rdesc[66] == 0x0f && rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
......
...@@ -345,14 +345,14 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -345,14 +345,14 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
struct usb_device_descriptor *udesc; struct usb_device_descriptor *udesc;
__u16 bcdDevice, rev_maj, rev_min; __u16 bcdDevice, rev_maj, rev_min;
if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
rdesc[84] == 0x8c && rdesc[85] == 0x02) { rdesc[84] == 0x8c && rdesc[85] == 0x02) {
hid_info(hdev, hid_info(hdev,
"fixing up Logitech keyboard report descriptor\n"); "fixing up Logitech keyboard report descriptor\n");
rdesc[84] = rdesc[89] = 0x4d; rdesc[84] = rdesc[89] = 0x4d;
rdesc[85] = rdesc[90] = 0x10; rdesc[85] = rdesc[90] = 0x10;
} }
if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
rdesc[32] == 0x81 && rdesc[33] == 0x06 && rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
rdesc[49] == 0x81 && rdesc[50] == 0x06) { rdesc[49] == 0x81 && rdesc[50] == 0x06) {
hid_info(hdev, hid_info(hdev,
......
...@@ -451,13 +451,13 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at ...@@ -451,13 +451,13 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
drv_data = hid_get_drvdata(hid); drv_data = hid_get_drvdata(hid);
if (!drv_data) { if (!drv_data) {
hid_err(hid, "Private driver data not found!\n"); hid_err(hid, "Private driver data not found!\n");
return 0; return -EINVAL;
} }
entry = drv_data->device_props; entry = drv_data->device_props;
if (!entry) { if (!entry) {
hid_err(hid, "Device properties not found!\n"); hid_err(hid, "Device properties not found!\n");
return 0; return -EINVAL;
} }
if (range == 0) if (range == 0)
......
...@@ -238,13 +238,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, ...@@ -238,13 +238,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
return; return;
} }
if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
(dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n",
__func__, dj_report->device_index);
return;
}
if (djrcv_dev->paired_dj_devices[dj_report->device_index]) { if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
/* The device is already known. No need to reallocate it. */ /* The device is already known. No need to reallocate it. */
dbg_hid("%s: device is already known\n", __func__); dbg_hid("%s: device is already known\n", __func__);
...@@ -557,7 +550,7 @@ static int logi_dj_ll_raw_request(struct hid_device *hid, ...@@ -557,7 +550,7 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
if (!out_buf) if (!out_buf)
return -ENOMEM; return -ENOMEM;
if (count < DJREPORT_SHORT_LENGTH - 2) if (count > DJREPORT_SHORT_LENGTH - 2)
count = DJREPORT_SHORT_LENGTH - 2; count = DJREPORT_SHORT_LENGTH - 2;
out_buf[0] = REPORT_ID_DJ_SHORT; out_buf[0] = REPORT_ID_DJ_SHORT;
...@@ -690,6 +683,12 @@ static int logi_dj_raw_event(struct hid_device *hdev, ...@@ -690,6 +683,12 @@ static int logi_dj_raw_event(struct hid_device *hdev,
* device (via hid_input_report() ) and return 1 so hid-core does not do * device (via hid_input_report() ) and return 1 so hid-core does not do
* anything else with it. * anything else with it.
*/ */
if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
(dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
dev_err(&hdev->dev, "%s: invalid device index:%d\n",
__func__, dj_report->device_index);
return false;
}
spin_lock_irqsave(&djrcv_dev->lock, flags); spin_lock_irqsave(&djrcv_dev->lock, flags);
if (dj_report->report_id == REPORT_ID_DJ_SHORT) { if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { if (*rsize >= 31 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
hid_info(hdev, "fixing up button/consumer in HID report descriptor\n"); hid_info(hdev, "fixing up button/consumer in HID report descriptor\n");
rdesc[30] = 0x0c; rdesc[30] = 0x0c;
} }
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && if (*rsize >= 62 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
rdesc[41] == 0x00 && rdesc[59] == 0x26 && rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
rdesc[60] == 0xf9 && rdesc[61] == 0x00) { rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n"); hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
......
...@@ -909,10 +909,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -909,10 +909,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret; return ret;
} }
if (!test_bit(RMI_STARTED, &data->flags)) { if (!test_bit(RMI_STARTED, &data->flags))
hid_hw_stop(hdev); /*
return -EIO; * The device maybe in the bootloader if rmi_input_configured
} * failed to find F11 in the PDT. Print an error, but don't
* return an error from rmi_probe so that hidraw will be
* accessible from userspace. That way a userspace tool
* can be used to reload working firmware on the touchpad.
*/
hid_err(hdev, "Device failed to be properly configured\n");
return 0; return 0;
} }
......
...@@ -604,9 +604,9 @@ static int sensor_hub_probe(struct hid_device *hdev, ...@@ -604,9 +604,9 @@ static int sensor_hub_probe(struct hid_device *hdev,
ret = -EINVAL; ret = -EINVAL;
goto err_stop_hw; goto err_stop_hw;
} }
sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt * sd->hid_sensor_hub_client_devs = devm_kzalloc(&hdev->dev, dev_cnt *
sizeof(struct mfd_cell), sizeof(struct mfd_cell),
GFP_KERNEL); GFP_KERNEL);
if (sd->hid_sensor_hub_client_devs == NULL) { if (sd->hid_sensor_hub_client_devs == NULL) {
hid_err(hdev, "Failed to allocate memory for mfd cells\n"); hid_err(hdev, "Failed to allocate memory for mfd cells\n");
ret = -ENOMEM; ret = -ENOMEM;
...@@ -618,11 +618,12 @@ static int sensor_hub_probe(struct hid_device *hdev, ...@@ -618,11 +618,12 @@ static int sensor_hub_probe(struct hid_device *hdev,
if (collection->type == HID_COLLECTION_PHYSICAL) { if (collection->type == HID_COLLECTION_PHYSICAL) {
hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev),
GFP_KERNEL);
if (!hsdev) { if (!hsdev) {
hid_err(hdev, "cannot allocate hid_sensor_hub_device\n"); hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err_no_mem; goto err_stop_hw;
} }
hsdev->hdev = hdev; hsdev->hdev = hdev;
hsdev->vendor_id = hdev->vendor; hsdev->vendor_id = hdev->vendor;
...@@ -631,13 +632,13 @@ static int sensor_hub_probe(struct hid_device *hdev, ...@@ -631,13 +632,13 @@ static int sensor_hub_probe(struct hid_device *hdev,
if (last_hsdev) if (last_hsdev)
last_hsdev->end_collection_index = i; last_hsdev->end_collection_index = i;
last_hsdev = hsdev; last_hsdev = hsdev;
name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x", name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
collection->usage); "HID-SENSOR-%x",
collection->usage);
if (name == NULL) { if (name == NULL) {
hid_err(hdev, "Failed MFD device name\n"); hid_err(hdev, "Failed MFD device name\n");
ret = -ENOMEM; ret = -ENOMEM;
kfree(hsdev); goto err_stop_hw;
goto err_no_mem;
} }
sd->hid_sensor_hub_client_devs[ sd->hid_sensor_hub_client_devs[
sd->hid_sensor_client_cnt].id = sd->hid_sensor_client_cnt].id =
...@@ -661,16 +662,10 @@ static int sensor_hub_probe(struct hid_device *hdev, ...@@ -661,16 +662,10 @@ static int sensor_hub_probe(struct hid_device *hdev,
ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs, ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
sd->hid_sensor_client_cnt, NULL, 0, NULL); sd->hid_sensor_client_cnt, NULL, 0, NULL);
if (ret < 0) if (ret < 0)
goto err_no_mem; goto err_stop_hw;
return ret; return ret;
err_no_mem:
for (i = 0; i < sd->hid_sensor_client_cnt; ++i) {
kfree(sd->hid_sensor_hub_client_devs[i].name);
kfree(sd->hid_sensor_hub_client_devs[i].platform_data);
}
kfree(sd->hid_sensor_hub_client_devs);
err_stop_hw: err_stop_hw:
hid_hw_stop(hdev); hid_hw_stop(hdev);
...@@ -681,7 +676,6 @@ static void sensor_hub_remove(struct hid_device *hdev) ...@@ -681,7 +676,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
{ {
struct sensor_hub_data *data = hid_get_drvdata(hdev); struct sensor_hub_data *data = hid_get_drvdata(hdev);
unsigned long flags; unsigned long flags;
int i;
hid_dbg(hdev, " hardware removed\n"); hid_dbg(hdev, " hardware removed\n");
hid_hw_close(hdev); hid_hw_close(hdev);
...@@ -691,11 +685,6 @@ static void sensor_hub_remove(struct hid_device *hdev) ...@@ -691,11 +685,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
complete(&data->pending.ready); complete(&data->pending.ready);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
mfd_remove_devices(&hdev->dev); mfd_remove_devices(&hdev->dev);
for (i = 0; i < data->hid_sensor_client_cnt; ++i) {
kfree(data->hid_sensor_hub_client_devs[i].name);
kfree(data->hid_sensor_hub_client_devs[i].platform_data);
}
kfree(data->hid_sensor_hub_client_devs);
hid_set_drvdata(hdev, NULL); hid_set_drvdata(hdev, NULL);
mutex_destroy(&data->mutex); mutex_destroy(&data->mutex);
} }
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
rdesc[106] == 0x03) { rdesc[106] == 0x03) {
hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n"); hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
rdesc[105] = rdesc[110] = 0x03; rdesc[105] = rdesc[110] = 0x03;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment