Skip to content

Commit d9cd8c2

Browse files
MichaelZaidmangregkh
authored andcommitted
HID: ft260: skip unexpected HID input reports
[ Upstream commit b7121e3 ] The FT260 is not supposed to generate unexpected HID reports. However, in theory, the unsolicited HID Input reports can be issued by a specially crafted malicious USB device masquerading as FT260 when the attacker has physical access to the USB port. In this case, the read_buf pointer points to the final data portion of the previous I2C Read transfer, and the memcpy invoked in the ft260_raw_event() will try copying the content of the unexpected report into the wrong location. This commit sets the Read buffer pointer to NULL on the I2C Read transaction completion and checks it in the ft260_raw_event() to detect and skip the unsolicited Input report. Reported-by: Enrik Berkhan <Enrik.Berkhan@inka.de> Signed-off-by: Michael Zaidman <michael.zaidman@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Stable-dep-of: bf3e39d ("HID: ft260: fix stack-use-after-return write in I2C read race") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 85fc8d7 commit d9cd8c2

1 file changed

Lines changed: 27 additions & 14 deletions

File tree

drivers/hid/hid-ft260.c

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -471,17 +471,13 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
471471
struct ft260_i2c_read_request_report rep;
472472
struct hid_device *hdev = dev->hdev;
473473
int timeout;
474-
int ret;
474+
int ret = 0;
475475

476476
if (len > FT260_RD_DATA_MAX) {
477477
hid_err(hdev, "%s: unsupported rd len: %d\n", __func__, len);
478478
return -EINVAL;
479479
}
480480

481-
dev->read_idx = 0;
482-
dev->read_buf = data;
483-
dev->read_len = len;
484-
485481
rep.report = FT260_I2C_READ_REQ;
486482
rep.length = cpu_to_le16(len);
487483
rep.address = addr;
@@ -492,25 +488,36 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
492488

493489
reinit_completion(&dev->wait);
494490

491+
dev->read_idx = 0;
492+
dev->read_buf = data;
493+
dev->read_len = len;
494+
495495
ret = ft260_hid_output_report(hdev, (u8 *)&rep, sizeof(rep));
496496
if (ret < 0) {
497497
hid_err(hdev, "%s: failed to start transaction, ret %d\n",
498498
__func__, ret);
499-
return ret;
499+
goto ft260_i2c_read_exit;
500500
}
501501

502502
timeout = msecs_to_jiffies(5000);
503503
if (!wait_for_completion_timeout(&dev->wait, timeout)) {
504+
ret = -ETIMEDOUT;
504505
ft260_i2c_reset(hdev);
505-
return -ETIMEDOUT;
506+
goto ft260_i2c_read_exit;
506507
}
507508

509+
dev->read_buf = NULL;
510+
508511
ret = ft260_xfer_status(dev);
509-
if (ret == 0)
510-
return 0;
512+
if (ret < 0) {
513+
ret = -EIO;
514+
ft260_i2c_reset(hdev);
515+
goto ft260_i2c_read_exit;
516+
}
511517

512-
ft260_i2c_reset(hdev);
513-
return -EIO;
518+
ft260_i2c_read_exit:
519+
dev->read_buf = NULL;
520+
return ret;
514521
}
515522

516523
/*
@@ -1033,6 +1040,13 @@ static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report,
10331040
ft260_dbg("i2c resp: rep %#02x len %d\n", xfer->report,
10341041
xfer->length);
10351042

1043+
if ((dev->read_buf == NULL) ||
1044+
(xfer->length > dev->read_len - dev->read_idx)) {
1045+
hid_err(hdev, "unexpected report %#02x, length %d\n",
1046+
xfer->report, xfer->length);
1047+
return -1;
1048+
}
1049+
10361050
memcpy(&dev->read_buf[dev->read_idx], &xfer->data,
10371051
xfer->length);
10381052
dev->read_idx += xfer->length;
@@ -1041,10 +1055,9 @@ static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report,
10411055
complete(&dev->wait);
10421056

10431057
} else {
1044-
hid_err(hdev, "unknown report: %#02x\n", xfer->report);
1045-
return 0;
1058+
hid_err(hdev, "unhandled report %#02x\n", xfer->report);
10461059
}
1047-
return 1;
1060+
return 0;
10481061
}
10491062

10501063
static struct hid_driver ft260_driver = {

0 commit comments

Comments
 (0)