summaryrefslogtreecommitdiff
path: root/sys/arch/amd64
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2022-11-04 16:49:32 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2022-11-04 16:49:32 +0000
commitd344992998333a2756a02a31041241701e341c58 (patch)
tree44be6fc97fded74506448f7aab7367397310c6c1 /sys/arch/amd64
parent73d53827cf25f86628e48155689805b594c254c7 (diff)
EFI firmware has bugs which may mean that calling EFI runtime services will
fault because it does memory accesses outside of the regions it told us to map. Try to mitigate this by installing a fault handler (using the pcb_onfault mechanism) and bail out using longjmp(9) if we encounter a page fault while executing an EFI runtime services call. Since some firmware bugs result in us executing code that isn't mapped, make kpageflttrap() handle execution faults as well as data faults. ok guenther@
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r--sys/arch/amd64/amd64/efi_machdep.c26
-rw-r--r--sys/arch/amd64/amd64/locore.S7
-rw-r--r--sys/arch/amd64/amd64/trap.c5
3 files changed, 29 insertions, 9 deletions
diff --git a/sys/arch/amd64/amd64/efi_machdep.c b/sys/arch/amd64/amd64/efi_machdep.c
index cb005543916..90716cb32e8 100644
--- a/sys/arch/amd64/amd64/efi_machdep.c
+++ b/sys/arch/amd64/amd64/efi_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: efi_machdep.c,v 1.2 2022/10/20 18:43:35 kettenis Exp $ */
+/* $OpenBSD: efi_machdep.c,v 1.3 2022/11/04 16:49:31 kettenis Exp $ */
/*
* Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
@@ -60,6 +60,11 @@ void efi_leave(struct efi_softc *);
int efi_gettime(struct todr_chip_handle *, struct timeval *);
int efi_settime(struct todr_chip_handle *, struct timeval *);
+label_t efi_jmpbuf;
+
+#define efi_enter_check(sc) (setjmp(&efi_jmpbuf) ? \
+ (efi_leave(sc), EFAULT) : (efi_enter(sc), 0))
+
int
efi_match(struct device *parent, void *match, void *aux)
{
@@ -134,7 +139,8 @@ efi_attach(struct device *parent, struct device *self, void *aux)
}
efi_leave(sc);
- efi_enter(sc);
+ if (efi_enter_check(sc))
+ return;
status = sc->sc_rs->GetTime(&time, NULL);
efi_leave(sc);
if (status != EFI_SUCCESS)
@@ -226,6 +232,12 @@ efi_map_runtime(struct efi_softc *sc)
}
void
+efi_fault(void)
+{
+ longjmp(&efi_jmpbuf);
+}
+
+void
efi_enter(struct efi_softc *sc)
{
sc->sc_psw = intr_disable();
@@ -233,11 +245,15 @@ efi_enter(struct efi_softc *sc)
lcr3(sc->sc_pm->pm_pdirpa | (pmap_use_pcid ? PCID_EFI : 0));
fpu_kernel_enter();
+
+ curpcb->pcb_onfault = (void *)efi_fault;
}
void
efi_leave(struct efi_softc *sc)
{
+ curpcb->pcb_onfault = NULL;
+
fpu_kernel_exit();
lcr3(sc->sc_cr3);
@@ -252,7 +268,8 @@ efi_gettime(struct todr_chip_handle *handle, struct timeval *tv)
EFI_TIME time;
EFI_STATUS status;
- efi_enter(sc);
+ if (efi_enter_check(sc))
+ return EFAULT;
status = sc->sc_rs->GetTime(&time, NULL);
efi_leave(sc);
if (status != EFI_SUCCESS)
@@ -296,7 +313,8 @@ efi_settime(struct todr_chip_handle *handle, struct timeval *tv)
time.TimeZone = 0;
time.Daylight = 0;
- efi_enter(sc);
+ if (efi_enter_check(sc))
+ return EFAULT;
status = sc->sc_rs->SetTime(&time);
efi_leave(sc);
if (status != EFI_SUCCESS)
diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S
index 2944720cc40..9be53956f53 100644
--- a/sys/arch/amd64/amd64/locore.S
+++ b/sys/arch/amd64/amd64/locore.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.S,v 1.128 2022/08/07 23:56:06 guenther Exp $ */
+/* $OpenBSD: locore.S,v 1.129 2022/11/04 16:49:31 kettenis Exp $ */
/* $NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $ */
/*
@@ -105,6 +105,7 @@
*/
#include "assym.h"
+#include "efi.h"
#include "lapic.h"
#include "ksyms.h"
#include "xen.h"
@@ -271,7 +272,7 @@ NENTRY(lgdt)
lretq
END(lgdt)
-#ifdef DDB
+#if defined(DDB) || NEFI > 0
ENTRY(setjmp)
RETGUARD_SETUP(setjmp, r11)
/*
@@ -313,7 +314,7 @@ ENTRY(longjmp)
ret
lfence
END(longjmp)
-#endif /* DDB */
+#endif /* DDB || NEFI > 0 */
/*****************************************************************************/
diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c
index 53707fbc99c..ffda7e2609b 100644
--- a/sys/arch/amd64/amd64/trap.c
+++ b/sys/arch/amd64/amd64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.91 2022/11/02 07:20:07 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.92 2022/11/04 16:49:31 kettenis Exp $ */
/* $NetBSD: trap.c,v 1.2 2003/05/04 23:51:56 fvdl Exp $ */
/*-
@@ -228,7 +228,8 @@ kpageflttrap(struct trapframe *frame, uint64_t cr2)
pcb = &p->p_addr->u_pcb;
/* This will only trigger if SMEP is enabled */
- if (cr2 <= VM_MAXUSER_ADDRESS && frame->tf_err & PGEX_I) {
+ if (pcb->pcb_onfault == NULL && cr2 <= VM_MAXUSER_ADDRESS &&
+ frame->tf_err & PGEX_I) {
KERNEL_LOCK();
fault("attempt to execute user address %p "
"in supervisor mode", (void *)cr2);