diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2018-03-20 17:43:50 +0000 |
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2018-03-20 17:43:50 +0000 |
| commit | 2337dc6430a1a169987955b6ee27bebf950f5491 (patch) | |
| tree | 96658dc8a55b86791af0b22eee5f98ca9cdd3179 /sys | |
| parent | fd40ecf3d4d2be5ca9c25c66fe572002214c65dd (diff) | |
Provide KPI for handling of rw/ro kernel text.
This is a pure syntax patch to create an interface to enable and later
restore write access to the kernel text and other read-only mapped
regions. It is in line with e.g. vm_fault_disable_pagefaults() by
allowing the nesting.
Discussed with: Peter Lei <peter.lei@ieee.org>
Reviewed by: jtl
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D14768
Notes
svn path=/head/; revision=331252
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/amd64/amd64/db_interface.c | 9 | ||||
| -rw-r--r-- | sys/amd64/amd64/gdb_machdep.c | 8 | ||||
| -rw-r--r-- | sys/amd64/amd64/machdep.c | 25 | ||||
| -rw-r--r-- | sys/amd64/include/md_var.h | 2 |
4 files changed, 35 insertions, 9 deletions
diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c index 9dfd44cf82c9..1ecec02835ce 100644 --- a/sys/amd64/amd64/db_interface.c +++ b/sys/amd64/amd64/db_interface.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/pcpu.h> #include <machine/cpufunc.h> +#include <machine/md_var.h> #include <machine/specialreg.h> #include <ddb/ddb.h> @@ -75,19 +76,19 @@ db_write_bytes(vm_offset_t addr, size_t size, char *data) jmp_buf jb; void *prev_jb; char *dst; - u_long cr0save; + bool old_wp; int ret; - cr0save = rcr0(); + old_wp = false; prev_jb = kdb_jmpbuf(jb); ret = setjmp(jb); if (ret == 0) { - load_cr0(cr0save & ~CR0_WP); + old_wp = disable_wp(); dst = (char *)addr; while (size-- > 0) *dst++ = *data++; } - load_cr0(cr0save); + restore_wp(old_wp); (void)kdb_jmpbuf(prev_jb); return (ret); } diff --git a/sys/amd64/amd64/gdb_machdep.c b/sys/amd64/amd64/gdb_machdep.c index 68eb6002593f..f7ca3c07ea36 100644 --- a/sys/amd64/amd64/gdb_machdep.c +++ b/sys/amd64/amd64/gdb_machdep.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <machine/cpufunc.h> #include <machine/frame.h> #include <machine/gdb_machdep.h> +#include <machine/md_var.h> #include <machine/pcb.h> #include <machine/psl.h> #include <machine/reg.h> @@ -127,17 +128,14 @@ gdb_cpu_signal(int type, int code) void * gdb_begin_write(void) { - u_long cr0save; - cr0save = rcr0(); - load_cr0(cr0save & ~CR0_WP); - return ((void *)cr0save); + return (disable_wp() ? &gdb_begin_write : NULL); } void gdb_end_write(void *arg) { - load_cr0((u_long)arg); + restore_wp(arg != NULL); } diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index e340c6cd14dc..fcc45eca57de 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -2597,6 +2597,31 @@ clear_pcb_flags(struct pcb *pcb, const u_int flags) : "cc", "memory"); } +/* + * Enable and restore kernel text write permissions. + * Callers must ensure that disable_wp()/restore_wp() are executed + * without rescheduling on the same core. + */ +bool +disable_wp(void) +{ + u_int cr0; + + cr0 = rcr0(); + if ((cr0 & CR0_WP) == 0) + return (false); + load_cr0(cr0 & ~CR0_WP); + return (true); +} + +void +restore_wp(bool old_wp) +{ + + if (old_wp) + load_cr0(rcr0() | CR0_WP); +} + #ifdef KDB /* diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h index 63dabaf40470..abcc273b6c60 100644 --- a/sys/amd64/include/md_var.h +++ b/sys/amd64/include/md_var.h @@ -53,6 +53,8 @@ void amd64_conf_fast_syscall(void); void amd64_db_resume_dbreg(void); void amd64_lower_shared_page(struct sysentvec *); void amd64_syscall(struct thread *td, int traced); +bool disable_wp(void); +void restore_wp(bool old_wp); void doreti_iret(void) __asm(__STRING(doreti_iret)); void doreti_iret_fault(void) __asm(__STRING(doreti_iret_fault)); void ld_ds(void) __asm(__STRING(ld_ds)); |
