[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:33 +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: I1e1a272f8fea8d8fa78c060696b3fa457165c4a2
Signed-off-by: hyesoo.yu <hyesoo.yu@samsung.com>
drivers/gpu/exynos/g2d/g2d.h
drivers/gpu/exynos/g2d/g2d_command.c
drivers/gpu/exynos/g2d/g2d_regs.c
drivers/gpu/exynos/g2d/g2d_task.c

index 9e1a5a7a7e0a10112950ae75c15a99f9297ceeb7..77bb8903e8ea828f8748b350d67151fc186f1007 100644 (file)
 
 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,
index 7dec4b811e2e47147a6d6f5eae08ff2c5f54f3a2..e31d3abc6b0341ed8913e81b8d515afb62830d75 100644 (file)
@@ -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)
index c33104ffd8b1c3647c63c2cfad09f1ae95810e69..571e309b16cdeae76f4577af316818fe0ad3d3ed 100644 (file)
 #include "g2d.h"
 #include "g2d_regs.h"
 #include "g2d_task.h"
+#include "g2d_uapi.h"
 
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+#include <linux/smc.h>
+#include <asm/cacheflush.h>
+
+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",
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;
 }