Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/aarch64 set kernel text/rodata readonly by default.
details: https://anonhg.NetBSD.org/src/rev/11fb69c140b2
branches: trunk
changeset: 365213:11fb69c140b2
user: ryo <ryo%NetBSD.org@localhost>
date: Mon Aug 06 12:50:56 2018 +0000
description:
set kernel text/rodata readonly by default.
add function db_write_text() for setting ddb breakpoint.
diffstat:
sys/arch/aarch64/aarch64/db_interface.c | 68 ++++++++++++++++++++++++-
sys/arch/aarch64/aarch64/locore.S | 6 +-
sys/arch/aarch64/aarch64/pmap.c | 88 ++++++++++++++++++++++++++++++++-
sys/arch/aarch64/include/pmap.h | 6 +-
4 files changed, 159 insertions(+), 9 deletions(-)
diffs (268 lines):
diff -r 1bb271dc1867 -r 11fb69c140b2 sys/arch/aarch64/aarch64/db_interface.c
--- a/sys/arch/aarch64/aarch64/db_interface.c Mon Aug 06 08:05:32 2018 +0000
+++ b/sys/arch/aarch64/aarch64/db_interface.c Mon Aug 06 12:50:56 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: db_interface.c,v 1.4 2018/06/03 20:18:10 christos Exp $ */
+/* $NetBSD: db_interface.c,v 1.5 2018/08/06 12:50:56 ryo Exp $ */
/*
* Copyright (c) 2017 Ryo Shimizu <ryo%nerv.org@localhost>
@@ -27,16 +27,18 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.4 2018/06/03 20:18:10 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.5 2018/08/06 12:50:56 ryo Exp $");
#include <sys/param.h>
#include <sys/types.h>
#include <uvm/uvm.h>
+#include <uvm/uvm_prot.h>
#include <aarch64/db_machdep.h>
#include <aarch64/machdep.h>
#include <aarch64/pmap.h>
+#include <aarch64/cpufunc.h>
#include <ddb/db_access.h>
#include <ddb/db_command.h>
@@ -88,12 +90,74 @@
}
}
+static void
+db_write_text(vaddr_t addr, size_t size, const char *data)
+{
+ pt_entry_t *ptep, pte;
+ size_t s;
+
+ /*
+ * consider page boundary, and
+ * it works even if kernel_text is mapped with L2 or L3.
+ */
+ if (atop(addr) != atop(addr + size - 1)) {
+ s = PAGE_SIZE - (addr & PAGE_MASK);
+ db_write_text(addr, s, data);
+ addr += s;
+ size -= s;
+ data += s;
+ }
+ while (size > 0) {
+ ptep = kvtopte(addr);
+ KASSERT(ptep != NULL);
+
+ /* save pte */
+ pte = *ptep;
+
+ /* change to writable */
+ pmap_kvattr(addr, VM_PROT_READ|VM_PROT_WRITE);
+ aarch64_tlbi_all();
+
+ s = size;
+ if (size > PAGE_SIZE)
+ s = PAGE_SIZE;
+
+ memcpy((void *)addr, data, s);
+ cpu_icache_sync_range(addr, size);
+
+ /* restore pte */
+ *ptep = pte;
+ aarch64_tlbi_all();
+
+ addr += s;
+ size -= s;
+ data += s;
+ }
+}
+
void
db_write_bytes(vaddr_t addr, size_t size, const char *data)
{
+ vaddr_t kernstart, datastart;
vaddr_t lastpage = -1;
char *dst;
+ /* if readonly page, require changing attribute to write */
+ extern char __kernel_text[], __data_start[];
+ kernstart = trunc_page((vaddr_t)__kernel_text);
+ datastart = trunc_page((vaddr_t)__data_start);
+ if (kernstart <= addr && addr < datastart) {
+ size_t s;
+
+ s = datastart - addr;
+ if (s > size)
+ s = size;
+ db_write_text(addr, s, data);
+ addr += s;
+ size -= s;
+ data += s;
+ }
+
/* XXX: need to check read only block/page */
for (dst = (char *)addr; size > 0;) {
uintptr_t tmp;
diff -r 1bb271dc1867 -r 11fb69c140b2 sys/arch/aarch64/aarch64/locore.S
--- a/sys/arch/aarch64/aarch64/locore.S Mon Aug 06 08:05:32 2018 +0000
+++ b/sys/arch/aarch64/aarch64/locore.S Mon Aug 06 12:50:56 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: locore.S,v 1.14 2018/08/03 16:32:55 ryo Exp $ */
+/* $NetBSD: locore.S,v 1.15 2018/08/06 12:50:56 ryo Exp $ */
/*
* Copyright (c) 2017 Ryo Shimizu <ryo%nerv.org@localhost>
@@ -35,7 +35,7 @@
#include <aarch64/hypervisor.h>
#include "assym.h"
-RCSID("$NetBSD: locore.S,v 1.14 2018/08/03 16:32:55 ryo Exp $")
+RCSID("$NetBSD: locore.S,v 1.15 2018/08/06 12:50:56 ryo Exp $")
/* #define DEBUG_LOCORE */
/* #define DEBUG_MMU */
@@ -650,7 +650,6 @@
lsr x4, x4, #L2_SHIFT
bl l2_setblocks
-#ifndef DDB
/* map READONLY from VM_MIN_KERNEL_ADDRESS to __data_start */
VERBOSE("Set kernel text/rodata READONLY\r\n")
ldr x3, =__data_start
@@ -684,7 +683,6 @@
9:
cmp x2, x3
blo 1b
-#endif
VERBOSE("Creating devmap tables\r\n")
/* devmap=PA table for L1 */
diff -r 1bb271dc1867 -r 11fb69c140b2 sys/arch/aarch64/aarch64/pmap.c
--- a/sys/arch/aarch64/aarch64/pmap.c Mon Aug 06 08:05:32 2018 +0000
+++ b/sys/arch/aarch64/aarch64/pmap.c Mon Aug 06 12:50:56 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.16 2018/07/31 07:00:48 skrll Exp $ */
+/* $NetBSD: pmap.c,v 1.17 2018/08/06 12:50:56 ryo Exp $ */
/*
* Copyright (c) 2017 Ryo Shimizu <ryo%nerv.org@localhost>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.16 2018/07/31 07:00:48 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.17 2018/08/06 12:50:56 ryo Exp $");
#include "opt_arm_debug.h"
#include "opt_ddb.h"
@@ -1990,6 +1990,90 @@
}
#ifdef DDB
+/* get pointer to kernel segment L2 or L3 table entry */
+pt_entry_t *
+kvtopte(vaddr_t va)
+{
+ pd_entry_t *l0, *l1, *l2, *l3;
+ pd_entry_t pde;
+ pt_entry_t *ptep;
+ unsigned int idx;
+
+ KASSERT(VM_MIN_KERNEL_ADDRESS <= va && va < VM_MAX_KERNEL_ADDRESS);
+
+ /*
+ * traverse L0 -> L1 -> L2 block (or -> L3 table)
+ */
+ l0 = pmap_kernel()->pm_l0table;
+
+ idx = l0pde_index(va);
+ pde = l0[idx];
+ if (!l0pde_valid(pde))
+ return NULL;
+
+ l1 = (void *)AARCH64_PA_TO_KVA(l0pde_pa(pde));
+ idx = l1pde_index(va);
+ pde = l1[idx];
+ if (!l1pde_valid(pde))
+ return NULL;
+
+ if (l1pde_is_block(pde))
+ return NULL;
+
+ l2 = (void *)AARCH64_PA_TO_KVA(l1pde_pa(pde));
+ idx = l2pde_index(va);
+ pde = l2[idx];
+ if (!l2pde_valid(pde))
+ return NULL;
+ if (l2pde_is_block(pde))
+ return &l2[idx]; /* kernel text/data use L2 blocks */
+
+ l3 = (void *)AARCH64_PA_TO_KVA(l2pde_pa(pde));
+ idx = l3pte_index(va);
+ ptep = &l3[idx]; /* or may use L3 page? */
+
+ return ptep;
+}
+
+/* change attribute of kernel segment */
+pt_entry_t
+pmap_kvattr(vaddr_t va, vm_prot_t prot)
+{
+ pt_entry_t *ptep, pte, opte;
+
+ KASSERT(VM_MIN_KERNEL_ADDRESS <= va && va < VM_MAX_KERNEL_ADDRESS);
+
+ ptep = kvtopte(va);
+ if (ptep == NULL)
+ panic("%s: %016lx is not mapped\n", __func__, va);
+
+ opte = pte = *ptep;
+
+ pte &= ~(LX_BLKPAG_AF|LX_BLKPAG_AP);
+ switch (prot & (VM_PROT_READ|VM_PROT_WRITE)) {
+ case 0:
+ break;
+ case VM_PROT_READ:
+ pte |= (LX_BLKPAG_AF|LX_BLKPAG_AP_RO);
+ break;
+ case VM_PROT_WRITE:
+ case VM_PROT_READ|VM_PROT_WRITE:
+ pte |= (LX_BLKPAG_AF|LX_BLKPAG_AP_RW);
+ break;
+ }
+
+ if ((prot & VM_PROT_EXECUTE) == 0) {
+ pte |= (LX_BLKPAG_UXN|LX_BLKPAG_PXN);
+ } else {
+ pte |= LX_BLKPAG_AF;
+ pte &= ~(LX_BLKPAG_UXN|LX_BLKPAG_PXN);
+ }
+
+ *ptep = pte;
+
+ return opte;
+}
+
static void
pmap_db_pte_print(pt_entry_t pte, int level, void (*pr)(const char *, ...))
{
diff -r 1bb271dc1867 -r 11fb69c140b2 sys/arch/aarch64/include/pmap.h
--- a/sys/arch/aarch64/include/pmap.h Mon Aug 06 08:05:32 2018 +0000
+++ b/sys/arch/aarch64/include/pmap.h Mon Aug 06 12:50:56 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.6 2018/07/27 07:04:04 ryo Exp $ */
+/* $NetBSD: pmap.h,v 1.7 2018/08/06 12:50:56 ryo Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -107,7 +107,11 @@
void pmap_bootstrap(vaddr_t, vaddr_t);
bool pmap_fault_fixup(struct pmap *, vaddr_t, vm_prot_t, bool user);
+
+/* for ddb */
void pmap_db_pteinfo(vaddr_t, void (*)(const char *, ...));
+pt_entry_t *kvtopte(vaddr_t);
+pt_entry_t pmap_kvattr(vaddr_t, vm_prot_t);
/* Hooks for the pool allocator */
paddr_t vtophys(vaddr_t);
Home |
Main Index |
Thread Index |
Old Index