diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2017-09-19 17:57:04 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2017-09-19 17:57:04 +0000 |
commit | 3cabd93e267a63a27d6098106dcb747ee8bd673c (patch) | |
tree | 21fe983a1b971ec64aeb7e245a16eb438097f561 /sys/i386 | |
parent | 9770475ce768cd06e9e88ea23917971f152ba448 (diff) | |
download | src-3cabd93e267a63a27d6098106dcb747ee8bd673c.tar.gz src-3cabd93e267a63a27d6098106dcb747ee8bd673c.zip |
Do not do torn writes to active LDTs.
Care must be taken when updating the active LDT, since parallel
threads might try to load a segment descriptor which is currently
updated. Since the results are undefined, this cannot be ignored by
claiming to be an application race.
Reviewed by: jhb
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Differential revision: https://reviews.freebsd.org/D12413
Notes
Notes:
svn path=/head/; revision=323772
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/i386/sys_machdep.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c index 3afed49c7b3b..4236d11a58d6 100644 --- a/sys/i386/i386/sys_machdep.c +++ b/sys/i386/i386/sys_machdep.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_map.h> #include <vm/vm_extern.h> +#include <machine/atomic.h> #include <machine/cpu.h> #include <machine/pcb.h> #include <machine/pcb_ext.h> @@ -546,7 +547,7 @@ i386_set_ldt(td, uap, descs) struct i386_ldt_args *uap; union descriptor *descs; { - int error = 0, i; + int error, i; int largest_ld; struct mdproc *mdp = &td->td_proc->p_md; struct proc_ldt *pldt; @@ -556,6 +557,7 @@ i386_set_ldt(td, uap, descs) printf("i386_set_ldt: start=%d num=%d descs=%p\n", uap->start, uap->num, (void *)uap->descs); #endif + error = 0; if (descs == NULL) { /* Free descriptors */ @@ -578,9 +580,9 @@ i386_set_ldt(td, uap, descs) largest_ld = uap->start + uap->num; if (largest_ld > pldt->ldt_len) largest_ld = pldt->ldt_len; - i = largest_ld - uap->start; - bzero(&((union descriptor *)(pldt->ldt_base))[uap->start], - sizeof(union descriptor) * i); + for (i = uap->start; i < largest_ld; i++) + atomic_store_rel_64(&((uint64_t *)(pldt->ldt_base))[i], + 0); mtx_unlock_spin(&dt_lock); return (0); } @@ -702,17 +704,27 @@ again: static int i386_set_ldt_data(struct thread *td, int start, int num, - union descriptor *descs) + union descriptor *descs) { - struct mdproc *mdp = &td->td_proc->p_md; - struct proc_ldt *pldt = mdp->md_ldt; + struct mdproc *mdp; + struct proc_ldt *pldt; + uint64_t *dst, *src; + int i; mtx_assert(&dt_lock, MA_OWNED); - /* Fill in range */ - bcopy(descs, - &((union descriptor *)(pldt->ldt_base))[start], - num * sizeof(union descriptor)); + mdp = &td->td_proc->p_md; + pldt = mdp->md_ldt; + dst = (uint64_t *)(pldt->ldt_base); + src = (uint64_t *)descs; + + /* + * Atomic(9) is used only to get 64bit atomic store with + * cmpxchg8b when available. There is no op without release + * semantic. + */ + for (i = 0; i < num; i++) + atomic_store_rel_64(&dst[start + i], src[i]); return (0); } |