diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2011-04-23 22:16:14 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2011-04-23 22:16:14 +0000 |
commit | 12b08c32b732e1fe5f7d0ebc8f15d7251c6eefe6 (patch) | |
tree | a6ac5cb784f8e32a345a1a11b9532d07960543de /sys/arch/i386 | |
parent | ec1cac950c8b22402998c1cc07f8cdea0c433f0d (diff) |
Don't leave the kernel code/rodata writeable for DDB. Make ddb enable
writes in the pte momentarily. Modified the code stolen from amd64.
ok miod
Diffstat (limited to 'sys/arch/i386')
-rw-r--r-- | sys/arch/i386/i386/db_memrw.c | 102 | ||||
-rw-r--r-- | sys/arch/i386/i386/locore.s | 6 |
2 files changed, 77 insertions, 31 deletions
diff --git a/sys/arch/i386/i386/db_memrw.c b/sys/arch/i386/i386/db_memrw.c index 6ff8a7eb835..49102f2305f 100644 --- a/sys/arch/i386/i386/db_memrw.c +++ b/sys/arch/i386/i386/db_memrw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_memrw.c,v 1.12 2007/02/20 21:15:01 tom Exp $ */ +/* $OpenBSD: db_memrw.c,v 1.13 2011/04/23 22:16:13 deraadt Exp $ */ /* $NetBSD: db_memrw.c,v 1.6 1999/04/12 20:38:19 pk Exp $ */ /* @@ -58,45 +58,95 @@ db_read_bytes(vaddr_t addr, size_t size, char *data) } /* + * Write bytes somewhere in the kernel text. Make the text + * pages writable temporarily. + */ +static void +db_write_text(vaddr_t addr, size_t size, char *data) +{ + pt_entry_t *pte, oldpte, tmppte; + vaddr_t pgva; + size_t limit; + char *dst; + + if (size == 0) + return; + + dst = (char *)addr; + + do { + /* + * Get the PTE for the page. + */ + pte = kvtopte(addr); + oldpte = *pte; + + if ((oldpte & PG_V) == 0) { + printf(" address %p not a valid page\n", dst); + return; + } + + /* + * Get the VA for the page. + */ + if (oldpte & PG_PS) + pgva = (vaddr_t)dst & PG_LGFRAME; + else + pgva = trunc_page((vaddr_t)dst); + + /* + * Compute number of bytes that can be written + * with this mapping and subtract it from the + * total size. + */ +#ifdef NBPD_L2 + if (oldpte & PG_PS) + limit = NBPD_L2 - ((vaddr_t)dst & (NBPD_L2 - 1)); + else +#endif + limit = PAGE_SIZE - ((vaddr_t)dst & PGOFSET); + if (limit > size) + limit = size; + size -= limit; + + tmppte = (oldpte & ~PG_KR) | PG_KW; + *pte = tmppte; + pmap_update_pg(pgva); + + /* + * Page is now writable. Do as much access as we + * can in this page. + */ + for (; limit > 0; limit--) + *dst++ = *data++; + + /* + * Restore the old PTE. + */ + *pte = oldpte; + + pmap_update_pg(pgva); + + } while (size != 0); +} + +/* * Write bytes to kernel address space for debugger. */ void db_write_bytes(vaddr_t addr, size_t size, char *data) { char *dst; - - pt_entry_t *ptep0 = 0; - pt_entry_t oldmap0 = { 0 }; - vaddr_t addr1; - pt_entry_t *ptep1 = 0; - pt_entry_t oldmap1 = { 0 }; extern char etext; if (addr >= VM_MIN_KERNEL_ADDRESS && addr < (vaddr_t)&etext) { - ptep0 = kvtopte(addr); - oldmap0 = *ptep0; - *(int *)ptep0 |= /* INTEL_PTE_WRITE */ PG_RW; - - addr1 = trunc_page(addr + size - 1); - if (trunc_page(addr) != addr1) { - /* data crosses a page boundary */ - ptep1 = kvtopte(addr1); - oldmap1 = *ptep1; - *(int *)ptep1 |= /* INTEL_PTE_WRITE */ PG_RW; - } - tlbflush(); + db_write_text(addr, size, data); + return; } dst = (char *)addr; while (size-- > 0) *dst++ = *data++; - - if (ptep0) { - *ptep0 = oldmap0; - if (ptep1) - *ptep1 = oldmap1; - tlbflush(); - } } diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s index 25b4840189f..4282d5d77b8 100644 --- a/sys/arch/i386/i386/locore.s +++ b/sys/arch/i386/i386/locore.s @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.s,v 1.132 2011/04/05 12:50:15 guenther Exp $ */ +/* $OpenBSD: locore.s,v 1.133 2011/04/23 22:16:13 deraadt Exp $ */ /* $NetBSD: locore.s,v 1.145 1996/05/03 19:41:19 christos Exp $ */ /*- @@ -528,11 +528,7 @@ try586: /* Use the `cpuid' instruction. */ movl %edx,%ecx subl %eax,%ecx shrl $PGSHIFT,%ecx -#ifdef DDB - orl $(PG_V|PG_KW),%eax -#else orl $(PG_V|PG_KR),%eax -#endif fillkpt /* Map the data, BSS, and bootstrap tables read-write. */ |