mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-12-23 22:49:28 -05:00
205 lines
5.9 KiB
Diff
205 lines
5.9 KiB
Diff
|
From ff96565f1dbabfeb7fb2c1604f40af768579d9df Mon Sep 17 00:00:00 2001
|
||
|
From: Ashish Kumar Dhanotiya <adhanoti@codeaurora.org>
|
||
|
Date: Fri, 14 Apr 2017 16:55:34 +0530
|
||
|
Subject: qcacld-3.0: Race condition while using pkt log buffer
|
||
|
|
||
|
There can be a race condition if two different threads use the
|
||
|
pkt log buffer at the same time. This issue can lead to Use-After-Free
|
||
|
of the packet log buffer.
|
||
|
|
||
|
To address this issue, protect the pktlog buffer access using spinlock.
|
||
|
|
||
|
Change-Id: I8098bb78a8e2462e109cee3407683c669f151fd5
|
||
|
CRs-Fixed: 2021363
|
||
|
---
|
||
|
core/utils/pktlog/linux_ac.c | 31 +++++++++++++++++++++++++------
|
||
|
core/utils/pktlog/pktlog_ac.c | 5 +++++
|
||
|
2 files changed, 30 insertions(+), 6 deletions(-)
|
||
|
|
||
|
diff --git a/core/utils/pktlog/linux_ac.c b/core/utils/pktlog/linux_ac.c
|
||
|
index 974cd2a..eb0943f 100644
|
||
|
--- a/core/utils/pktlog/linux_ac.c
|
||
|
+++ b/core/utils/pktlog/linux_ac.c
|
||
|
@@ -520,12 +520,15 @@ static void pktlog_detach(struct hif_opaque_softc *scn)
|
||
|
pl_info = pl_dev->pl_info;
|
||
|
remove_proc_entry(WLANDEV_BASENAME, g_pktlog_pde);
|
||
|
pktlog_sysctl_unregister(pl_dev);
|
||
|
- pktlog_cleanup(pl_info);
|
||
|
+
|
||
|
+ spin_lock_bh(&pl_info->log_lock);
|
||
|
|
||
|
if (pl_info->buf) {
|
||
|
pktlog_release_buf(scn);
|
||
|
pl_dev->tgt_pktlog_alloced = false;
|
||
|
}
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
+ pktlog_cleanup(pl_info);
|
||
|
|
||
|
if (pl_dev) {
|
||
|
kfree(pl_info);
|
||
|
@@ -701,11 +704,16 @@ pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos,
|
||
|
int rem_len;
|
||
|
int start_offset, end_offset;
|
||
|
int fold_offset, ppos_data, cur_rd_offset, cur_wr_offset;
|
||
|
- struct ath_pktlog_buf *log_buf = pl_info->buf;
|
||
|
+ struct ath_pktlog_buf *log_buf;
|
||
|
+
|
||
|
+ spin_lock_bh(&pl_info->log_lock);
|
||
|
+ log_buf = pl_info->buf;
|
||
|
+
|
||
|
*read_complete = false;
|
||
|
|
||
|
if (log_buf == NULL) {
|
||
|
*read_complete = true;
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -808,7 +816,6 @@ rd_done:
|
||
|
*ppos += ret_val;
|
||
|
|
||
|
if (ret_val == 0) {
|
||
|
- PKTLOG_LOCK(pl_info);
|
||
|
/* Write pointer might have been updated during the read.
|
||
|
* So, if some data is written into, lets not reset the pointers
|
||
|
* We can continue to read from the offset position
|
||
|
@@ -822,9 +829,8 @@ rd_done:
|
||
|
pl_info->buf->offset = PKTLOG_READ_OFFSET;
|
||
|
*read_complete = true;
|
||
|
}
|
||
|
- PKTLOG_UNLOCK(pl_info);
|
||
|
}
|
||
|
-
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
return ret_val;
|
||
|
}
|
||
|
|
||
|
@@ -849,16 +855,20 @@ __pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
|
||
|
if (!pl_info)
|
||
|
return 0;
|
||
|
|
||
|
+ spin_lock_bh(&pl_info->log_lock);
|
||
|
log_buf = pl_info->buf;
|
||
|
|
||
|
- if (log_buf == NULL)
|
||
|
+ if (log_buf == NULL) {
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
return 0;
|
||
|
+ }
|
||
|
|
||
|
if (pl_info->log_state) {
|
||
|
/* Read is not allowed when write is going on
|
||
|
* When issuing cat command, ensure to send
|
||
|
* pktlog disable command first.
|
||
|
*/
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
@@ -875,11 +885,13 @@ __pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
|
||
|
|
||
|
if (*ppos < bufhdr_size) {
|
||
|
count = QDF_MIN((bufhdr_size - *ppos), rem_len);
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
if (copy_to_user(buf, ((char *)&log_buf->bufhdr) + *ppos,
|
||
|
count))
|
||
|
return -EFAULT;
|
||
|
rem_len -= count;
|
||
|
ret_val += count;
|
||
|
+ spin_lock_bh(&pl_info->log_lock);
|
||
|
}
|
||
|
|
||
|
start_offset = log_buf->rd_offset;
|
||
|
@@ -921,19 +933,23 @@ __pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
|
||
|
goto rd_done;
|
||
|
|
||
|
count = QDF_MIN(rem_len, (end_offset - ppos_data + 1));
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
if (copy_to_user(buf + ret_val,
|
||
|
log_buf->log_data + ppos_data, count))
|
||
|
return -EFAULT;
|
||
|
ret_val += count;
|
||
|
rem_len -= count;
|
||
|
+ spin_lock_bh(&pl_info->log_lock);
|
||
|
} else {
|
||
|
if (ppos_data <= fold_offset) {
|
||
|
count = QDF_MIN(rem_len, (fold_offset - ppos_data + 1));
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
if (copy_to_user(buf + ret_val,
|
||
|
log_buf->log_data + ppos_data, count))
|
||
|
return -EFAULT;
|
||
|
ret_val += count;
|
||
|
rem_len -= count;
|
||
|
+ spin_lock_bh(&pl_info->log_lock);
|
||
|
}
|
||
|
|
||
|
if (rem_len == 0)
|
||
|
@@ -945,11 +961,13 @@ __pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
|
||
|
|
||
|
if (ppos_data <= end_offset) {
|
||
|
count = QDF_MIN(rem_len, (end_offset - ppos_data + 1));
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
if (copy_to_user(buf + ret_val,
|
||
|
log_buf->log_data + ppos_data, count))
|
||
|
return -EFAULT;
|
||
|
ret_val += count;
|
||
|
rem_len -= count;
|
||
|
+ spin_lock_bh(&pl_info->log_lock);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -960,6 +978,7 @@ rd_done:
|
||
|
}
|
||
|
*ppos += ret_val;
|
||
|
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
return ret_val;
|
||
|
}
|
||
|
|
||
|
diff --git a/core/utils/pktlog/pktlog_ac.c b/core/utils/pktlog/pktlog_ac.c
|
||
|
index ab0be7c..524591b 100644
|
||
|
--- a/core/utils/pktlog/pktlog_ac.c
|
||
|
+++ b/core/utils/pktlog/pktlog_ac.c
|
||
|
@@ -457,6 +457,7 @@ int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
||
|
|
||
|
}
|
||
|
|
||
|
+ spin_lock_bh(&pl_info->log_lock);
|
||
|
pl_info->buf->bufhdr.version = CUR_PKTLOG_VER;
|
||
|
pl_info->buf->bufhdr.magic_num = PKTLOG_MAGIC_NUM;
|
||
|
pl_info->buf->wr_offset = 0;
|
||
|
@@ -465,6 +466,7 @@ int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
||
|
pl_info->buf->bytes_written = 0;
|
||
|
pl_info->buf->msg_index = 1;
|
||
|
pl_info->buf->offset = PKTLOG_READ_OFFSET;
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
|
||
|
pl_info->start_time_thruput = os_get_timestamp();
|
||
|
pl_info->start_time_per = pl_info->start_time_thruput;
|
||
|
@@ -542,12 +544,14 @@ int pktlog_setsize(struct hif_opaque_softc *scn, int32_t size)
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
+ spin_lock_bh(&pl_info->log_lock);
|
||
|
if (pl_info->buf != NULL) {
|
||
|
if (pl_dev->is_pktlog_cb_subscribed &&
|
||
|
wdi_pktlog_unsubscribe(pdev_txrx_handle,
|
||
|
pl_info->log_state)) {
|
||
|
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||
|
printk("Cannot unsubscribe pktlog from the WDI\n");
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
pktlog_release_buf(scn);
|
||
|
@@ -560,6 +564,7 @@ int pktlog_setsize(struct hif_opaque_softc *scn, int32_t size)
|
||
|
pl_info->buf_size = size;
|
||
|
}
|
||
|
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||
|
+ spin_unlock_bh(&pl_info->log_lock);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
--
|
||
|
cgit v1.1
|
||
|
|