From 25f2da2e6475271a2ed5e8d0a9fa03431ec41a82 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sun, 23 Aug 2020 20:32:13 +0000 Subject: [PATCH] Add amd64 procctl(2) ops to manage forced LA48/LA57 VA after exec. Tested by: pho (LA48 hardware) Sponsored by: The FreeBSD Foundation Differential revision: https://reviews.freebsd.org/D25273 --- sys/amd64/amd64/vm_machdep.c | 115 ++++++++++++++++++++++++++++------- sys/x86/include/procctl.h | 11 +++- 2 files changed, 103 insertions(+), 23 deletions(-) diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index 37a71c9d58b..b4513f1b751 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -377,21 +377,67 @@ cpu_exec_vmspace_reuse(struct proc *p, vm_map_t map) } static void -cpu_procctl_kpti(struct proc *p, int com, int *val) +cpu_procctl_kpti_ctl(struct proc *p, int val) { - if (com == PROC_KPTI_CTL) { - if (pti && *val == PROC_KPTI_CTL_ENABLE_ON_EXEC) - p->p_md.md_flags |= P_MD_KPTI; - if (*val == PROC_KPTI_CTL_DISABLE_ON_EXEC) - p->p_md.md_flags &= ~P_MD_KPTI; - } else /* PROC_KPTI_STATUS */ { - *val = (p->p_md.md_flags & P_MD_KPTI) != 0 ? - PROC_KPTI_CTL_ENABLE_ON_EXEC: - PROC_KPTI_CTL_DISABLE_ON_EXEC; - if (vmspace_pmap(p->p_vmspace)->pm_ucr3 != PMAP_NO_CR3) - *val |= PROC_KPTI_STATUS_ACTIVE; + if (pti && val == PROC_KPTI_CTL_ENABLE_ON_EXEC) + p->p_md.md_flags |= P_MD_KPTI; + if (val == PROC_KPTI_CTL_DISABLE_ON_EXEC) + p->p_md.md_flags &= ~P_MD_KPTI; +} + +static void +cpu_procctl_kpti_status(struct proc *p, int *val) +{ + *val = (p->p_md.md_flags & P_MD_KPTI) != 0 ? + PROC_KPTI_CTL_ENABLE_ON_EXEC: + PROC_KPTI_CTL_DISABLE_ON_EXEC; + if (vmspace_pmap(p->p_vmspace)->pm_ucr3 != PMAP_NO_CR3) + *val |= PROC_KPTI_STATUS_ACTIVE; +} + +static int +cpu_procctl_la_ctl(struct proc *p, int val) +{ + int error; + + error = 0; + switch (val) { + case PROC_LA_CTL_LA48_ON_EXEC: + p->p_md.md_flags |= P_MD_LA48; + p->p_md.md_flags &= ~P_MD_LA57; + break; + case PROC_LA_CTL_LA57_ON_EXEC: + if (la57) { + p->p_md.md_flags &= ~P_MD_LA48; + p->p_md.md_flags |= P_MD_LA57; + } else { + error = ENOTSUP; + } + break; + case PROC_LA_CTL_DEFAULT_ON_EXEC: + p->p_md.md_flags &= ~(P_MD_LA48 | P_MD_LA57); + break; } + return (error); +} + +static void +cpu_procctl_la_status(struct proc *p, int *val) +{ + int res; + + if ((p->p_md.md_flags & P_MD_LA48) != 0) + res = PROC_LA_CTL_LA48_ON_EXEC; + else if ((p->p_md.md_flags & P_MD_LA57) != 0) + res = PROC_LA_CTL_LA57_ON_EXEC; + else + res = PROC_LA_CTL_DEFAULT_ON_EXEC; + if (p->p_sysent->sv_maxuser == VM_MAXUSER_ADDRESS_LA48) + res |= PROC_LA_STATUS_LA48; + else + res |= PROC_LA_STATUS_LA57; + *val = res; } int @@ -403,6 +449,8 @@ cpu_procctl(struct thread *td, int idtype, id_t id, int com, void *data) switch (com) { case PROC_KPTI_CTL: case PROC_KPTI_STATUS: + case PROC_LA_CTL: + case PROC_LA_STATUS: if (idtype != P_PID) { error = EINVAL; break; @@ -412,22 +460,45 @@ cpu_procctl(struct thread *td, int idtype, id_t id, int com, void *data) error = priv_check(td, PRIV_IO); if (error != 0) break; + } + if (com == PROC_KPTI_CTL || com == PROC_LA_CTL) { error = copyin(data, &val, sizeof(val)); if (error != 0) break; - if (val != PROC_KPTI_CTL_ENABLE_ON_EXEC && - val != PROC_KPTI_CTL_DISABLE_ON_EXEC) { - error = EINVAL; - break; - } + } + if (com == PROC_KPTI_CTL && + val != PROC_KPTI_CTL_ENABLE_ON_EXEC && + val != PROC_KPTI_CTL_DISABLE_ON_EXEC) { + error = EINVAL; + break; + } + if (com == PROC_LA_CTL && + val != PROC_LA_CTL_LA48_ON_EXEC && + val != PROC_LA_CTL_LA57_ON_EXEC && + val != PROC_LA_CTL_DEFAULT_ON_EXEC) { + error = EINVAL; + break; } error = pget(id, PGET_CANSEE | PGET_NOTWEXIT | PGET_NOTID, &p); - if (error == 0) { - cpu_procctl_kpti(p, com, &val); - PROC_UNLOCK(p); - if (com == PROC_KPTI_STATUS) - error = copyout(&val, data, sizeof(val)); + if (error != 0) + break; + switch (com) { + case PROC_KPTI_CTL: + cpu_procctl_kpti_ctl(p, val); + break; + case PROC_KPTI_STATUS: + cpu_procctl_kpti_status(p, &val); + break; + case PROC_LA_CTL: + error = cpu_procctl_la_ctl(p, val); + break; + case PROC_LA_STATUS: + cpu_procctl_la_status(p, &val); + break; } + PROC_UNLOCK(p); + if (com == PROC_KPTI_STATUS || com == PROC_LA_STATUS) + error = copyout(&val, data, sizeof(val)); break; default: error = EINVAL; diff --git a/sys/x86/include/procctl.h b/sys/x86/include/procctl.h index 8cb79218902..eb9a1e2c6ad 100644 --- a/sys/x86/include/procctl.h +++ b/sys/x86/include/procctl.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2019 The FreeBSD Foundation + * Copyright (c) 2019,2020 The FreeBSD Foundation * * Portions of this software were developed by Konstantin Belousov * under sponsorship from the FreeBSD Foundation. @@ -35,9 +35,18 @@ #define PROC_KPTI_CTL (PROC_PROCCTL_MD_MIN + 0) #define PROC_KPTI_STATUS (PROC_PROCCTL_MD_MIN + 1) +#define PROC_LA_CTL (PROC_PROCCTL_MD_MIN + 2) +#define PROC_LA_STATUS (PROC_PROCCTL_MD_MIN + 3) #define PROC_KPTI_CTL_ENABLE_ON_EXEC 1 #define PROC_KPTI_CTL_DISABLE_ON_EXEC 2 #define PROC_KPTI_STATUS_ACTIVE 0x80000000 +#define PROC_LA_CTL_LA48_ON_EXEC 1 +#define PROC_LA_CTL_LA57_ON_EXEC 2 +#define PROC_LA_CTL_DEFAULT_ON_EXEC 3 + +#define PROC_LA_STATUS_LA48 0x01000000 +#define PROC_LA_STATUS_LA57 0x02000000 + #endif