summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVikash Garodia <vgarodia@codeaurora.org>2019-01-12 00:32:22 +0530
committerVikash Garodia <vgarodia@codeaurora.org>2019-02-08 16:47:51 +0530
commit0aa01df247f846ea3907e9ba6bb803af3b6b6e9e (patch)
tree80c67fe93e39e11e27f1e92f4a70a2ac091173ab
parent5b964b49e9fdfe977724a260d2972d5befd175a2 (diff)
msm: vidc: Ensure validity of shared Q indices
Video driver and firmware communicates over shared queue. The queue header has the indices which synchronizes the read and write between the driver and firmware modules. This change ensures that the indices are within the valid range before accessing them. CRs-fixed: 2345481 Change-Id: I8da6bb4218a5b8ec0e2e2c7b87f6cc9eec21bd16 Signed-off-by: Vikash Garodia <vgarodia@codeaurora.org> Signed-off-by: Paras Nagda <pnagda@codeaurora.org>
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.c68
1 files changed, 44 insertions, 24 deletions
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index d828d81ab724..18899373de8a 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -328,7 +328,7 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
{
struct hfi_queue_header *queue;
u32 packet_size_in_words, new_write_idx;
- u32 empty_space, read_idx;
+ u32 empty_space, read_idx, write_idx;
u32 *write_ptr;
if (!qinfo || !packet) {
@@ -351,16 +351,18 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
}
packet_size_in_words = (*(u32 *)packet) >> 2;
- if (!packet_size_in_words) {
- dprintk(VIDC_ERR, "Zero packet size\n");
+ if (!packet_size_in_words || packet_size_in_words >
+ qinfo->q_array.mem_size>>2) {
+ dprintk(VIDC_ERR, "Invalid packet size\n");
return -ENODATA;
}
read_idx = queue->qhdr_read_idx;
+ write_idx = queue->qhdr_write_idx;
- empty_space = (queue->qhdr_write_idx >= read_idx) ?
- (queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) :
- (read_idx - queue->qhdr_write_idx);
+ empty_space = (write_idx >= read_idx) ?
+ ((qinfo->q_array.mem_size>>2) - (write_idx - read_idx)) :
+ (read_idx - write_idx);
if (empty_space <= packet_size_in_words) {
queue->qhdr_tx_req = 1;
dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n",
@@ -370,13 +372,20 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
queue->qhdr_tx_req = 0;
- new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
+ new_write_idx = write_idx + packet_size_in_words;
write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
- (queue->qhdr_write_idx << 2));
- if (new_write_idx < queue->qhdr_q_size) {
+ (write_idx << 2));
+ if (write_ptr < (u32 *)qinfo->q_array.align_virtual_addr ||
+ write_ptr > (u32 *)(qinfo->q_array.align_virtual_addr +
+ qinfo->q_array.mem_size)) {
+ dprintk(VIDC_ERR, "Invalid write index");
+ return -ENODATA;
+ }
+
+ if (new_write_idx < (qinfo->q_array.mem_size >> 2)) {
memcpy(write_ptr, packet, packet_size_in_words << 2);
} else {
- new_write_idx -= queue->qhdr_q_size;
+ new_write_idx -= qinfo->q_array.mem_size >> 2;
memcpy(write_ptr, packet, (packet_size_in_words -
new_write_idx) << 2);
memcpy((void *)qinfo->q_array.align_virtual_addr,
@@ -468,7 +477,8 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
u32 packet_size_in_words, new_read_idx;
u32 *read_ptr;
u32 receive_request = 0;
- int rc = 0;
+ u32 read_idx, write_idx;
+ int rc = 0;
if (!qinfo || !packet || !pb_tx_req_is_set) {
dprintk(VIDC_ERR, "Invalid Params\n");
@@ -499,7 +509,10 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q)
receive_request = 1;
- if (queue->qhdr_read_idx == queue->qhdr_write_idx) {
+ read_idx = queue->qhdr_read_idx;
+ write_idx = queue->qhdr_write_idx;
+
+ if (read_idx == write_idx) {
queue->qhdr_rx_req = receive_request;
*pb_tx_req_is_set = 0;
dprintk(VIDC_DBG,
@@ -511,21 +524,28 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
}
read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
- (queue->qhdr_read_idx << 2));
+ (read_idx << 2));
+ if (read_ptr < (u32 *)qinfo->q_array.align_virtual_addr ||
+ read_ptr > (u32 *)(qinfo->q_array.align_virtual_addr +
+ qinfo->q_array.mem_size - sizeof(*read_ptr))) {
+ dprintk(VIDC_ERR, "Invalid read index\n");
+ return -ENODATA;
+ }
+
packet_size_in_words = (*read_ptr) >> 2;
if (!packet_size_in_words) {
dprintk(VIDC_ERR, "Zero packet size\n");
return -ENODATA;
}
- new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
- if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE)
- && queue->qhdr_read_idx <= queue->qhdr_q_size) {
- if (new_read_idx < queue->qhdr_q_size) {
+ new_read_idx = read_idx + packet_size_in_words;
+ if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) &&
+ read_idx <= (qinfo->q_array.mem_size >> 2)) {
+ if (new_read_idx < (qinfo->q_array.mem_size >> 2)) {
memcpy(packet, read_ptr,
packet_size_in_words << 2);
} else {
- new_read_idx -= queue->qhdr_q_size;
+ new_read_idx -= (qinfo->q_array.mem_size >> 2);
memcpy(packet, read_ptr,
(packet_size_in_words - new_read_idx) << 2);
memcpy(packet + ((packet_size_in_words -
@@ -536,19 +556,19 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
} else {
dprintk(VIDC_WARN,
"BAD packet received, read_idx: %#x, pkt_size: %d\n",
- queue->qhdr_read_idx, packet_size_in_words << 2);
+ read_idx, packet_size_in_words << 2);
dprintk(VIDC_WARN, "Dropping this packet\n");
- new_read_idx = queue->qhdr_write_idx;
+ new_read_idx = write_idx;
rc = -ENODATA;
}
- queue->qhdr_read_idx = new_read_idx;
-
- if (queue->qhdr_read_idx != queue->qhdr_write_idx)
+ if (new_read_idx != write_idx)
queue->qhdr_rx_req = 0;
else
queue->qhdr_rx_req = receive_request;
+ queue->qhdr_read_idx = new_read_idx;
+
*pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
if (msm_vidc_debug & VIDC_PKT) {