diff options
author | Mohan Srinivasan <srmohan@google.com> | 2017-07-26 12:14:41 -0700 |
---|---|---|
committer | Amit Pundir <amit.pundir@linaro.org> | 2017-08-23 18:53:30 +0530 |
commit | 8ad43c44513170d98e4146517005e4890c776ac1 (patch) | |
tree | fd6518f9a2012b696c0aea9e9f58c60e8799864d | |
parent | 04233a18865f542cad26eff9a1790df94c491e59 (diff) | |
download | linaro-android-8ad43c44513170d98e4146517005e4890c776ac1.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
-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 9e568b0a0901..248eb3f7c5cb 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; |