video: rockchip: rga3: Fix memory out-of-bounds on iova

When the virtual address has an in-page offset, iova needs to be offset
to the corresponding starting point.

Update driver version to 1.2.1

Signed-off-by: Yu Qiaowei <cerf.yu@rock-chips.com>
Change-Id: I01e5109bd684f573920773d0d1e08685d1214a40
This commit is contained in:
Yu Qiaowei
2022-01-25 11:20:52 +08:00
committed by Tao Huang
parent 821d33cd0f
commit ee87937f76
3 changed files with 34 additions and 14 deletions

View File

@@ -75,7 +75,7 @@
#define DRIVER_MAJOR_VERISON 1
#define DRIVER_MINOR_VERSION 2
#define DRIVER_REVISION_VERSION 0
#define DRIVER_REVISION_VERSION 1
#define DRIVER_VERSION (STR(DRIVER_MAJOR_VERISON) "." STR(DRIVER_MINOR_VERSION) \
"." STR(DRIVER_REVISION_VERSION))
@@ -181,6 +181,12 @@ struct rga_dma_buffer {
dma_addr_t iova;
unsigned long size;
/*
* The offset of the first page of the sgt.
* Since alloc iova must be page aligned, the offset of the first page is
* identified separately.
*/
size_t offset;
/* The core of the mapping */
int core;
@@ -194,6 +200,9 @@ struct rga_virt_addr {
int page_count;
unsigned long size;
/* The offset of the first page of the virtual address */
size_t offset;
int result;
};

View File

@@ -497,7 +497,8 @@ static int rga_viraddr_get_channel_info(struct rga_img_info_t *channel_info,
unsigned long size;
unsigned long start_addr;
unsigned int count;
int order = 0;
int pages_order = 0;
int page_table_order = 0;
uint32_t *page_table = NULL;
struct page **pages = NULL;
@@ -543,18 +544,20 @@ static int rga_viraddr_get_channel_info(struct rga_img_info_t *channel_info,
count = rga_buf_size_cal(channel_info->yrgb_addr, channel_info->uv_addr,
channel_info->v_addr, format,
channel_info->vir_w, channel_info->vir_h,
&start_addr, &size);
&start_addr, NULL);
size = count * PAGE_SIZE;
/* alloc pages and page_table */
order = get_order(size / 4096 * sizeof(struct page *));
pages = (struct page **)__get_free_pages(GFP_KERNEL, order);
pages_order = get_order(count * sizeof(struct page *));
pages = (struct page **)__get_free_pages(GFP_KERNEL, pages_order);
if (pages == NULL) {
pr_err("Can not alloc pages for pages\n");
ret = -ENOMEM;
goto out_free_buffer;
}
page_table = (uint32_t *)__get_free_pages(GFP_KERNEL, order);
page_table_order = get_order(count * sizeof(uint32_t *));
page_table = (uint32_t *)__get_free_pages(GFP_KERNEL, page_table_order);
if (page_table == NULL) {
pr_err("Can not alloc pages for page_table\n");
ret = -ENOMEM;
@@ -604,7 +607,12 @@ static int rga_viraddr_get_channel_info(struct rga_img_info_t *channel_info,
goto out_free_sg;
}
channel_info->yrgb_addr = iova;
/*
* When the virtual address has an in-page offset, it needs to be offset to
* the corresponding starting point.
*/
channel_info->yrgb_addr = iova + (channel_info->yrgb_addr & (~PAGE_MASK));
alloc_buffer->iova = iova;
alloc_buffer->size = size;
alloc_buffer->cookie = cookie;
@@ -613,8 +621,8 @@ static int rga_viraddr_get_channel_info(struct rga_img_info_t *channel_info,
sg_free_table(&sgt);
free_pages((unsigned long)pages, order);
free_pages((unsigned long)page_table, order);
free_pages((unsigned long)pages, pages_order);
free_pages((unsigned long)page_table, page_table_order);
*rga_dma_buffer = alloc_buffer;
@@ -625,10 +633,10 @@ out_free_sg:
rga_iommu_dma_free_iova(cookie, iova, size);
out_free_pages_table:
free_pages((unsigned long)page_table, order);
free_pages((unsigned long)page_table, page_table_order);
out_free_pages:
free_pages((unsigned long)pages, order);
free_pages((unsigned long)pages, pages_order);
out_free_buffer:
kfree(alloc_buffer);

View File

@@ -216,6 +216,7 @@ static int rga_alloc_sgt(struct rga_virt_addr *virt_addr,
virt_dma_buf->sgt = sgt;
virt_dma_buf->size = virt_addr->size;
virt_dma_buf->offset = virt_addr->offset;
return 0;
@@ -267,10 +268,11 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p,
/* Calculate page size. */
count = rga_buf_size_cal(viraddr, viraddr, viraddr, format,
memory_parm->width, memory_parm->height,
&start_addr, &size);
&start_addr, NULL);
size = count * PAGE_SIZE;
/* alloc pages and page_table */
order = get_order(size / 4096 * sizeof(struct page *));
order = get_order(count * sizeof(struct page *));
pages = (struct page **)__get_free_pages(GFP_KERNEL, order);
if (pages == NULL) {
pr_err("%s can not alloc pages for pages\n", __func__);
@@ -301,6 +303,7 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p,
virt_addr->pages_order = order;
virt_addr->page_count = count;
virt_addr->size = size;
virt_addr->offset = viraddr & (~PAGE_MASK);
virt_addr->result = result;
return 0;
@@ -702,7 +705,7 @@ dma_addr_t rga_mm_lookup_iova(struct rga_internal_buffer *buffer, int core)
for (i = 0; i < buffer->dma_buffer_size; i++)
if (buffer->dma_buffer[i].core == core)
return buffer->dma_buffer[i].iova;
return buffer->dma_buffer[i].iova + buffer->dma_buffer[i].offset;
return 0;
}