From 92fc7f9aa0298cc112b2893e4e0bcf522f2659a8 Mon Sep 17 00:00:00 2001 From: Mohan Srinivasan Date: Wed, 26 Jul 2017 12:14:41 -0700 Subject: [PATCH] ANDROID: input: 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 Bug: 63962952 Change-Id: Iafef48b5d7283750ac0f39f5aaa767b1c3bf2004 [AmitP: Folded following android-4.9 commit changes into this patch a1e4c795e1b6 ("Use %zu to print resid (size_t).")] Signed-off-by: Amit Pundir --- drivers/input/misc/keychord.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c index 9e568b0a0901..a3ae4586850c 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 %zu\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 %zu\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; -- 2.20.1