aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorEspen Fjellvær Olsen <espen@mrfjo.org>2013-01-08 21:30:59 +0100
committerEspen Fjellvær Olsen <espen@mrfjo.org>2013-01-09 18:46:56 +0100
commit49017aa9e80dbdb44cbfe8f4aa3b5edd9466705c (patch)
tree8a22b8d121d4ce41c2f4a590eb9fbf186af5f368 /arch
parent5528b5d5c43f0c38903db0e672581ec4176ae523 (diff)
downloadkernel_samsung_smdk4412-49017aa9e80dbdb44cbfe8f4aa3b5edd9466705c.zip
kernel_samsung_smdk4412-49017aa9e80dbdb44cbfe8f4aa3b5edd9466705c.tar.gz
kernel_samsung_smdk4412-49017aa9e80dbdb44cbfe8f4aa3b5edd9466705c.tar.bz2
Update to the exynos-mem security issue from Samsung I9300 Update7
p2: includes the secmem changes as well as Andreis MFC addition as well Change-Id: I144c2b42586f07b737fba09742315683cbab36ef
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-exynos/include/mach/secmem.h11
-rw-r--r--arch/arm/mach-exynos/mach-midas.c25
-rw-r--r--arch/arm/mach-exynos/secmem-allocdev.c140
3 files changed, 169 insertions, 7 deletions
diff --git a/arch/arm/mach-exynos/include/mach/secmem.h b/arch/arm/mach-exynos/include/mach/secmem.h
index dfa86a4..9adcdf8 100644
--- a/arch/arm/mach-exynos/include/mach/secmem.h
+++ b/arch/arm/mach-exynos/include/mach/secmem.h
@@ -24,6 +24,17 @@ struct secchunk_info {
size_t size;
};
+struct secmem_fd_info {
+ uint32_t phys_addr;
+ size_t size;
+};
+
+struct secmem_fd_list {
+ struct secmem_fd_list *next;
+ struct secmem_fd_list *prev;
+ struct secmem_fd_info fdinfo;
+};
+
extern struct miscdevice secmem;
#if defined(CONFIG_ION)
struct secfd_info {
diff --git a/arch/arm/mach-exynos/mach-midas.c b/arch/arm/mach-exynos/mach-midas.c
index fc6c224..bf8776e 100644
--- a/arch/arm/mach-exynos/mach-midas.c
+++ b/arch/arm/mach-exynos/mach-midas.c
@@ -3423,11 +3423,36 @@ static void __init exynos4_reserve(void)
CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC1 * SZ_1K, 0x65800000, 0);
if (ret != 0)
panic("alloc failed for FIMC1\n");
+ else {
+ static struct cma_region fimc_reg = {
+ .name = "fimc1",
+ .size = CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC1 * SZ_1K,
+ .start = 0x65800000,
+ .reserved = 1,
+ };
+
+ if (cma_early_region_register(&fimc_reg))
+ pr_err("S5P/CMA: Failed to register '%s'\n",
+ fimc_reg.name);
+ }
#endif
#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_M0)
ret = dma_declare_contiguous(&s5p_device_mfc.dev,
0x02800000, 0x5C800000, 0);
+
+ if (ret == 0) {
+ static struct cma_region mfc_reg = {
+ .name = "mfc",
+ .size = 0x02800000,
+ .start = 0x5C800000,
+ .reserved = 1,
+ };
+
+ if (cma_early_region_register(&mfc_reg))
+ pr_err("S5P/CMA: Failed to register '%s'\n",
+ mfc_reg.name);
+ }
#endif
if (ret != 0)
printk(KERN_ERR "%s Fail\n", __func__);
diff --git a/arch/arm/mach-exynos/secmem-allocdev.c b/arch/arm/mach-exynos/secmem-allocdev.c
index cab2bc5..29bd7da 100644
--- a/arch/arm/mach-exynos/secmem-allocdev.c
+++ b/arch/arm/mach-exynos/secmem-allocdev.c
@@ -34,6 +34,8 @@
struct miscdevice secmem;
struct secmem_crypto_driver_ftn *crypto_driver;
+struct secmem_fd_list g_fd_head;
+
#if defined(CONFIG_ION)
extern struct ion_device *ion_exynos;
#endif
@@ -63,9 +65,100 @@ static bool drm_onoff = false;
#define SECMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK)))
+
+static void secmem_fd_list_init(struct secmem_fd_list *list)
+{
+ list->next = list;
+ list->prev = list;
+ list->fdinfo.phys_addr = 0;
+ list->fdinfo.size = 0;
+}
+
+static void secmem_fd_list_clear(struct secmem_fd_list *head)
+{
+ head->next = head;
+ head->prev = head;
+}
+
+static void secmem_fd_list_add(struct secmem_fd_list *new, struct secmem_fd_list *head)
+{
+ head->next->prev = new;
+ new->next = head->next;
+ new->prev = head;
+ head->next = new;
+}
+
+static void secmem_fd_list_del(struct secmem_fd_list *list)
+{
+ list->prev->next = list->next;
+ list->next->prev = list->prev;
+}
+
+static void init_secmem_fd_list(void)
+{
+ secmem_fd_list_init(&g_fd_head);
+}
+
+static void clear_secmem_fd_list(void)
+{
+ secmem_fd_list_clear(&g_fd_head);
+}
+
+static struct secmem_fd_list *secmem_fd_list_find(struct secmem_fd_list *head, uint32_t phys_addr, size_t size)
+{
+ struct secmem_fd_list *pos;
+
+ for (pos = head->next; pos != head; pos = pos->next) {
+ if ((pos->fdinfo.phys_addr == phys_addr) &&
+ (pos->fdinfo.size >= size))
+ return pos;
+ }
+
+ return NULL;
+}
+
+static int find_secmem_fd_list(struct secmem_fd_list *head, uint32_t phys_addr, size_t size)
+{
+ struct secmem_fd_list *fd_ent = NULL;
+
+ fd_ent = secmem_fd_list_find(head, phys_addr, size);
+ if (fd_ent == NULL)
+ return -1;
+
+ return 0;
+}
+
+static void put_secmem_fd_list(struct secmem_fd_info *secmem_fd)
+{
+ struct secmem_fd_list *new = NULL;
+
+ new = (struct secmem_fd_list *)kzalloc(sizeof(struct secmem_fd_list), GFP_KERNEL);
+
+ new->fdinfo.phys_addr = secmem_fd->phys_addr;
+ new->fdinfo.size = secmem_fd->size;
+
+ secmem_fd_list_add(new, &g_fd_head);
+}
+
+static int del_secmem_fd_list(struct secmem_region *region)
+{
+ struct secmem_fd_list *fd_ent = NULL;
+
+ fd_ent = secmem_fd_list_find(&g_fd_head, region->phys_addr, region->len);
+ if (fd_ent == NULL)
+ return -1;
+
+ secmem_fd_list_del(fd_ent);
+ kfree(fd_ent);
+
+ return 0;
+}
+
static int secmem_mmap(struct file *file, struct vm_area_struct *vma)
{
+ int ret;
unsigned long size = vma->vm_end - vma->vm_start;
+ uint32_t phys_addr = vma->vm_pgoff << 12;
BUG_ON(!SECMEM_IS_PAGE_ALIGNED(vma->vm_start));
BUG_ON(!SECMEM_IS_PAGE_ALIGNED(vma->vm_end));
@@ -73,6 +166,12 @@ static int secmem_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ ret = find_secmem_fd_list(&g_fd_head, phys_addr, size);
+ if (ret < 0) {
+ printk(KERN_ERR "%s : Fail mmap due to Invalid address\n", __func__);
+ return -EAGAIN;
+ }
+
if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
size, vma->vm_page_prot)) {
printk(KERN_ERR "%s : remap_pfn_range() failed!\n", __func__);
@@ -213,6 +312,7 @@ static long secmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case SECMEM_IOC_GET_ADDR:
{
struct secmem_region region;
+ struct secmem_fd_info secmem_fd;
if (copy_from_user(&region, (void __user *)arg,
sizeof(struct secmem_region)))
@@ -224,12 +324,29 @@ static long secmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
pr_info("SECMEM_IOC_GET_ADDR: size:%lu\n", region.len);
-
+#ifndef CONFIG_DMA_CMA
+ region.virt_addr = kmalloc(region.len, GFP_KERNEL | GFP_DMA);
+#else
region.virt_addr = dma_alloc_coherent(NULL, region.len,
&region.phys_addr, GFP_KERNEL);
- if (!region.virt_addr)
- panic("SECMEM_IOC_GET_ADDR: dma_alloc_coherent failed! "
- "size=%lu\n", region.len);
+#endif
+ if (!region.virt_addr) {
+ printk(KERN_ERR "%s: Get memory address failed. "
+ " [size : %ld]\n", __func__, region.len);
+ return -EFAULT;
+ }
+
+#ifndef CONFIG_DMA_CMA
+ region.phys_addr = virt_to_phys(region.virt_addr);
+
+ dma_map_single(secmem.this_device, region.virt_addr,
+ region.len, DMA_TO_DEVICE);
+#endif
+
+ secmem_fd.phys_addr = region.phys_addr;
+ secmem_fd.size = region.len;
+
+ put_secmem_fd_list(&secmem_fd);
if (copy_to_user((void __user *)arg, &region,
sizeof(struct secmem_region)))
@@ -250,8 +367,17 @@ static long secmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
pr_info("SECMEM_IOC_RELEASE_ADDR: size:%lu\n", region.len);
+ if (del_secmem_fd_list(&region) < 0) {
+ printk(KERN_ERR "%s: Release memory failed.\n", __func__);
+ return -EFAULT;
+ }
+
+#ifndef CONFIG_DMA_CMA
+ kfree(region.virt_addr);
+#else
dma_free_coherent(NULL, region.len, region.virt_addr,
region.phys_addr);
+#endif
break;
}
@@ -292,9 +418,6 @@ static long secmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
minfo.base = info.lower_bound;
minfo.size = info.total_size;
- printk("[minfo base] : 0x%x", minfo.base);
- printk("[minfo size] : 0x%x", minfo.size);
-
if (copy_to_user((void __user *)arg, &minfo, sizeof(minfo)))
return -EFAULT;
break;
@@ -337,6 +460,8 @@ static int __init secmem_init(void)
crypto_driver = NULL;
+ init_secmem_fd_list();
+
pm_runtime_enable(secmem.this_device);
return 0;
@@ -345,6 +470,7 @@ static int __init secmem_init(void)
static void __exit secmem_exit(void)
{
__pm_runtime_disable(secmem.this_device, false);
+ clear_secmem_fd_list();
misc_deregister(&secmem);
}