diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2019-03-16 11:44:33 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2019-03-16 11:44:33 +0000 |
commit | fd8d844f7622a08d362994fde083170ec29088ae (patch) | |
tree | ddd401c39ecbacd9a9069413d165c0ba50e2afed | |
parent | 6f1fe3305a2be0a1395569b2ea5f56a93e491ae0 (diff) |
amd64 KPTI: add control from procctl(2).
Add the infrastructure to allow MD procctl(2) commands, and use it to
introduce amd64 PTI control and reporting. PTI mode cannot be
modified for existing pmap, the knob controls PTI of the new vmspace
created on exec.
Requested by: jhb
Reviewed by: jhb, markj (previous version)
Tested by: pho
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D19514
Notes
Notes:
svn path=/head/; revision=345228
-rw-r--r-- | sys/amd64/amd64/vm_machdep.c | 63 | ||||
-rw-r--r-- | sys/amd64/include/procctl.h | 6 | ||||
-rw-r--r-- | sys/arm/arm/vm_machdep.c | 7 | ||||
-rw-r--r-- | sys/arm/include/procctl.h | 4 | ||||
-rw-r--r-- | sys/arm64/arm64/vm_machdep.c | 8 | ||||
-rw-r--r-- | sys/arm64/include/procctl.h | 4 | ||||
-rw-r--r-- | sys/compat/freebsd32/freebsd32_misc.c | 4 | ||||
-rw-r--r-- | sys/i386/i386/vm_machdep.c | 8 | ||||
-rw-r--r-- | sys/i386/include/procctl.h | 6 | ||||
-rw-r--r-- | sys/kern/kern_procctl.c | 4 | ||||
-rw-r--r-- | sys/mips/include/procctl.h | 4 | ||||
-rw-r--r-- | sys/mips/mips/vm_machdep.c | 8 | ||||
-rw-r--r-- | sys/powerpc/include/procctl.h | 4 | ||||
-rw-r--r-- | sys/powerpc/powerpc/vm_machdep.c | 7 | ||||
-rw-r--r-- | sys/riscv/include/procctl.h | 4 | ||||
-rw-r--r-- | sys/riscv/riscv/vm_machdep.c | 8 | ||||
-rw-r--r-- | sys/sparc64/include/procctl.h | 4 | ||||
-rw-r--r-- | sys/sparc64/sparc64/vm_machdep.c | 8 | ||||
-rw-r--r-- | sys/sys/proc.h | 2 | ||||
-rw-r--r-- | sys/sys/procctl.h | 4 | ||||
-rw-r--r-- | sys/x86/include/procctl.h | 43 |
21 files changed, 210 insertions, 0 deletions
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index 0cf9eecc6d45..8508b6860297 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -59,13 +59,16 @@ __FBSDID("$FreeBSD$"); #include <sys/mbuf.h> #include <sys/mutex.h> #include <sys/pioctl.h> +#include <sys/priv.h> #include <sys/proc.h> +#include <sys/procctl.h> #include <sys/smp.h> #include <sys/sysctl.h> #include <sys/sysent.h> #include <sys/unistd.h> #include <sys/vnode.h> #include <sys/vmmeter.h> +#include <sys/wait.h> #include <machine/cpu.h> #include <machine/md_var.h> @@ -377,6 +380,66 @@ cpu_exec_vmspace_reuse(struct proc *p, vm_map_t map) (vm_map_pmap(map)->pm_ucr3 != PMAP_NO_CR3)); } +static void +cpu_procctl_kpti(struct proc *p, int com, 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; + } +} + +int +cpu_procctl(struct thread *td, int idtype, id_t id, int com, void *data) +{ + struct proc *p; + int error, val; + + switch (com) { + case PROC_KPTI_CTL: + case PROC_KPTI_STATUS: + if (idtype != P_PID) { + error = EINVAL; + break; + } + if (com == PROC_KPTI_CTL) { + /* sad but true and not a joke */ + error = priv_check(td, PRIV_IO); + if (error != 0) + break; + 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; + } + } + 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)); + } + break; + default: + error = EINVAL; + break; + } + return (error); +} + void cpu_set_syscall_retval(struct thread *td, int error) { diff --git a/sys/amd64/include/procctl.h b/sys/amd64/include/procctl.h new file mode 100644 index 000000000000..4a6bcc712046 --- /dev/null +++ b/sys/amd64/include/procctl.h @@ -0,0 +1,6 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ + +#include <x86/procctl.h> diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c index a2b457c2a253..3c75f43e5a1c 100644 --- a/sys/arm/arm/vm_machdep.c +++ b/sys/arm/arm/vm_machdep.c @@ -352,3 +352,10 @@ cpu_exec_vmspace_reuse(struct proc *p __unused, vm_map_t map __unused) return (true); } +int +cpu_procctl(struct thread *td __unused, int idtype __unused, id_t id __unused, + int com __unused, void *data __unused) +{ + + return (EINVAL); +} diff --git a/sys/arm/include/procctl.h b/sys/arm/include/procctl.h new file mode 100644 index 000000000000..5221cfcd7be1 --- /dev/null +++ b/sys/arm/include/procctl.h @@ -0,0 +1,4 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ diff --git a/sys/arm64/arm64/vm_machdep.c b/sys/arm64/arm64/vm_machdep.c index 083061b25846..af9a9c87519f 100644 --- a/sys/arm64/arm64/vm_machdep.c +++ b/sys/arm64/arm64/vm_machdep.c @@ -286,6 +286,14 @@ cpu_exec_vmspace_reuse(struct proc *p __unused, vm_map_t map __unused) return (true); } +int +cpu_procctl(struct thread *td __unused, int idtype __unused, id_t id __unused, + int com __unused, void *data __unused) +{ + + return (EINVAL); +} + void swi_vm(void *v) { diff --git a/sys/arm64/include/procctl.h b/sys/arm64/include/procctl.h new file mode 100644 index 000000000000..5221cfcd7be1 --- /dev/null +++ b/sys/arm64/include/procctl.h @@ -0,0 +1,4 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 64e3b046ecf0..81cb49a26867 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -3327,6 +3327,10 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap) } x32; int error, error1, flags, signum; + if (uap->com >= PROC_PROCCTL_MD_MIN) + return (cpu_procctl(td, uap->idtype, PAIR32TO64(id_t, uap->id), + uap->com, PTRIN(uap->data))); + switch (uap->com) { case PROC_ASLR_CTL: case PROC_SPROTECT: diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c index acc5a439ab0c..ef4772cd4ee5 100644 --- a/sys/i386/i386/vm_machdep.c +++ b/sys/i386/i386/vm_machdep.c @@ -389,6 +389,14 @@ cpu_exec_vmspace_reuse(struct proc *p __unused, vm_map_t map __unused) return (true); } +int +cpu_procctl(struct thread *td __unused, int idtype __unused, id_t id __unused, + int com __unused, void *data __unused) +{ + + return (EINVAL); +} + void cpu_set_syscall_retval(struct thread *td, int error) { diff --git a/sys/i386/include/procctl.h b/sys/i386/include/procctl.h new file mode 100644 index 000000000000..4a6bcc712046 --- /dev/null +++ b/sys/i386/include/procctl.h @@ -0,0 +1,6 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ + +#include <x86/procctl.h> diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c index b02094322996..4e9f200aea79 100644 --- a/sys/kern/kern_procctl.c +++ b/sys/kern/kern_procctl.c @@ -494,6 +494,10 @@ sys_procctl(struct thread *td, struct procctl_args *uap) } x; int error, error1, flags, signum; + if (uap->com >= PROC_PROCCTL_MD_MIN) + return (cpu_procctl(td, uap->idtype, uap->id, + uap->com, uap->data)); + switch (uap->com) { case PROC_ASLR_CTL: case PROC_SPROTECT: diff --git a/sys/mips/include/procctl.h b/sys/mips/include/procctl.h new file mode 100644 index 000000000000..5221cfcd7be1 --- /dev/null +++ b/sys/mips/include/procctl.h @@ -0,0 +1,4 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ diff --git a/sys/mips/mips/vm_machdep.c b/sys/mips/mips/vm_machdep.c index a224f81c4a68..e686ffcbcebe 100644 --- a/sys/mips/mips/vm_machdep.c +++ b/sys/mips/mips/vm_machdep.c @@ -460,6 +460,14 @@ cpu_exec_vmspace_reuse(struct proc *p __unused, vm_map_t map __unused) return (true); } +int +cpu_procctl(struct thread *td __unused, int idtype __unused, id_t id __unused, + int com __unused, void *data __unused) +{ + + return (EINVAL); +} + /* * Software interrupt handler for queued VM system processing. */ diff --git a/sys/powerpc/include/procctl.h b/sys/powerpc/include/procctl.h new file mode 100644 index 000000000000..5221cfcd7be1 --- /dev/null +++ b/sys/powerpc/include/procctl.h @@ -0,0 +1,4 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ diff --git a/sys/powerpc/powerpc/vm_machdep.c b/sys/powerpc/powerpc/vm_machdep.c index 7649711cef0a..4aab71ec036c 100644 --- a/sys/powerpc/powerpc/vm_machdep.c +++ b/sys/powerpc/powerpc/vm_machdep.c @@ -256,3 +256,10 @@ cpu_exec_vmspace_reuse(struct proc *p __unused, vm_map_t map __unused) return (true); } +int +cpu_procctl(struct thread *td __unused, int idtype __unused, id_t id __unused, + int com __unused, void *data __unused) +{ + + return (EINVAL); +} diff --git a/sys/riscv/include/procctl.h b/sys/riscv/include/procctl.h new file mode 100644 index 000000000000..5221cfcd7be1 --- /dev/null +++ b/sys/riscv/include/procctl.h @@ -0,0 +1,4 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ diff --git a/sys/riscv/riscv/vm_machdep.c b/sys/riscv/riscv/vm_machdep.c index 39119a07f581..7bcd13abc47d 100644 --- a/sys/riscv/riscv/vm_machdep.c +++ b/sys/riscv/riscv/vm_machdep.c @@ -271,6 +271,14 @@ cpu_exec_vmspace_reuse(struct proc *p __unused, vm_map_t map __unused) return (true); } +int +cpu_procctl(struct thread *td __unused, int idtype __unused, id_t id __unused, + int com __unused, void *data __unused) +{ + + return (EINVAL); +} + void swi_vm(void *v) { diff --git a/sys/sparc64/include/procctl.h b/sys/sparc64/include/procctl.h new file mode 100644 index 000000000000..5221cfcd7be1 --- /dev/null +++ b/sys/sparc64/include/procctl.h @@ -0,0 +1,4 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ diff --git a/sys/sparc64/sparc64/vm_machdep.c b/sys/sparc64/sparc64/vm_machdep.c index a4a316e0bc86..c56555a0120b 100644 --- a/sys/sparc64/sparc64/vm_machdep.c +++ b/sys/sparc64/sparc64/vm_machdep.c @@ -381,6 +381,14 @@ cpu_exec_vmspace_reuse(struct proc *p __unused, vm_map_t map __unused) } int +cpu_procctl(struct thread *td __unused, int idtype __unused, id_t id __unused, + int com __unused, void *data __unused) +{ + + return (EINVAL); +} + +int is_physical_memory(vm_paddr_t addr) { struct ofw_mem_region *mr; diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 2d71a72e4d2c..53d5cc88d58f 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1097,6 +1097,8 @@ bool cpu_exec_vmspace_reuse(struct proc *p, struct vm_map *map); int cpu_fetch_syscall_args(struct thread *td); void cpu_fork(struct thread *, struct proc *, struct thread *, int); void cpu_fork_kthread_handler(struct thread *, void (*)(void *), void *); +int cpu_procctl(struct thread *td, int idtype, id_t id, int com, + void *data); void cpu_set_syscall_retval(struct thread *, int); void cpu_set_upcall(struct thread *, void (*)(void *), void *, stack_t *); diff --git a/sys/sys/procctl.h b/sys/sys/procctl.h index 1f519454e963..80679f5eb972 100644 --- a/sys/sys/procctl.h +++ b/sys/sys/procctl.h @@ -41,6 +41,10 @@ #include <sys/wait.h> #endif +/* MD PROCCTL verbs start at 0x10000000 */ +#define PROC_PROCCTL_MD_MIN 0x10000000 +#include <machine/procctl.h> + #define PROC_SPROTECT 1 /* set protected state */ #define PROC_REAP_ACQUIRE 2 /* reaping enable */ #define PROC_REAP_RELEASE 3 /* reaping disable */ diff --git a/sys/x86/include/procctl.h b/sys/x86/include/procctl.h new file mode 100644 index 000000000000..8cb792189020 --- /dev/null +++ b/sys/x86/include/procctl.h @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 The FreeBSD Foundation + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _X86_PROCCTL_H +#define _X86_PROCCTL_H + +#define PROC_KPTI_CTL (PROC_PROCCTL_MD_MIN + 0) +#define PROC_KPTI_STATUS (PROC_PROCCTL_MD_MIN + 1) + +#define PROC_KPTI_CTL_ENABLE_ON_EXEC 1 +#define PROC_KPTI_CTL_DISABLE_ON_EXEC 2 +#define PROC_KPTI_STATUS_ACTIVE 0x80000000 + +#endif |