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
This commit is contained in:
Linus Torvalds 2014-08-21 14:25:20 -07:00
commit cee5aa1f81
11 changed files with 115 additions and 94 deletions

View file

@ -28,7 +28,7 @@
static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
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");
rdesc[11] = rdesc[16] = 0xff;
rdesc[12] = rdesc[17] = 0x03;

View file

@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = {
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 */
struct huion_drvdata {
__u8 *rdesc;
@ -115,7 +124,12 @@ static int huion_tablet_enable(struct hid_device *hdev)
int rc;
struct usb_device *usb_dev = hid_to_usb_dev(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
@ -123,65 +137,79 @@ static int huion_tablet_enable(struct hid_device *hdev)
* driver traffic.
* 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),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + 0x64,
0x0409, buf, sizeof(buf),
0x0409, buf, len,
USB_CTRL_GET_TIMEOUT);
if (rc == -EPIPE)
hid_warn(hdev, "device parameters not found\n");
else if (rc < 0)
hid_warn(hdev, "failed to get device parameters: %d\n", rc);
else if (rc != sizeof(buf))
hid_warn(hdev, "invalid device parameters\n");
else {
s32 params[HUION_PH_ID_NUM];
s32 resolution;
__u8 *p;
s32 v;
if (rc == -EPIPE) {
hid_err(hdev, "device parameters not found\n");
rc = -ENODEV;
goto cleanup;
} else if (rc < 0) {
hid_err(hdev, "failed to get device parameters: %d\n", rc);
rc = -ENODEV;
goto cleanup;
} else if (rc != len) {
hid_err(hdev, "invalid device parameters\n");
rc = -ENODEV;
goto cleanup;
}
/* Extract device parameters */
params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]);
params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]);
params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]);
resolution = le16_to_cpu(buf[5]);
if (resolution == 0) {
params[HUION_PH_ID_X_PM] = 0;
params[HUION_PH_ID_Y_PM] = 0;
/* Extract device parameters */
params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
params[HUION_PH_ID_PRESSURE_LM] =
le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
if (resolution == 0) {
params[HUION_PH_ID_X_PM] = 0;
params[HUION_PH_ID_Y_PM] = 0;
} else {
params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
1000 / resolution;
params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
1000 / resolution;
}
/* Allocate fixed report descriptor */
drvdata->rdesc = devm_kmalloc(&hdev->dev,
sizeof(huion_tablet_rdesc_template),
GFP_KERNEL);
if (drvdata->rdesc == NULL) {
hid_err(hdev, "failed to allocate fixed rdesc\n");
rc = -ENOMEM;
goto cleanup;
}
drvdata->rsize = sizeof(huion_tablet_rdesc_template);
/* Format fixed report descriptor */
memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
drvdata->rsize);
for (p = drvdata->rdesc;
p <= drvdata->rdesc + drvdata->rsize - 4;) {
if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
p[3] < sizeof(params)) {
v = params[p[3]];
put_unaligned(cpu_to_le32(v), (s32 *)p);
p += 4;
} else {
params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
1000 / resolution;
params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
1000 / resolution;
}
/* Allocate fixed report descriptor */
drvdata->rdesc = devm_kmalloc(&hdev->dev,
sizeof(huion_tablet_rdesc_template),
GFP_KERNEL);
if (drvdata->rdesc == NULL) {
hid_err(hdev, "failed to allocate fixed rdesc\n");
return -ENOMEM;
}
drvdata->rsize = sizeof(huion_tablet_rdesc_template);
/* Format fixed report descriptor */
memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
drvdata->rsize);
for (p = drvdata->rdesc;
p <= drvdata->rdesc + drvdata->rsize - 4;) {
if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
p[3] < sizeof(params)) {
v = params[p[3]];
put_unaligned(cpu_to_le32(v), (s32 *)p);
p += 4;
} 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)

View file

@ -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
* buttons
*/
if (*rsize >= 74 &&
if (*rsize >= 75 &&
rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
rdesc[65] == 0x29 && rdesc[66] == 0x0f &&

View file

@ -345,14 +345,14 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
struct usb_device_descriptor *udesc;
__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) {
hid_info(hdev,
"fixing up Logitech keyboard report descriptor\n");
rdesc[84] = rdesc[89] = 0x4d;
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[49] == 0x81 && rdesc[50] == 0x06) {
hid_info(hdev,

View file

@ -451,13 +451,13 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
drv_data = hid_get_drvdata(hid);
if (!drv_data) {
hid_err(hid, "Private driver data not found!\n");
return 0;
return -EINVAL;
}
entry = drv_data->device_props;
if (!entry) {
hid_err(hid, "Device properties not found!\n");
return 0;
return -EINVAL;
}
if (range == 0)

View file

@ -238,13 +238,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
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]) {
/* The device is already known. No need to reallocate it. */
dbg_hid("%s: device is already known\n", __func__);
@ -557,7 +550,7 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
if (!out_buf)
return -ENOMEM;
if (count < DJREPORT_SHORT_LENGTH - 2)
if (count > DJREPORT_SHORT_LENGTH - 2)
count = DJREPORT_SHORT_LENGTH - 2;
out_buf[0] = REPORT_ID_DJ_SHORT;
@ -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
* 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);
if (dj_report->report_id == REPORT_ID_DJ_SHORT) {

View file

@ -24,7 +24,7 @@
static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
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");
rdesc[30] = 0x0c;
}

View file

@ -25,7 +25,7 @@
static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
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[60] == 0xf9 && rdesc[61] == 0x00) {
hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");

View file

@ -909,10 +909,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
if (!test_bit(RMI_STARTED, &data->flags)) {
hid_hw_stop(hdev);
return -EIO;
}
if (!test_bit(RMI_STARTED, &data->flags))
/*
* 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;
}

View file

@ -604,9 +604,9 @@ static int sensor_hub_probe(struct hid_device *hdev,
ret = -EINVAL;
goto err_stop_hw;
}
sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt *
sizeof(struct mfd_cell),
GFP_KERNEL);
sd->hid_sensor_hub_client_devs = devm_kzalloc(&hdev->dev, dev_cnt *
sizeof(struct mfd_cell),
GFP_KERNEL);
if (sd->hid_sensor_hub_client_devs == NULL) {
hid_err(hdev, "Failed to allocate memory for mfd cells\n");
ret = -ENOMEM;
@ -618,11 +618,12 @@ static int sensor_hub_probe(struct hid_device *hdev,
if (collection->type == HID_COLLECTION_PHYSICAL) {
hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev),
GFP_KERNEL);
if (!hsdev) {
hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
ret = -ENOMEM;
goto err_no_mem;
goto err_stop_hw;
}
hsdev->hdev = hdev;
hsdev->vendor_id = hdev->vendor;
@ -631,13 +632,13 @@ static int sensor_hub_probe(struct hid_device *hdev,
if (last_hsdev)
last_hsdev->end_collection_index = i;
last_hsdev = hsdev;
name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
collection->usage);
name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
"HID-SENSOR-%x",
collection->usage);
if (name == NULL) {
hid_err(hdev, "Failed MFD device name\n");
ret = -ENOMEM;
kfree(hsdev);
goto err_no_mem;
goto err_stop_hw;
}
sd->hid_sensor_hub_client_devs[
sd->hid_sensor_client_cnt].id =
@ -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,
sd->hid_sensor_client_cnt, NULL, 0, NULL);
if (ret < 0)
goto err_no_mem;
goto err_stop_hw;
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:
hid_hw_stop(hdev);
@ -681,7 +676,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
{
struct sensor_hub_data *data = hid_get_drvdata(hdev);
unsigned long flags;
int i;
hid_dbg(hdev, " hardware removed\n");
hid_hw_close(hdev);
@ -691,11 +685,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
complete(&data->pending.ready);
spin_unlock_irqrestore(&data->lock, flags);
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);
mutex_destroy(&data->mutex);
}

View file

@ -24,7 +24,7 @@
static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
rdesc[106] == 0x03) {
hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
rdesc[105] = rdesc[110] = 0x03;