DivestOS/Patches/Linux_CVEs/CVE-2016-10288/ANY/0001.patch
2017-11-07 17:32:46 -05:00

207 lines
5.8 KiB
Diff

From db2cdc95204bc404f03613d5dd7002251fb33660 Mon Sep 17 00:00:00 2001
From: Ankit Sharma <ansharma@codeaurora.org>
Date: Thu, 9 Feb 2017 16:23:09 +0530
Subject: leds: qpnp-flash: Fix Use-after-free(UAF) for debugfs
Fix UAF where two threads can open and close the same file. Second
open will cause the private data for the first file to be overwritten.
When the first file is closed and the private data is freed, this makes
the now-shared private data OOB for the second thread.
CRs-Fixed: 1109763
Change-Id: I1c4618d5be99e140abf0f3ea0d7f485897db5ab2
Signed-off-by: Ankit Sharma <ansharma@codeaurora.org>
---
drivers/leds/leds-qpnp-flash.c | 82 +++++++++++++++++++++++++++---------------
1 file changed, 54 insertions(+), 28 deletions(-)
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
index 56ba8f5..ec4b4e7 100644
--- a/drivers/leds/leds-qpnp-flash.c
+++ b/drivers/leds/leds-qpnp-flash.c
@@ -225,11 +225,13 @@ struct flash_led_platform_data {
};
struct qpnp_flash_led_buffer {
- struct mutex debugfs_lock; /* Prevent thread concurrency */
- size_t rpos;
- size_t wpos;
- size_t len;
- char data[0];
+ struct mutex debugfs_lock; /* Prevent thread concurrency */
+ size_t rpos;
+ size_t wpos;
+ size_t len;
+ struct qpnp_flash_led *led;
+ u32 buffer_cnt;
+ char data[0];
};
/*
@@ -247,10 +249,8 @@ struct qpnp_flash_led {
struct workqueue_struct *ordered_workq;
struct qpnp_vadc_chip *vadc_dev;
struct mutex flash_led_lock;
- struct qpnp_flash_led_buffer *log;
struct dentry *dbgfs_root;
int num_leds;
- u32 buffer_cnt;
u16 base;
u16 current_addr;
u16 current2_addr;
@@ -282,10 +282,10 @@ static int flash_led_dbgfs_file_open(struct qpnp_flash_led *led,
log->wpos = 0;
log->len = logbufsize - sizeof(*log);
mutex_init(&log->debugfs_lock);
- led->log = log;
+ log->led = led;
- led->buffer_cnt = 1;
- file->private_data = led;
+ log->buffer_cnt = 1;
+ file->private_data = log;
return 0;
}
@@ -299,12 +299,12 @@ static int flash_led_dfs_open(struct inode *inode, struct file *file)
static int flash_led_dfs_close(struct inode *inode, struct file *file)
{
- struct qpnp_flash_led *led = file->private_data;
+ struct qpnp_flash_led_buffer *log = file->private_data;
- if (led && led->log) {
+ if (log) {
file->private_data = NULL;
- mutex_destroy(&led->log->debugfs_lock);
- kfree(led->log);
+ mutex_destroy(&log->debugfs_lock);
+ kfree(log);
}
return 0;
@@ -333,15 +333,21 @@ static int print_to_log(struct qpnp_flash_led_buffer *log,
static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
size_t count, loff_t *ppos) {
- struct qpnp_flash_led *led = fp->private_data;
- struct qpnp_flash_led_buffer *log = led->log;
+ struct qpnp_flash_led_buffer *log = fp->private_data;
+ struct qpnp_flash_led *led;
u8 val;
int rc = 0;
size_t len;
size_t ret;
+ if (!log) {
+ pr_err("error: file private data is NULL\n");
+ return -EFAULT;
+ }
+ led = log->led;
+
mutex_lock(&log->debugfs_lock);
- if ((log->rpos >= log->wpos && led->buffer_cnt == 0) ||
+ if ((log->rpos >= log->wpos && log->buffer_cnt == 0) ||
((log->len - log->wpos) < MIN_BUFFER_WRITE_LEN))
goto unlock_mutex;
@@ -353,7 +359,7 @@ static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
INT_LATCHED_STS(led->base), rc);
goto unlock_mutex;
}
- led->buffer_cnt--;
+ log->buffer_cnt--;
rc = print_to_log(log, "0x%05X ", INT_LATCHED_STS(led->base));
if (rc == 0)
@@ -388,18 +394,24 @@ unlock_mutex:
static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
size_t count, loff_t *ppos) {
- struct qpnp_flash_led *led = fp->private_data;
- struct qpnp_flash_led_buffer *log = led->log;
+ struct qpnp_flash_led_buffer *log = fp->private_data;
+ struct qpnp_flash_led *led;
int rc = 0;
size_t len;
size_t ret;
+ if (!log) {
+ pr_err("error: file private data is NULL\n");
+ return -EFAULT;
+ }
+ led = log->led;
+
mutex_lock(&log->debugfs_lock);
- if ((log->rpos >= log->wpos && led->buffer_cnt == 0) ||
+ if ((log->rpos >= log->wpos && log->buffer_cnt == 0) ||
((log->len - log->wpos) < MIN_BUFFER_WRITE_LEN))
goto unlock_mutex;
- led->buffer_cnt--;
+ log->buffer_cnt--;
rc = print_to_log(log, "0x%05X ", FLASH_LED_FAULT_STATUS(led->base));
if (rc == 0)
@@ -441,10 +453,17 @@ static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
int data;
size_t ret = 0;
- struct qpnp_flash_led *led = file->private_data;
+ struct qpnp_flash_led_buffer *log = file->private_data;
+ struct qpnp_flash_led *led;
char *kbuf;
- mutex_lock(&led->log->debugfs_lock);
+ if (!log) {
+ pr_err("error: file private data is NULL\n");
+ return -EFAULT;
+ }
+ led = log->led;
+
+ mutex_lock(&log->debugfs_lock);
kbuf = kmalloc(count + 1, GFP_KERNEL);
if (!kbuf) {
ret = -ENOMEM;
@@ -479,7 +498,7 @@ static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
free_buf:
kfree(kbuf);
unlock_mutex:
- mutex_unlock(&led->log->debugfs_lock);
+ mutex_unlock(&log->debugfs_lock);
return ret;
}
@@ -491,10 +510,17 @@ static ssize_t flash_led_dfs_dbg_enable(struct file *file,
int cnt = 0;
int data;
size_t ret = 0;
- struct qpnp_flash_led *led = file->private_data;
+ struct qpnp_flash_led_buffer *log = file->private_data;
+ struct qpnp_flash_led *led;
char *kbuf;
- mutex_lock(&led->log->debugfs_lock);
+ if (!log) {
+ pr_err("error: file private data is NULL\n");
+ return -EFAULT;
+ }
+ led = log->led;
+
+ mutex_lock(&log->debugfs_lock);
kbuf = kmalloc(count + 1, GFP_KERNEL);
if (!kbuf) {
ret = -ENOMEM;
@@ -528,7 +554,7 @@ static ssize_t flash_led_dfs_dbg_enable(struct file *file,
free_buf:
kfree(kbuf);
unlock_mutex:
- mutex_unlock(&led->log->debugfs_lock);
+ mutex_unlock(&log->debugfs_lock);
return ret;
}
--
cgit v1.1