ALSA: info: Check for integer overflow in snd_info_entry_write()
Siqi Lin [Mon, 16 Jan 2017 08:28:01 +0000 (13:28 +0530)]
snd_info_entry_write() resizes the buffer with an unsigned long
size argument that gets truncated because resize_info_buffer()
takes the size parameter as an unsigned int. On 64-bit kernels,
this causes the following copy_to_user() to write out-of-bounds
if (pos + count) can't be represented by an unsigned int.

Bug: 32510733

CVE-2017-0404 (A-32510733)
Bug 1849492

Change-Id: I9e8b55f93f2bd606b4a73b5a4525b71ee88c7c23
Signed-off-by: Siqi Lin <siqilin@google.com>
Signed-off-by: Gagan Grover <ggrover@nvidia.com>
Reviewed-on: http://git-master/r/1285802
(cherry picked from commit 080aad52eb18b8f622676063334f105a77f6cf58)
Reviewed-on: http://git-master/r/1299509
(cherry picked from commit 935b76652a88fd9906eefea1030c051613310f64)
Reviewed-on: http://git-master/r/1311417
GVS: Gerrit_Virtual_Submit
Reviewed-by: Vinayak Pane <vpane@nvidia.com>

sound/core/info.c

index 08070e1..332c9a1 100644 (file)
@@ -253,6 +253,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
        struct snd_info_buffer *buf;
        ssize_t size = 0;
        loff_t pos;
+       unsigned long realloc_size;
 
        data = file->private_data;
        if (snd_BUG_ON(!data))
@@ -261,7 +262,8 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
        pos = *offset;
        if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
                return -EIO;
-       if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
+       realloc_size = (unsigned long) pos + (unsigned long) count;
+       if (realloc_size < (unsigned long) pos || realloc_size > UINT_MAX)
                return -EIO;
        switch (entry->content) {
        case SNDRV_INFO_CONTENT_TEXT: