mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
207 lines
5.8 KiB
Diff
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
|
|
|