summaryrefslogtreecommitdiff
authorTao Zeng <tao.zeng@amlogic.com>2019-05-07 02:51:42 (GMT)
committer Jianxin Pan <jianxin.pan@amlogic.com>2019-05-09 09:46:38 (GMT)
commit9ddd6cd4c8623ee31f1459ee3812e22291c2a2a3 (patch)
tree8dc5c5dc6cdf44d7e61e096f9fb3595862748c6c
parent32dd894674ecaa380593c33aa0c6ca8cba5bc324 (diff)
downloadcommon-9ddd6cd4c8623ee31f1459ee3812e22291c2a2a3.zip
common-9ddd6cd4c8623ee31f1459ee3812e22291c2a2a3.tar.gz
common-9ddd6cd4c8623ee31f1459ee3812e22291c2a2a3.tar.bz2
kasan: rebuild address layout after vmalloc increased [1/1]
PD#SWPL-8132 Problem: In Jira TV-5143, final fix change have increased 128MB address space for vmalloc. Because binder wasted too many vmalloc space but it's hard to fix it in kernel side. Due to incease of vmalloc address space, old design of address space layout for KASAN32 is not suitable after this change. So we need to change memory layout to fix this problem and let KASAN can running OK again. Solution: 1, rebuild address space layout for kasan 2, make kasan compatible with vmap stack config Verify: p212 Change-Id: I2ce8a840df0ce1fcda61ebeb14a64b1d609719ca Signed-off-by: Tao Zeng <tao.zeng@amlogic.com>
Diffstat
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/Makefile2
-rw-r--r--arch/arm/include/asm/kasan.h22
-rw-r--r--arch/arm/include/asm/memory.h23
-rw-r--r--arch/arm/kernel/unwind.c13
-rw-r--r--arch/arm/mm/kasan_init.c10
-rw-r--r--arch/arm64/include/asm/kasan.h3
-rw-r--r--arch/arm64/mm/kasan_init.c5
-rw-r--r--drivers/amlogic/memory_ext/Kconfig2
-rw-r--r--drivers/amlogic/memory_ext/vmap_stack.c74
-rw-r--r--include/linux/amlogic/vmap_stack.h11
-rw-r--r--mm/kasan/report.c4
12 files changed, 129 insertions, 41 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d341592..d74f489 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1433,6 +1433,7 @@ choice
bool "3G/1G user/kernel split"
config VMSPLIT_3G_OPT
bool "3G/1G user/kernel split (for full 1G low memory)"
+ depends on !AMLOGIC_KASAN32
config VMSPLIT_2G
bool "2G/2G user/kernel split"
config VMSPLIT_1G
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 62732af..4a1ada2 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -53,7 +53,7 @@ LD += -EL
endif
ifeq ($(CONFIG_KASAN),y)
-KASAN_SHADOW_OFFSET := 0xA0000000
+KASAN_SHADOW_OFFSET := 0x99000000
endif
#
diff --git a/arch/arm/include/asm/kasan.h b/arch/arm/include/asm/kasan.h
index 7b86cb0..1bff547 100644
--- a/arch/arm/include/asm/kasan.h
+++ b/arch/arm/include/asm/kasan.h
@@ -20,27 +20,26 @@
* 0x00000000 +--------+
* | |
* | |
- * | | User space memory, 2944MB
+ * | | User space memory, 2816MB
* | |
* | |
- * 0xb8000000 +--------+
- * | | Kasan shaddow memory, 128MB
- * 0xc0000000 +--------+
- * | | Vmalloc address, 240MB
- * | |
+ * 0xb0000000 +--------+
+ * | | Kasan shaddow memory, 144MB
+ * 0xb9000000 +--------+
+ * | | Vmalloc address, 356MB
* 0xCF400000 +--------+
* 0xCF600000 +--------+ PKmap, for kmap 2MB
- * 0xD0000000 +--------+ Module and pkmap, 10MB
+ * 0xD0000000 +--------+ Modul 10MB
* | |
* | | Kernel linear mapped space, 762MB
+ * | |
* 0xFFa00000 +--------+
* 0xFFFc0000 +--------+ static map, 2MB
* 0xFFF00000 +--------+ Fixed map, for kmap_atomic, 3MB
* 0xFFFF0000 +--------+ High vector, 4KB
*
*/
-#define KADDR_SIZE (SZ_1G)
-#define KASAN_SHADOW_SIZE (KADDR_SIZE >> 3)
+#define KASAN_SHADOW_SIZE (0x09000000)
#define KASAN_SHADOW_START (TASK_SIZE)
#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)
@@ -50,13 +49,16 @@
* shadow_addr = (address >> 3) + KASAN_SHADOW_OFFSET;
*
*/
-#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_START - (VMALLOC_START >> 3))
+#define KASAN_SHADOW_OFFSET 0x99000000UL
struct map_desc;
void kasan_init(void);
void kasan_copy_shadow(pgd_t *pgdir);
asmlinkage void kasan_early_init(void);
void cpu_v7_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
void create_mapping(struct map_desc *md);
+#ifdef CONFIG_AMLOGIC_VMAP
+void clear_pgds(unsigned long start, unsigned long end);
+#endif
#else
static inline void kasan_init(void) { }
static inline void kasan_copy_shadow(pgd_t *pgdir) { }
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index f033759..1e81f57 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -38,15 +38,18 @@
* TASK_SIZE - the maximum size of a user space task.
* TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
*/
-#define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(SZ_64M))
-#elif defined(CONFIG_AMLOGIC_KASAN32)
+#ifdef CONFIG_AMLOGIC_KASAN32
/*
- * reserve 128MB address space for kasan
- * for this memory layout implementation, PAGE_OFFSET should be 0xD0000000
+ * if open AMLOGIC_KASAN32, PAGE_OFFSET is set to 0xD0000000
+ * we config 0xB0000000 as shadow memory start. so vmalloc
+ * can be 0xb9000000 and total 368mb space for vmalloc
*/
-#define VMALLOC_START (UL(CONFIG_PAGE_OFFSET) - UL(SZ_256M))
-#define TASK_SIZE (VMALLOC_START - UL(SZ_128M))
+#define VMALLOC_START (UL(0xB9000000))
+#define TASK_SIZE (UL(0xB0000000))
#define KMEM_END (0xffa00000UL)
+#else /* CONFIG_AMLOGIC_KASAN32 */
+#define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(SZ_64M))
+#endif
#else
/*
* TASK_SIZE - the maximum size of a user space task.
@@ -63,7 +66,11 @@
#ifdef CONFIG_AMLOGIC_VMAP
#ifndef CONFIG_THUMB2_KERNEL
+#ifdef CONFIG_AMLOGIC_KASAN32
+#define MODULES_VADDR (PAGE_OFFSET - SZ_16M + SZ_4M + SZ_2M)
+#else
#define MODULES_VADDR (PAGE_OFFSET - SZ_64M)
+#endif /* CONFIG_AMLOGIC_KASAN32 */
#else
#define MODULES_VADDR (PAGE_OFFSET - SZ_8M)
#endif
@@ -73,14 +80,10 @@
* and PAGE_OFFSET - it must be within 32MB of the kernel text.
*/
#ifndef CONFIG_THUMB2_KERNEL
-#ifdef CONFIG_AMLOGIC_KASAN32
/*
* to fix module link problem
*/
-#define MODULES_VADDR (PAGE_OFFSET - SZ_16M + SZ_4M + SZ_2M)
-#else
#define MODULES_VADDR (PAGE_OFFSET - SZ_16M)
-#endif
#else
/* smaller range for Thumb-2 symbols relocation (2^24)*/
#define MODULES_VADDR (PAGE_OFFSET - SZ_8M)
diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
index 4682dd2..7ad8026 100644
--- a/arch/arm/kernel/unwind.c
+++ b/arch/arm/kernel/unwind.c
@@ -246,21 +246,8 @@ static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
}
/* Before poping a register check whether it is feasible or not */
-#ifdef CONFIG_AMLOGIC_KASAN32
-/*
- * If enabled KASAN and unwind_frame is called under IRQ routine,
- * an value-less kasan report will trigger. Because IRQ is using
- * thread context and don't initialized shadow memory when irq_svc
- * saving irq context. Since it's hard to guess reserved memory for
- * shadow in stack by compiler, so we just tell compiler do not
- * sanitize for this function
- */
-int __no_sanitize_address unwind_pop_register(struct unwind_ctrl_block *ctrl,
- unsigned long **vsp, unsigned int reg)
-#else
static int unwind_pop_register(struct unwind_ctrl_block *ctrl,
unsigned long **vsp, unsigned int reg)
-#endif
{
if (unlikely(ctrl->check_each_pop))
if (*vsp >= (unsigned long *)ctrl->sp_high)
diff --git a/arch/arm/mm/kasan_init.c b/arch/arm/mm/kasan_init.c
index cd16c6f..d5416b3 100644
--- a/arch/arm/mm/kasan_init.c
+++ b/arch/arm/mm/kasan_init.c
@@ -120,14 +120,18 @@ static inline pmd_t *pmd_off_k(unsigned long virt)
return pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt);
}
-static void __init clear_pmds(unsigned long start,
- unsigned long end)
+#ifdef CONFIG_AMLOGIC_VMAP
+void __init clear_pgds(unsigned long start, unsigned long end)
+#else
+static void __init clear_pgds(unsigned long start, unsigned long end)
+#endif
{
/*
* Remove references to kasan page tables from
* swapper_pg_dir. pmd_clear() can't be used
* here because it's nop on 2,3-level pagetable setups
*/
+ pr_debug("%s, clear %lx %lx\n", __func__, start, end);
for (; start < end; start += PGDIR_SIZE)
pmd_clear(pmd_off_k(start));
}
@@ -168,7 +172,7 @@ void __init kasan_init(void)
memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir));
dsb(ishst);
cpu_switch_mm(tmp_pg_dir, &init_mm);
- clear_pmds(KASAN_SHADOW_START, KASAN_SHADOW_END);
+ clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
for_each_memblock(memory, reg) {
mem_size += reg->size;
diff --git a/arch/arm64/include/asm/kasan.h b/arch/arm64/include/asm/kasan.h
index 71ad0f9..c609dcd 100644
--- a/arch/arm64/include/asm/kasan.h
+++ b/arch/arm64/include/asm/kasan.h
@@ -31,6 +31,9 @@
void kasan_init(void);
void kasan_copy_shadow(pgd_t *pgdir);
asmlinkage void kasan_early_init(void);
+#ifdef CONFIG_AMLOGIC_VMAP
+void clear_pgds(unsigned long start, unsigned long end);
+#endif
#else
static inline void kasan_init(void) { }
diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index 201d918..01967b4 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -122,8 +122,13 @@ void __init kasan_copy_shadow(pgd_t *pgdir)
} while (pgd++, pgd_new++, pgd != pgd_end);
}
+#ifdef CONFIG_AMLOGIC_VMAP
+void __init clear_pgds(unsigned long start,
+ unsigned long end)
+#else
static void __init clear_pgds(unsigned long start,
unsigned long end)
+#endif
{
/*
* Remove references to kasan page tables from
diff --git a/drivers/amlogic/memory_ext/Kconfig b/drivers/amlogic/memory_ext/Kconfig
index f40e0e3..0da0422 100644
--- a/drivers/amlogic/memory_ext/Kconfig
+++ b/drivers/amlogic/memory_ext/Kconfig
@@ -55,8 +55,6 @@ config AMLOGIC_KASAN32
config AMLOGIC_VMAP
bool "Amlogic kernel stack"
depends on AMLOGIC_MEMORY_EXTEND
- depends on !KASAN
- depends on !AMLOGIC_KASAN32
default y
help
This config is used to enable amlogic kernel stack
diff --git a/drivers/amlogic/memory_ext/vmap_stack.c b/drivers/amlogic/memory_ext/vmap_stack.c
index d199f76..dae386a 100644
--- a/drivers/amlogic/memory_ext/vmap_stack.c
+++ b/drivers/amlogic/memory_ext/vmap_stack.c
@@ -33,6 +33,10 @@
#include <linux/memcontrol.h>
#include <linux/amlogic/vmap_stack.h>
#include <linux/highmem.h>
+#include <linux/delay.h>
+#ifdef CONFIG_KASAN
+#include <linux/kasan.h>
+#endif
#include <asm/tlbflush.h>
#include <asm/stacktrace.h>
@@ -455,16 +459,18 @@ static void check_sp_fault_again(struct pt_regs *regs)
* will fault when we copy back context, so handle
* it first
*/
- E("fault again, sp:%lx, addr:%lx\n", sp, addr);
+ D("fault again, sp:%lx, addr:%lx\n", sp, addr);
page = get_vmap_cached_page(&cache);
WARN_ON(!page);
vmap_mmu_set(page, addr, 1);
update_vmap_stack(1);
+ #ifndef CONFIG_KASAN
if ((THREAD_SIZE_ORDER > 1) && stack_floor_page(addr)) {
E("task:%d %s, stack near overflow, addr:%lx\n",
current->pid, current->comm, addr);
show_fault_stack(addr, regs);
}
+ #endif
/* cache is not enough */
if (cache <= (VMAP_CACHE_PAGE / 2))
@@ -683,6 +689,40 @@ void aml_account_task_stack(struct task_struct *tsk, int account)
}
}
+#ifdef CONFIG_KASAN
+DEFINE_MUTEX(stack_shadow_lock);
+static void check_and_map_stack_shadow(unsigned long addr)
+{
+ unsigned long shadow;
+ struct page *page, *pages[2] = {};
+ int ret;
+
+ shadow = (unsigned long)kasan_mem_to_shadow((void *)addr);
+ page = check_pte_exist(shadow);
+ if (page) {
+ WARN(page_address(page) == (void *)kasan_zero_page,
+ "bad pte, page:%p, %lx, addr:%lx\n",
+ page_address(page), page_to_pfn(page), addr);
+ return;
+ }
+ shadow = shadow & PAGE_MASK;
+ page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM |
+ __GFP_ZERO | __GFP_REPEAT);
+ if (!page) {
+ WARN(!page,
+ "alloc page for addr:%lx, shadow:%lx fail\n",
+ addr, shadow);
+ return;
+ }
+ pages[0] = page;
+ ret = map_kernel_range_noflush(shadow, PAGE_SIZE, PAGE_KERNEL, pages);
+ if (ret < 0) {
+ pr_err("%s, map shadow:%lx failed:%d\n", __func__, shadow, ret);
+ __free_page(page);
+ }
+}
+#endif
+
void *aml_stack_alloc(int node, struct task_struct *tsk)
{
unsigned long bitmap_no, raw_start;
@@ -722,6 +762,12 @@ void *aml_stack_alloc(int node, struct task_struct *tsk)
map_addr = addr + STACK_TOP_PAGE_OFF;
vmap_mmu_set(page, map_addr, 1);
update_vmap_stack(1);
+#ifdef CONFIG_KASAN
+ /* 2 thread stack can be a single shadow page, we need use lock */
+ mutex_lock(&stack_shadow_lock);
+ check_and_map_stack_shadow(addr);
+ mutex_unlock(&stack_shadow_lock);
+#endif
D("bit idx:%5ld, start:%5ld, addr:%lx, page:%lx\n",
bitmap_no, raw_start, addr, page_to_pfn(page));
@@ -747,6 +793,9 @@ void aml_stack_free(struct task_struct *tsk)
page = vmalloc_to_page((const void *)addr);
if (!page)
break;
+ #ifdef CONFIG_KASAN
+ kasan_unpoison_shadow((void *)addr, PAGE_SIZE);
+ #endif
vmap_mmu_set(page, addr, 0);
/* supplement for stack page cache first */
spin_lock_irqsave(&avmap->page_lock, flags);
@@ -813,6 +862,9 @@ void __init thread_stack_cache_init(void)
{
int i;
struct page *page;
+#ifdef CONFIG_KASAN
+ unsigned long align, size;
+#endif
page = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, VMAP_CACHE_PAGE_ORDER);
if (!page)
@@ -832,11 +884,31 @@ void __init thread_stack_cache_init(void)
}
pr_info("%s, vmap:%p, bitmap:%p, cache page:%lx\n",
__func__, avmap, avmap->bitmap, page_to_pfn(page));
+#ifdef CONFIG_KASAN
+ align = PGDIR_SIZE << KASAN_SHADOW_SCALE_SHIFT;
+ size = VM_STACK_AREA_SIZE;
+ size = ALIGN(size, align);
+ avmap->root_vm = __get_vm_area_node(size, align, VM_NO_GUARD,
+ VMALLOC_START, VMALLOC_END,
+ NUMA_NO_NODE, GFP_KERNEL,
+ __builtin_return_address(0));
+ WARN(!avmap->root_vm, "alloc vmap area %lx failed\n", size);
+ if (avmap->root_vm) {
+ unsigned long s, e;
+
+ s = (unsigned long)kasan_mem_to_shadow(avmap->root_vm->addr);
+ e = (unsigned long)avmap->root_vm->addr + size;
+ e = (unsigned long)kasan_mem_to_shadow((void *)e);
+ pr_info("%s, s:%lx, e:%lx, size:%lx\n", __func__, s, e, size);
+ clear_pgds(s, e);
+ }
+#else
avmap->root_vm = __get_vm_area_node(VM_STACK_AREA_SIZE,
VMAP_ALIGN,
0, VMAP_ADDR_START, VMAP_ADDR_END,
NUMA_NO_NODE, GFP_KERNEL,
__builtin_return_address(0));
+#endif
if (!avmap->root_vm) {
__free_pages(page, VMAP_CACHE_PAGE_ORDER);
kfree(avmap->bitmap);
diff --git a/include/linux/amlogic/vmap_stack.h b/include/linux/amlogic/vmap_stack.h
index a8aa35f..9b1f868 100644
--- a/include/linux/amlogic/vmap_stack.h
+++ b/include/linux/amlogic/vmap_stack.h
@@ -28,8 +28,13 @@
#else
/* currently support max 6144 tasks on 32bit */
#define VM_STACK_AREA_SIZE (SZ_64M - SZ_16M)
+#ifdef CONFIG_AMLOGIC_KASAN32 /* change place if open kasan */
+#define VMAP_ADDR_START VMALLOC_START
+#define VMAP_ADDR_END (VMALLOC_START + VM_STACK_AREA_SIZE)
+#else
#define VMAP_ADDR_START MODULES_VADDR
#define VMAP_ADDR_END MODULES_END
+#endif /* CONFIG_AMLOGIC_KASAN32 */
#define VMAP_ALIGN SZ_64M
#endif
@@ -40,9 +45,13 @@
#define VMAP_PAGE_FLAG (__GFP_ZERO | __GFP_HIGH |\
__GFP_ATOMIC | __GFP_REPEAT)
+#ifdef CONFIG_KASAN
+#define VMAP_CACHE_PAGE_ORDER 7
+#else
#define VMAP_CACHE_PAGE_ORDER 5
+#endif
#define VMAP_CACHE_PAGE (1 << VMAP_CACHE_PAGE_ORDER)
-#define CACHE_MAINTAIN_DELAY (HZ)
+#define CACHE_MAINTAIN_DELAY (HZ / 2)
struct aml_vmap {
spinlock_t vmap_lock;
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index a324797..21f67cb 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -397,7 +397,11 @@ static inline bool kasan_report_enabled(void)
void kasan_report(unsigned long addr, size_t size,
bool is_write, unsigned long ip)
{
+#ifdef CONFIG_AMLOGIC_MODIFY
+ struct kasan_access_info info = {};
+#else
struct kasan_access_info info;
+#endif
if (likely(!kasan_report_enabled()))
return;