From 684d03a49b41351bfb68c6520b9a79750a8579e4 Mon Sep 17 00:00:00 2001 From: "hyesoo.yu" Date: Fri, 14 Jul 2017 13:23:08 +0900 Subject: [PATCH] [COMMON] g2d: fix the security hole Secure layer information could be changed at any time on normal OS. That is, someone can change the destination from secure to normal by hacking maliciously. To solve this problem, modify that every task has been pushed in the secure world. Change-Id: I1e1a272f8fea8d8fa78c060696b3fa457165c4a2 Signed-off-by: hyesoo.yu --- drivers/gpu/exynos/g2d/g2d.h | 8 ++++++++ drivers/gpu/exynos/g2d/g2d_command.c | 20 ++++++++++++------- drivers/gpu/exynos/g2d/g2d_regs.c | 30 ++++++++++++++++++++++++++++ drivers/gpu/exynos/g2d/g2d_task.c | 24 ---------------------- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/exynos/g2d/g2d.h b/drivers/gpu/exynos/g2d/g2d.h index 9e1a5a7a7e0a..77bb8903e8ea 100644 --- a/drivers/gpu/exynos/g2d/g2d.h +++ b/drivers/gpu/exynos/g2d/g2d.h @@ -22,6 +22,14 @@ struct g2d_task; /* defined in g2d_task.h */ +struct g2d_task_secbuf { + unsigned long cmd_paddr; + int cmd_count; + int priority; + int job_id; + int secure_layer; +}; + enum g2d_priority { G2D_LOW_PRIORITY, G2D_MEDIUM_PRIORITY, diff --git a/drivers/gpu/exynos/g2d/g2d_command.c b/drivers/gpu/exynos/g2d/g2d_command.c index 7dec4b811e2e..e31d3abc6b03 100644 --- a/drivers/gpu/exynos/g2d/g2d_command.c +++ b/drivers/gpu/exynos/g2d/g2d_command.c @@ -123,6 +123,18 @@ static void g2d_set_hwfc_commands(struct g2d_task *task) task->cmd_count++; } +#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION +void g2d_complete_commands(struct g2d_task *task) +{ + /* 832 is the total number of the G2D registers */ + BUG_ON(task->cmd_count > 830); + + g2d_set_taskctl_commands(task); + + if (IS_HWFC(task->flags)) + g2d_set_hwfc_commands(task); +} +#else void g2d_complete_commands(struct g2d_task *task) { struct g2d_reg *regs = page_address(task->cmd_page); @@ -152,6 +164,7 @@ void g2d_complete_commands(struct g2d_task *task) regs[task->cmd_count].value = 1; task->cmd_count++; } +#endif static const struct g2d_fmt g2d_formats[] = { { @@ -962,9 +975,6 @@ bool g2d_prepare_source(struct g2d_task *task, if ((layer->flags & G2D_LAYERFLAG_COLORFILL) != 0) return true; - if ((layer->flags & G2D_LAYERFLAG_SECURE) != 0) - reg[TASK_REG_LAYER_SECURE].value |= 1 << index; - task->cmd_count = ((colormode & G2D_DATAFORMAT_AFBC) != 0) ? g2d_set_afbc_buffer(task, layer, LAYER_OFFSET(index)) : g2d_set_image_buffer(task, layer, colormode, @@ -978,12 +988,8 @@ bool g2d_prepare_source(struct g2d_task *task, bool g2d_prepare_target(struct g2d_task *task) { - struct g2d_reg *reg = (struct g2d_reg *)page_address(task->cmd_page); u32 colormode = task->target.commands[G2DSFR_IMG_COLORMODE].value; - if ((task->target.flags & G2D_LAYERFLAG_SECURE) != 0) - reg[TASK_REG_LAYER_SECURE].value |= 1 << 24; - task->cmd_count = ((colormode & G2D_DATAFORMAT_AFBC) != 0) ? g2d_set_afbc_buffer(task, &task->target, TARGET_OFFSET) diff --git a/drivers/gpu/exynos/g2d/g2d_regs.c b/drivers/gpu/exynos/g2d/g2d_regs.c index c33104ffd8b1..571e309b16cd 100644 --- a/drivers/gpu/exynos/g2d/g2d_regs.c +++ b/drivers/gpu/exynos/g2d/g2d_regs.c @@ -19,7 +19,36 @@ #include "g2d.h" #include "g2d_regs.h" #include "g2d_task.h" +#include "g2d_uapi.h" +#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION +#include +#include + +void g2d_hw_push_task(struct g2d_device *g2d_dev, struct g2d_task *task) +{ + struct g2d_task_secbuf sec_task; + int i; + + sec_task.cmd_paddr = (unsigned long)page_to_phys(task->cmd_page); + sec_task.cmd_count = task->cmd_count; + sec_task.priority = task->priority; + sec_task.job_id = task->job_id; + sec_task.secure_layer = 0; + + for (i = 0; i < task->num_source; i++) { + if ((task->source[i].flags & G2D_LAYERFLAG_SECURE) != 0) + sec_task.secure_layer |= 1 << i; + } + if ((task->target.flags & G2D_LAYERFLAG_SECURE) != 0) + sec_task.secure_layer |= 1 << 24; + + __flush_dcache_area(&sec_task, sizeof(sec_task)); + __flush_dcache_area(page_address(task->cmd_page), G2D_CMD_LIST_SIZE); + if (exynos_smc(SMC_DRM_G2D_CMD_DATA, virt_to_phys(&sec_task), 0, 0)) + BUG_ON(1); +} +#else void g2d_hw_push_task(struct g2d_device *g2d_dev, struct g2d_task *task) { u32 state = g2d_hw_get_job_state(g2d_dev, task->job_id); @@ -38,6 +67,7 @@ void g2d_hw_push_task(struct g2d_device *g2d_dev, struct g2d_task *task) writel_relaxed(1 << task->job_id, g2d_dev->reg + G2D_JOB_INT_ID_REG); writel(G2D_JOBPUSH_INT_ENABLE, g2d_dev->reg + G2D_JOB_PUSH_REG); } +#endif static const char *error_desc[3] = { "AFBC Stuck", diff --git a/drivers/gpu/exynos/g2d/g2d_task.c b/drivers/gpu/exynos/g2d/g2d_task.c index 1329fafba24d..287eefd77ae6 100644 --- a/drivers/gpu/exynos/g2d/g2d_task.c +++ b/drivers/gpu/exynos/g2d/g2d_task.c @@ -28,33 +28,9 @@ #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION #include -#define G2D_SECURE_DMA_BASE 0x8000000 -#define G2D_SEC_COMMAND_BUF 12 #define G2D_ALWAYS_S 37 - static int g2d_map_cmd_data(struct g2d_task *task) { - struct g2d_buffer_prot_info *prot = &task->prot_info; - int ret; - - prot->chunk_count = 1; - prot->flags = G2D_SEC_COMMAND_BUF; - prot->chunk_size = G2D_CMD_LIST_SIZE; - prot->bus_address = page_to_phys(task->cmd_page); - prot->dma_addr = G2D_SECURE_DMA_BASE + G2D_CMD_LIST_SIZE * task->job_id; - - __flush_dcache_area(prot, sizeof(struct g2d_buffer_prot_info)); - ret = exynos_smc(SMC_DRM_PPMP_PROT, virt_to_phys(prot), 0, 0); - - if (ret) { - dev_err(task->g2d_dev->dev, - "Failed to map secure page tbl (%d) %x %x %lx\n", ret, - prot->dma_addr, prot->flags, prot->bus_address); - return ret; - } - - task->cmd_addr = prot->dma_addr; - return 0; } -- 2.20.1