[COMMON] g2d: fix the security hole
authorhyesoo.yu <hyesoo.yu@samsung.com>
Fri, 14 Jul 2017 04:23:08 +0000 (13:23 +0900)
committerSeungchul Kim <sc377.kim@samsung.com>
Mon, 28 May 2018 05:27:41 +0000 (14:27 +0900)
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 <hyesoo.yu@samsung.com>
drivers/gpu/exynos/g2d/g2d_command.c
drivers/gpu/exynos/g2d/g2d_debug.c
drivers/gpu/exynos/g2d/g2d_debug.h
drivers/gpu/exynos/g2d/g2d_regs.c
drivers/gpu/exynos/g2d/g2d_task.c

index 7dec4b811e2e47147a6d6f5eae08ff2c5f54f3a2..0f6cb3fb376bc9611c7c5729cead02fbe8910e7a 100644 (file)
@@ -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)
index aea9c9bf5f0095b66c098e0df99105a2719d3876..ecb6ee12cc635ea399ef288b85c479fa42d01f8e 100644 (file)
@@ -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;
index 8daccd0970c2528d54fedab9be73369d773272ac..7e3685ca1c8ce181d7b25cfa72dd241abbee2f20 100644 (file)
@@ -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_ */
index c33104ffd8b1c3647c63c2cfad09f1ae95810e69..e943fa57e0df7731963b129ca604d03b1d6f9d18 100644 (file)
 #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 <linux/smc.h>
+#include <asm/cacheflush.h>
+
+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",
index 1329fafba24df290de5dade952899ce02dca1a06..287eefd77ae694591cf9e4283597d715c1832929 100644 (file)
 #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
 #include <linux/smc.h>
 
-#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;
 }