diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2016-09-05 22:27:24 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2016-09-05 22:27:24 +0000 |
commit | 7d93ec35593ed1082d1bcc402111e732d6e2b785 (patch) | |
tree | fd3e2ad2ef6da03d2b01f19f057154c41ec29aa4 /sys | |
parent | bc6bb33a38bb3aa1c4ad2de1a4f6f7d9154c28dc (diff) |
Fix hibernation - make stack protector writable during resume
Committing for guenther@ because he is on United and apparently
they break ssh (as well as guitars)
ok deraadt@ in the car from cambridge
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/subr_hibernate.c | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c index 7d360522314..a4f1eafa71a 100644 --- a/sys/kern/subr_hibernate.c +++ b/sys/kern/subr_hibernate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_hibernate.c,v 1.117 2016/09/01 13:12:59 akfaew Exp $ */ +/* $OpenBSD: subr_hibernate.c,v 1.118 2016/09/05 22:27:23 beck Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl> @@ -1035,6 +1035,37 @@ hibernate_preserve_entropy(union hibernate_info *hib) km_free(entropy, PAGE_SIZE, &kv_any, &kp_none); } +#ifndef NO_PROPOLICE +vaddr_t +hibernate_unprotect_ssp(void) +{ + struct kmem_dyn_mode kd_avoidalias; + vaddr_t va = trunc_page((vaddr_t)&__guard_local); + paddr_t pa; + + pmap_extract(pmap_kernel(), va, &pa); + + memset(&kd_avoidalias, 0, sizeof kd_avoidalias); + kd_avoidalias.kd_prefer = pa; + kd_avoidalias.kd_waitok = 1; + va = (vaddr_t)km_alloc(PAGE_SIZE, &kv_any, &kp_none, &kd_avoidalias); + if (!va) + panic("hibernate_unprotect_ssp"); + + pmap_kenter_pa(va, pa, PROT_READ | PROT_WRITE); + pmap_update(pmap_kernel()); + + return va; +} + +void +hibernate_reprotect_ssp(vaddr_t va) +{ + pmap_kremove(va, PAGE_SIZE); + km_free((void *)va, PAGE_SIZE, &kv_any, &kp_none); +} +#endif /* NO_PROPOLICE */ + /* * Reads the signature block from swap, checks against the current machine's * information. If the information matches, perform a resume by reading the @@ -1047,6 +1078,11 @@ hibernate_resume(void) { union hibernate_info hib; int s; +#ifndef NO_PROPOLICE + vsize_t off = (vaddr_t)&__guard_local - + trunc_page((vaddr_t)&__guard_local); + vaddr_t guard_va; +#endif /* Get current running machine's hibernate info */ memset(&hib, 0, sizeof(hib)); @@ -1111,6 +1147,10 @@ hibernate_resume(void) if (config_suspend_all(DVACT_QUIESCE) != 0) goto fail; +#ifndef NO_PROPOLICE + guard_va = hibernate_unprotect_ssp(); +#endif /* NO_PROPOLICE */ + (void) splhigh(); hibernate_disable_intr_machdep(); cold = 1; @@ -1119,6 +1159,9 @@ hibernate_resume(void) if (config_suspend_all(DVACT_SUSPEND) != 0) { cold = 0; hibernate_enable_intr_machdep(); +#ifndef NO_PROPOLICE + hibernate_reprotect_ssp(guard_va); +#endif /* ! NO_PROPOLICE */ goto fail; } @@ -1132,7 +1175,8 @@ hibernate_resume(void) #ifndef NO_PROPOLICE /* Start using suspended kernel's propolice guard */ - __guard_local = disk_hib.guard; + *(long *)(guard_va + off) = disk_hib.guard; + hibernate_reprotect_ssp(guard_va); #endif /* ! NO_PROPOLICE */ /* Unpack and resume */ |