| From db10e556518eb9d21ee92ff944530d84349684f4 Mon Sep 17 00:00:00 2001 |
| From: Tyler Hicks <tyhicks@canonical.com> |
| Date: Thu, 12 Jan 2012 11:30:44 +0100 |
| Subject: eCryptfs: Sanitize write counts of /dev/ecryptfs |
| |
| From: Tyler Hicks <tyhicks@canonical.com> |
| |
| commit db10e556518eb9d21ee92ff944530d84349684f4 upstream. |
| |
| A malicious count value specified when writing to /dev/ecryptfs may |
| result in a a very large kernel memory allocation. |
| |
| This patch peeks at the specified packet payload size, adds that to the |
| size of the packet headers and compares the result with the write count |
| value. The resulting maximum memory allocation size is approximately 532 |
| bytes. |
| |
| Signed-off-by: Tyler Hicks <tyhicks@canonical.com> |
| Reported-by: Sasha Levin <levinsasha928@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/ecryptfs/miscdev.c | 56 +++++++++++++++++++++++++++++++++----------------- |
| 1 file changed, 38 insertions(+), 18 deletions(-) |
| |
| --- a/fs/ecryptfs/miscdev.c |
| +++ b/fs/ecryptfs/miscdev.c |
| @@ -408,11 +408,47 @@ ecryptfs_miscdev_write(struct file *file |
| ssize_t sz = 0; |
| char *data; |
| uid_t euid = current_euid(); |
| + unsigned char packet_size_peek[3]; |
| int rc; |
| |
| - if (count == 0) |
| + if (count == 0) { |
| goto out; |
| + } else if (count == (1 + 4)) { |
| + /* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */ |
| + goto memdup; |
| + } else if (count < (1 + 4 + 1) |
| + || count > (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4 |
| + + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES)) { |
| + printk(KERN_WARNING "%s: Acceptable packet size range is " |
| + "[%d-%lu], but amount of data written is [%zu].", |
| + __func__, (1 + 4 + 1), |
| + (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4 |
| + + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES), count); |
| + return -EINVAL; |
| + } |
| + |
| + if (copy_from_user(packet_size_peek, (buf + 1 + 4), |
| + sizeof(packet_size_peek))) { |
| + printk(KERN_WARNING "%s: Error while inspecting packet size\n", |
| + __func__); |
| + return -EFAULT; |
| + } |
| |
| + rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size, |
| + &packet_size_length); |
| + if (rc) { |
| + printk(KERN_WARNING "%s: Error parsing packet length; " |
| + "rc = [%d]\n", __func__, rc); |
| + return rc; |
| + } |
| + |
| + if ((1 + 4 + packet_size_length + packet_size) != count) { |
| + printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__, |
| + packet_size); |
| + return -EINVAL; |
| + } |
| + |
| +memdup: |
| data = memdup_user(buf, count); |
| if (IS_ERR(data)) { |
| printk(KERN_ERR "%s: memdup_user returned error [%ld]\n", |
| @@ -434,23 +470,7 @@ ecryptfs_miscdev_write(struct file *file |
| } |
| memcpy(&counter_nbo, &data[i], 4); |
| seq = be32_to_cpu(counter_nbo); |
| - i += 4; |
| - rc = ecryptfs_parse_packet_length(&data[i], &packet_size, |
| - &packet_size_length); |
| - if (rc) { |
| - printk(KERN_WARNING "%s: Error parsing packet length; " |
| - "rc = [%d]\n", __func__, rc); |
| - goto out_free; |
| - } |
| - i += packet_size_length; |
| - if ((1 + 4 + packet_size_length + packet_size) != count) { |
| - printk(KERN_WARNING "%s: (1 + packet_size_length([%zd])" |
| - " + packet_size([%zd]))([%zd]) != " |
| - "count([%zd]). Invalid packet format.\n", |
| - __func__, packet_size_length, packet_size, |
| - (1 + packet_size_length + packet_size), count); |
| - goto out_free; |
| - } |
| + i += 4 + packet_size_length; |
| rc = ecryptfs_miscdev_response(&data[i], packet_size, |
| euid, current_user_ns(), |
| task_pid(current), seq); |