diff options
author | Mohan Srinivasan <srmohan@google.com> | 2017-07-26 12:14:41 -0700 |
---|---|---|
committer | Mohan Srinivasan <srmohan@google.com> | 2017-08-11 19:27:30 +0000 |
commit | eac37ad2df7ecf81b8dba0b64e9ed52351f73d63 (patch) | |
tree | da83cd5eba3aecd42cd29bf8aaca1fa85085ef85 | |
parent | 6f227409a1797b448402a3ebf7523a229b8b6cbd (diff) | |
download | v4.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.c | 28 |
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; |