aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohan Srinivasan <srmohan@google.com>2017-07-26 12:14:41 -0700
committerMohan Srinivasan <srmohan@google.com>2017-08-11 19:27:30 +0000
commiteac37ad2df7ecf81b8dba0b64e9ed52351f73d63 (patch)
treeda83cd5eba3aecd42cd29bf8aaca1fa85085ef85
parent6f227409a1797b448402a3ebf7523a229b8b6cbd (diff)
downloadv4.4-eac37ad2df7ecf81b8dba0b64e9ed52351f73d63.tar.gz
ANDROID: keychord: Fix a slab out-of-bounds read.
Fix a slab out of bounds read in keychord_write(), detected by KASAN. Signed-off-by: Mohan Srinivasan <srmohan@google.com> Bug: 63962952 Change-Id: Iafef48b5d7283750ac0f39f5aaa767b1c3bf2004 (cherry picked from commit 913d980e07d84a843f5323acc55d185212a2abec)
-rw-r--r--drivers/input/misc/keychord.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c
index a5ea27ad0e16..f148b937b4e5 100644
--- a/drivers/input/misc/keychord.c
+++ b/drivers/input/misc/keychord.c
@@ -232,9 +232,11 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer,
{
struct keychord_device *kdev = file->private_data;
struct input_keychord *keychords = 0;
- struct input_keychord *keychord, *next, *end;
+ struct input_keychord *keychord;
int ret, i, key;
unsigned long flags;
+ size_t resid = count;
+ size_t key_bytes;
if (count < sizeof(struct input_keychord))
return -EINVAL;
@@ -265,15 +267,29 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer,
kdev->head = kdev->tail = 0;
keychord = keychords;
- end = (struct input_keychord *)((char *)keychord + count);
- while (keychord < end) {
- next = NEXT_KEYCHORD(keychord);
- if (keychord->count <= 0 || next > end) {
+ while (resid > 0) {
+ /* Is the entire keychord entry header present ? */
+ if (resid < sizeof(struct input_keychord)) {
+ pr_err("keychord: Insufficient bytes present for header %lu\n",
+ resid);
+ goto err_unlock_return;
+ }
+ resid -= sizeof(struct input_keychord);
+ if (keychord->count <= 0) {
pr_err("keychord: invalid keycode count %d\n",
keychord->count);
goto err_unlock_return;
}
+ key_bytes = keychord->count * sizeof(keychord->keycodes[0]);
+ /* Do we have all the expected keycodes ? */
+ if (resid < key_bytes) {
+ pr_err("keychord: Insufficient bytes present for keycount %lu\n",
+ resid);
+ goto err_unlock_return;
+ }
+ resid -= key_bytes;
+
if (keychord->version != KEYCHORD_VERSION) {
pr_err("keychord: unsupported version %d\n",
keychord->version);
@@ -292,7 +308,7 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer,
}
kdev->keychord_count++;
- keychord = next;
+ keychord = NEXT_KEYCHORD(keychord);
}
kdev->keychords = keychords;