From f2eeda955ea9050d2d7535ad998491522d056315 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: Ic6a35920452f49bd735a4e3545a22d71cba7c190 Signed-off-by: hyesoo.yu --- drivers/gpu/exynos/g2d/g2d_command.c | 34 ++++++++++---------- drivers/gpu/exynos/g2d/g2d_debug.c | 2 +- drivers/gpu/exynos/g2d/g2d_debug.h | 1 + drivers/gpu/exynos/g2d/g2d_regs.c | 46 ++++++++++++++++++++++++++++ drivers/gpu/exynos/g2d/g2d_task.c | 24 --------------- 5 files changed, 66 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/exynos/g2d/g2d_command.c b/drivers/gpu/exynos/g2d/g2d_command.c index 7dec4b811e2e..0f6cb3fb376b 100644 --- a/drivers/gpu/exynos/g2d/g2d_command.c +++ b/drivers/gpu/exynos/g2d/g2d_command.c @@ -123,19 +123,14 @@ static void g2d_set_hwfc_commands(struct g2d_task *task) task->cmd_count++; } -void g2d_complete_commands(struct g2d_task *task) +#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION +#define g2d_set_start_commands(task) do { } while (0) +#else +void g2d_set_start_commands(struct g2d_task *task) { struct g2d_reg *regs = page_address(task->cmd_page); unsigned int n; - /* 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); - /* * Number of commands should be multiple of 8. * If it is not, then pad dummy commands with no side effect. @@ -152,6 +147,20 @@ void g2d_complete_commands(struct g2d_task *task) regs[task->cmd_count].value = 1; task->cmd_count++; } +#endif + +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); + + g2d_set_start_commands(task); +} static const struct g2d_fmt g2d_formats[] = { { @@ -962,9 +971,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 +984,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_debug.c b/drivers/gpu/exynos/g2d/g2d_debug.c index aea9c9bf5f00..ecb6ee12cc63 100644 --- a/drivers/gpu/exynos/g2d/g2d_debug.c +++ b/drivers/gpu/exynos/g2d/g2d_debug.c @@ -135,7 +135,7 @@ static struct regs_info g2d_reg_info[] = { { 0x1100, 0x100, "Layer15" }, }; -static void g2d_dump_task(struct g2d_task *task) +void g2d_dump_task(struct g2d_task *task) { struct g2d_device *g2d_dev = task->g2d_dev; unsigned int i, num_array; diff --git a/drivers/gpu/exynos/g2d/g2d_debug.h b/drivers/gpu/exynos/g2d/g2d_debug.h index 8daccd0970c2..7e3685ca1c8c 100644 --- a/drivers/gpu/exynos/g2d/g2d_debug.h +++ b/drivers/gpu/exynos/g2d/g2d_debug.h @@ -48,4 +48,5 @@ enum g2d_stamp_id { void g2d_init_debug(struct g2d_device *dev); void g2d_destroy_debug(struct g2d_device *dev); void g2d_stamp_task(struct g2d_task *task, u32 val); +void g2d_dump_task(struct g2d_task *task); #endif /* __EXYNOS_G2D_HELPER_H_ */ diff --git a/drivers/gpu/exynos/g2d/g2d_regs.c b/drivers/gpu/exynos/g2d/g2d_regs.c index c33104ffd8b1..e943fa57e0df 100644 --- a/drivers/gpu/exynos/g2d/g2d_regs.c +++ b/drivers/gpu/exynos/g2d/g2d_regs.c @@ -19,7 +19,52 @@ #include "g2d.h" #include "g2d_regs.h" #include "g2d_task.h" +#include "g2d_uapi.h" +#include "g2d_debug.h" + +#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION +#include +#include + +struct g2d_task_secbuf { + unsigned long cmd_paddr; + int cmd_count; + int priority; + int job_id; + int secure_layer; +}; +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)) + sec_task.secure_layer |= 1 << i; + } + if (!!(task->target.flags & G2D_LAYERFLAG_SECURE) || + !!(sec_task.secure_layer)) + 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)) { + dev_err(g2d_dev->dev, "%s : Failed to push %d %d %d %d\n", + __func__, sec_task.cmd_count, sec_task.priority, + sec_task.job_id, sec_task.secure_layer); + + g2d_dump_task(task); + BUG(); + } +} +#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 +83,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