2015-10-12 23:52:58 +08:00
|
|
|
/*
|
|
|
|
* This file contains kasan initialization code for ARM64.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
|
|
|
|
* Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define pr_fmt(fmt) "kasan: " fmt
|
2017-11-16 09:36:40 +08:00
|
|
|
#include <linux/bootmem.h>
|
2015-10-12 23:52:58 +08:00
|
|
|
#include <linux/kasan.h>
|
|
|
|
#include <linux/kernel.h>
|
2017-02-04 08:20:53 +08:00
|
|
|
#include <linux/sched/task.h>
|
2015-10-12 23:52:58 +08:00
|
|
|
#include <linux/memblock.h>
|
|
|
|
#include <linux/start_kernel.h>
|
2017-01-11 05:35:49 +08:00
|
|
|
#include <linux/mm.h>
|
2015-10-12 23:52:58 +08:00
|
|
|
|
2016-01-25 19:45:02 +08:00
|
|
|
#include <asm/mmu_context.h>
|
2016-02-16 20:52:40 +08:00
|
|
|
#include <asm/kernel-pgtable.h>
|
2015-10-12 23:52:58 +08:00
|
|
|
#include <asm/page.h>
|
|
|
|
#include <asm/pgalloc.h>
|
|
|
|
#include <asm/pgtable.h>
|
2016-02-16 20:52:40 +08:00
|
|
|
#include <asm/sections.h>
|
2015-10-12 23:52:58 +08:00
|
|
|
#include <asm/tlbflush.h>
|
|
|
|
|
|
|
|
static pgd_t tmp_pg_dir[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE);
|
|
|
|
|
2017-01-11 05:35:49 +08:00
|
|
|
/*
|
|
|
|
* The p*d_populate functions call virt_to_phys implicitly so they can't be used
|
|
|
|
* directly on kernel symbols (bm_p*d). All the early functions are called too
|
|
|
|
* early to use lm_alias so __p*d_populate functions must be used to populate
|
|
|
|
* with the physical address from __pa_symbol.
|
|
|
|
*/
|
|
|
|
|
2017-11-16 09:36:40 +08:00
|
|
|
static phys_addr_t __init kasan_alloc_zeroed_page(int node)
|
2015-10-12 23:52:58 +08:00
|
|
|
{
|
2017-11-16 09:36:40 +08:00
|
|
|
void *p = memblock_virt_alloc_try_nid(PAGE_SIZE, PAGE_SIZE,
|
|
|
|
__pa(MAX_DMA_ADDRESS),
|
|
|
|
MEMBLOCK_ALLOC_ACCESSIBLE, node);
|
|
|
|
return __pa(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pte_t *__init kasan_pte_offset(pmd_t *pmd, unsigned long addr, int node,
|
|
|
|
bool early)
|
|
|
|
{
|
|
|
|
if (pmd_none(*pmd)) {
|
|
|
|
phys_addr_t pte_phys = early ? __pa_symbol(kasan_zero_pte)
|
|
|
|
: kasan_alloc_zeroed_page(node);
|
|
|
|
__pmd_populate(pmd, pte_phys, PMD_TYPE_TABLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return early ? pte_offset_kimg(pmd, addr)
|
|
|
|
: pte_offset_kernel(pmd, addr);
|
|
|
|
}
|
2015-10-12 23:52:58 +08:00
|
|
|
|
2017-11-16 09:36:40 +08:00
|
|
|
static pmd_t *__init kasan_pmd_offset(pud_t *pud, unsigned long addr, int node,
|
|
|
|
bool early)
|
|
|
|
{
|
|
|
|
if (pud_none(*pud)) {
|
|
|
|
phys_addr_t pmd_phys = early ? __pa_symbol(kasan_zero_pmd)
|
|
|
|
: kasan_alloc_zeroed_page(node);
|
|
|
|
__pud_populate(pud, pmd_phys, PMD_TYPE_TABLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return early ? pmd_offset_kimg(pud, addr) : pmd_offset(pud, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pud_t *__init kasan_pud_offset(pgd_t *pgd, unsigned long addr, int node,
|
|
|
|
bool early)
|
|
|
|
{
|
|
|
|
if (pgd_none(*pgd)) {
|
|
|
|
phys_addr_t pud_phys = early ? __pa_symbol(kasan_zero_pud)
|
|
|
|
: kasan_alloc_zeroed_page(node);
|
|
|
|
__pgd_populate(pgd, pud_phys, PMD_TYPE_TABLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return early ? pud_offset_kimg(pgd, addr) : pud_offset(pgd, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init kasan_pte_populate(pmd_t *pmd, unsigned long addr,
|
|
|
|
unsigned long end, int node, bool early)
|
|
|
|
{
|
|
|
|
unsigned long next;
|
|
|
|
pte_t *pte = kasan_pte_offset(pmd, addr, node, early);
|
2015-10-12 23:52:58 +08:00
|
|
|
|
|
|
|
do {
|
2017-11-16 09:36:40 +08:00
|
|
|
phys_addr_t page_phys = early ? __pa_symbol(kasan_zero_page)
|
|
|
|
: kasan_alloc_zeroed_page(node);
|
2015-10-12 23:52:58 +08:00
|
|
|
next = addr + PAGE_SIZE;
|
2017-11-16 09:36:40 +08:00
|
|
|
set_pte(pte, pfn_pte(__phys_to_pfn(page_phys), PAGE_KERNEL));
|
2015-10-12 23:52:58 +08:00
|
|
|
} while (pte++, addr = next, addr != end && pte_none(*pte));
|
|
|
|
}
|
|
|
|
|
2017-11-16 09:36:40 +08:00
|
|
|
static void __init kasan_pmd_populate(pud_t *pud, unsigned long addr,
|
|
|
|
unsigned long end, int node, bool early)
|
2015-10-12 23:52:58 +08:00
|
|
|
{
|
|
|
|
unsigned long next;
|
2017-11-16 09:36:40 +08:00
|
|
|
pmd_t *pmd = kasan_pmd_offset(pud, addr, node, early);
|
2015-10-12 23:52:58 +08:00
|
|
|
|
|
|
|
do {
|
|
|
|
next = pmd_addr_end(addr, end);
|
2017-11-16 09:36:40 +08:00
|
|
|
kasan_pte_populate(pmd, addr, next, node, early);
|
2015-10-12 23:52:58 +08:00
|
|
|
} while (pmd++, addr = next, addr != end && pmd_none(*pmd));
|
|
|
|
}
|
|
|
|
|
2017-11-16 09:36:40 +08:00
|
|
|
static void __init kasan_pud_populate(pgd_t *pgd, unsigned long addr,
|
|
|
|
unsigned long end, int node, bool early)
|
2015-10-12 23:52:58 +08:00
|
|
|
{
|
|
|
|
unsigned long next;
|
2017-11-16 09:36:40 +08:00
|
|
|
pud_t *pud = kasan_pud_offset(pgd, addr, node, early);
|
2015-10-12 23:52:58 +08:00
|
|
|
|
|
|
|
do {
|
|
|
|
next = pud_addr_end(addr, end);
|
2017-11-16 09:36:40 +08:00
|
|
|
kasan_pmd_populate(pud, addr, next, node, early);
|
2015-10-12 23:52:58 +08:00
|
|
|
} while (pud++, addr = next, addr != end && pud_none(*pud));
|
|
|
|
}
|
|
|
|
|
2017-11-16 09:36:40 +08:00
|
|
|
static void __init kasan_pgd_populate(unsigned long addr, unsigned long end,
|
|
|
|
int node, bool early)
|
2015-10-12 23:52:58 +08:00
|
|
|
{
|
|
|
|
unsigned long next;
|
|
|
|
pgd_t *pgd;
|
|
|
|
|
|
|
|
pgd = pgd_offset_k(addr);
|
|
|
|
do {
|
|
|
|
next = pgd_addr_end(addr, end);
|
2017-11-16 09:36:40 +08:00
|
|
|
kasan_pud_populate(pgd, addr, next, node, early);
|
2015-10-12 23:52:58 +08:00
|
|
|
} while (pgd++, addr = next, addr != end);
|
|
|
|
}
|
|
|
|
|
2017-11-16 09:36:40 +08:00
|
|
|
/* The early shadow maps everything to a single page of zeroes */
|
2015-10-13 21:01:06 +08:00
|
|
|
asmlinkage void __init kasan_early_init(void)
|
2015-10-12 23:52:58 +08:00
|
|
|
{
|
2018-02-07 07:36:44 +08:00
|
|
|
BUILD_BUG_ON(KASAN_SHADOW_OFFSET !=
|
|
|
|
KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT)));
|
2015-10-12 23:52:58 +08:00
|
|
|
BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_START, PGDIR_SIZE));
|
|
|
|
BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, PGDIR_SIZE));
|
2017-11-16 09:36:40 +08:00
|
|
|
kasan_pgd_populate(KASAN_SHADOW_START, KASAN_SHADOW_END, NUMA_NO_NODE,
|
|
|
|
true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up full kasan mappings, ensuring that the mapped pages are zeroed */
|
|
|
|
static void __init kasan_map_populate(unsigned long start, unsigned long end,
|
|
|
|
int node)
|
|
|
|
{
|
|
|
|
kasan_pgd_populate(start & PAGE_MASK, PAGE_ALIGN(end), node, false);
|
2015-10-12 23:52:58 +08:00
|
|
|
}
|
|
|
|
|
arm64: mm: create new fine-grained mappings at boot
At boot we may change the granularity of the tables mapping the kernel
(by splitting or making sections). This may happen when we create the
linear mapping (in __map_memblock), or at any point we try to apply
fine-grained permissions to the kernel (e.g. fixup_executable,
mark_rodata_ro, fixup_init).
Changing the active page tables in this manner may result in multiple
entries for the same address being allocated into TLBs, risking problems
such as TLB conflict aborts or issues derived from the amalgamation of
TLB entries. Generally, a break-before-make (BBM) approach is necessary
to avoid conflicts, but we cannot do this for the kernel tables as it
risks unmapping text or data being used to do so.
Instead, we can create a new set of tables from scratch in the safety of
the existing mappings, and subsequently migrate over to these using the
new cpu_replace_ttbr1 helper, which avoids the two sets of tables being
active simultaneously.
To avoid issues when we later modify permissions of the page tables
(e.g. in fixup_init), we must create the page tables at a granularity
such that later modification does not result in splitting of tables.
This patch applies this strategy, creating a new set of fine-grained
page tables from scratch, and safely migrating to them. The existing
fixmap and kasan shadow page tables are reused in the new fine-grained
tables.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Jeremy Linton <jeremy.linton@arm.com>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-25 19:45:12 +08:00
|
|
|
/*
|
|
|
|
* Copy the current shadow region into a new pgdir.
|
|
|
|
*/
|
|
|
|
void __init kasan_copy_shadow(pgd_t *pgdir)
|
|
|
|
{
|
|
|
|
pgd_t *pgd, *pgd_new, *pgd_end;
|
|
|
|
|
|
|
|
pgd = pgd_offset_k(KASAN_SHADOW_START);
|
|
|
|
pgd_end = pgd_offset_k(KASAN_SHADOW_END);
|
|
|
|
pgd_new = pgd_offset_raw(pgdir, KASAN_SHADOW_START);
|
|
|
|
do {
|
|
|
|
set_pgd(pgd_new, *pgd);
|
|
|
|
} while (pgd++, pgd_new++, pgd != pgd_end);
|
|
|
|
}
|
|
|
|
|
2015-10-12 23:52:58 +08:00
|
|
|
static void __init clear_pgds(unsigned long start,
|
|
|
|
unsigned long end)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Remove references to kasan page tables from
|
|
|
|
* swapper_pg_dir. pgd_clear() can't be used
|
|
|
|
* here because it's nop on 2,3-level pagetable setups
|
|
|
|
*/
|
|
|
|
for (; start < end; start += PGDIR_SIZE)
|
|
|
|
set_pgd(pgd_offset_k(start), __pgd(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init kasan_init(void)
|
|
|
|
{
|
2016-02-16 20:52:40 +08:00
|
|
|
u64 kimg_shadow_start, kimg_shadow_end;
|
arm64: add support for kernel ASLR
This adds support for KASLR is implemented, based on entropy provided by
the bootloader in the /chosen/kaslr-seed DT property. Depending on the size
of the address space (VA_BITS) and the page size, the entropy in the
virtual displacement is up to 13 bits (16k/2 levels) and up to 25 bits (all
4 levels), with the sidenote that displacements that result in the kernel
image straddling a 1GB/32MB/512MB alignment boundary (for 4KB/16KB/64KB
granule kernels, respectively) are not allowed, and will be rounded up to
an acceptable value.
If CONFIG_RANDOMIZE_MODULE_REGION_FULL is enabled, the module region is
randomized independently from the core kernel. This makes it less likely
that the location of core kernel data structures can be determined by an
adversary, but causes all function calls from modules into the core kernel
to be resolved via entries in the module PLTs.
If CONFIG_RANDOMIZE_MODULE_REGION_FULL is not enabled, the module region is
randomized by choosing a page aligned 128 MB region inside the interval
[_etext - 128 MB, _stext + 128 MB). This gives between 10 and 14 bits of
entropy (depending on page size), independently of the kernel randomization,
but still guarantees that modules are within the range of relative branch
and jump instructions (with the caveat that, since the module region is
shared with other uses of the vmalloc area, modules may need to be loaded
further away if the module region is exhausted)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-26 21:12:01 +08:00
|
|
|
u64 mod_shadow_start, mod_shadow_end;
|
2015-10-12 23:52:58 +08:00
|
|
|
struct memblock_region *reg;
|
2016-01-11 21:50:21 +08:00
|
|
|
int i;
|
2015-10-12 23:52:58 +08:00
|
|
|
|
2017-11-16 09:36:40 +08:00
|
|
|
kimg_shadow_start = (u64)kasan_mem_to_shadow(_text) & PAGE_MASK;
|
|
|
|
kimg_shadow_end = PAGE_ALIGN((u64)kasan_mem_to_shadow(_end));
|
2016-02-16 20:52:40 +08:00
|
|
|
|
arm64: add support for kernel ASLR
This adds support for KASLR is implemented, based on entropy provided by
the bootloader in the /chosen/kaslr-seed DT property. Depending on the size
of the address space (VA_BITS) and the page size, the entropy in the
virtual displacement is up to 13 bits (16k/2 levels) and up to 25 bits (all
4 levels), with the sidenote that displacements that result in the kernel
image straddling a 1GB/32MB/512MB alignment boundary (for 4KB/16KB/64KB
granule kernels, respectively) are not allowed, and will be rounded up to
an acceptable value.
If CONFIG_RANDOMIZE_MODULE_REGION_FULL is enabled, the module region is
randomized independently from the core kernel. This makes it less likely
that the location of core kernel data structures can be determined by an
adversary, but causes all function calls from modules into the core kernel
to be resolved via entries in the module PLTs.
If CONFIG_RANDOMIZE_MODULE_REGION_FULL is not enabled, the module region is
randomized by choosing a page aligned 128 MB region inside the interval
[_etext - 128 MB, _stext + 128 MB). This gives between 10 and 14 bits of
entropy (depending on page size), independently of the kernel randomization,
but still guarantees that modules are within the range of relative branch
and jump instructions (with the caveat that, since the module region is
shared with other uses of the vmalloc area, modules may need to be loaded
further away if the module region is exhausted)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-26 21:12:01 +08:00
|
|
|
mod_shadow_start = (u64)kasan_mem_to_shadow((void *)MODULES_VADDR);
|
|
|
|
mod_shadow_end = (u64)kasan_mem_to_shadow((void *)MODULES_END);
|
|
|
|
|
2015-10-12 23:52:58 +08:00
|
|
|
/*
|
|
|
|
* We are going to perform proper setup of shadow memory.
|
|
|
|
* At first we should unmap early shadow (clear_pgds() call bellow).
|
|
|
|
* However, instrumented code couldn't execute without shadow memory.
|
|
|
|
* tmp_pg_dir used to keep early shadow mapped until full shadow
|
|
|
|
* setup will be finished.
|
|
|
|
*/
|
|
|
|
memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir));
|
2016-01-25 19:45:02 +08:00
|
|
|
dsb(ishst);
|
2017-01-11 05:35:49 +08:00
|
|
|
cpu_replace_ttbr1(lm_alias(tmp_pg_dir));
|
2015-10-12 23:52:58 +08:00
|
|
|
|
|
|
|
clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
|
|
|
|
|
2017-11-16 09:36:40 +08:00
|
|
|
kasan_map_populate(kimg_shadow_start, kimg_shadow_end,
|
|
|
|
pfn_to_nid(virt_to_pfn(lm_alias(_text))));
|
2016-02-16 20:52:40 +08:00
|
|
|
|
2015-10-12 23:52:58 +08:00
|
|
|
kasan_populate_zero_shadow((void *)KASAN_SHADOW_START,
|
arm64: add support for kernel ASLR
This adds support for KASLR is implemented, based on entropy provided by
the bootloader in the /chosen/kaslr-seed DT property. Depending on the size
of the address space (VA_BITS) and the page size, the entropy in the
virtual displacement is up to 13 bits (16k/2 levels) and up to 25 bits (all
4 levels), with the sidenote that displacements that result in the kernel
image straddling a 1GB/32MB/512MB alignment boundary (for 4KB/16KB/64KB
granule kernels, respectively) are not allowed, and will be rounded up to
an acceptable value.
If CONFIG_RANDOMIZE_MODULE_REGION_FULL is enabled, the module region is
randomized independently from the core kernel. This makes it less likely
that the location of core kernel data structures can be determined by an
adversary, but causes all function calls from modules into the core kernel
to be resolved via entries in the module PLTs.
If CONFIG_RANDOMIZE_MODULE_REGION_FULL is not enabled, the module region is
randomized by choosing a page aligned 128 MB region inside the interval
[_etext - 128 MB, _stext + 128 MB). This gives between 10 and 14 bits of
entropy (depending on page size), independently of the kernel randomization,
but still guarantees that modules are within the range of relative branch
and jump instructions (with the caveat that, since the module region is
shared with other uses of the vmalloc area, modules may need to be loaded
further away if the module region is exhausted)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-26 21:12:01 +08:00
|
|
|
(void *)mod_shadow_start);
|
2016-02-16 20:52:40 +08:00
|
|
|
kasan_populate_zero_shadow((void *)kimg_shadow_end,
|
arm64: add support for kernel ASLR
This adds support for KASLR is implemented, based on entropy provided by
the bootloader in the /chosen/kaslr-seed DT property. Depending on the size
of the address space (VA_BITS) and the page size, the entropy in the
virtual displacement is up to 13 bits (16k/2 levels) and up to 25 bits (all
4 levels), with the sidenote that displacements that result in the kernel
image straddling a 1GB/32MB/512MB alignment boundary (for 4KB/16KB/64KB
granule kernels, respectively) are not allowed, and will be rounded up to
an acceptable value.
If CONFIG_RANDOMIZE_MODULE_REGION_FULL is enabled, the module region is
randomized independently from the core kernel. This makes it less likely
that the location of core kernel data structures can be determined by an
adversary, but causes all function calls from modules into the core kernel
to be resolved via entries in the module PLTs.
If CONFIG_RANDOMIZE_MODULE_REGION_FULL is not enabled, the module region is
randomized by choosing a page aligned 128 MB region inside the interval
[_etext - 128 MB, _stext + 128 MB). This gives between 10 and 14 bits of
entropy (depending on page size), independently of the kernel randomization,
but still guarantees that modules are within the range of relative branch
and jump instructions (with the caveat that, since the module region is
shared with other uses of the vmalloc area, modules may need to be loaded
further away if the module region is exhausted)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-26 21:12:01 +08:00
|
|
|
kasan_mem_to_shadow((void *)PAGE_OFFSET));
|
|
|
|
|
|
|
|
if (kimg_shadow_start > mod_shadow_end)
|
|
|
|
kasan_populate_zero_shadow((void *)mod_shadow_end,
|
|
|
|
(void *)kimg_shadow_start);
|
2015-10-12 23:52:58 +08:00
|
|
|
|
|
|
|
for_each_memblock(memory, reg) {
|
|
|
|
void *start = (void *)__phys_to_virt(reg->base);
|
|
|
|
void *end = (void *)__phys_to_virt(reg->base + reg->size);
|
|
|
|
|
|
|
|
if (start >= end)
|
|
|
|
break;
|
|
|
|
|
2017-11-16 09:36:40 +08:00
|
|
|
kasan_map_populate((unsigned long)kasan_mem_to_shadow(start),
|
|
|
|
(unsigned long)kasan_mem_to_shadow(end),
|
|
|
|
pfn_to_nid(virt_to_pfn(start)));
|
2015-10-12 23:52:58 +08:00
|
|
|
}
|
|
|
|
|
2016-01-11 21:50:21 +08:00
|
|
|
/*
|
|
|
|
* KAsan may reuse the contents of kasan_zero_pte directly, so we
|
|
|
|
* should make sure that it maps the zero page read-only.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < PTRS_PER_PTE; i++)
|
|
|
|
set_pte(&kasan_zero_pte[i],
|
2017-01-11 05:35:49 +08:00
|
|
|
pfn_pte(sym_to_pfn(kasan_zero_page), PAGE_KERNEL_RO));
|
2016-01-11 21:50:21 +08:00
|
|
|
|
2015-10-12 23:52:58 +08:00
|
|
|
memset(kasan_zero_page, 0, PAGE_SIZE);
|
2017-01-11 05:35:49 +08:00
|
|
|
cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
|
2015-10-12 23:52:58 +08:00
|
|
|
|
|
|
|
/* At this point kasan is fully initialized. Enable error messages */
|
|
|
|
init_task.kasan_depth = 0;
|
|
|
|
pr_info("KernelAddressSanitizer initialized\n");
|
|
|
|
}
|