OSDN Git Service

ANDROID: keychord: Fix a slab out-of-bounds read.
authorMohan Srinivasan <srmohan@google.com>
Wed, 26 Jul 2017 19:14:41 +0000 (12:14 -0700)
committerMohan Srinivasan <srmohan@google.com>
Fri, 11 Aug 2017 19:27:30 +0000 (19:27 +0000)
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)

drivers/input/misc/keychord.c

index a5ea27a..f148b93 100644 (file)
@@ -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;