diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2019-04-15 22:29:18 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2019-04-15 22:29:19 -0700 |
commit | a12886d31b7e220d83c4cebaf07fafa0a40835a8 (patch) | |
tree | 39b3bb71aa083df888a58cb30040889760785443 | |
parent | dfe4fc94d39b018698d8fb8aaf86507ca42ae141 (diff) | |
parent | 7aaa4a64787a5e6ebee4f9ba56d0bce99a35f574 (diff) |
Merge "msm: vidc: Ensure validity of shared Q indices" into LE.UM.2.3.2.r1.20LE.UM.2.3.2-06400-SDX24
-rw-r--r-- | drivers/media/platform/msm/vidc/venus_hfi.c | 68 |
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 c026fb4e88df..811414af41b5 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 @@ -327,7 +327,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) { @@ -350,16 +350,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", @@ -369,13 +371,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, @@ -471,7 +480,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"); @@ -504,7 +514,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; /* * mb() to ensure qhdr is updated in main memory @@ -521,21 +534,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 - @@ -546,18 +566,18 @@ 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; /* * mb() to ensure qhdr is updated in main memory * so that venus reads the updated header values |