Date: Tue, 19 Sep 2017 17:57:04 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r323772 - in head/sys: amd64/amd64 i386/i386 Message-ID: <201709191757.v8JHv4aD073675@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Tue Sep 19 17:57:04 2017 New Revision: 323772 URL: https://svnweb.freebsd.org/changeset/base/323772 Log: 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 Modified: head/sys/amd64/amd64/sys_machdep.c head/sys/i386/i386/sys_machdep.c Modified: head/sys/amd64/amd64/sys_machdep.c ============================================================================== --- head/sys/amd64/amd64/sys_machdep.c Tue Sep 19 17:12:18 2017 (r323771) +++ head/sys/amd64/amd64/sys_machdep.c Tue Sep 19 17:57:04 2017 (r323772) @@ -583,22 +583,22 @@ amd64_get_ldt(td, uap) } int -amd64_set_ldt(td, uap, descs) - struct thread *td; - struct i386_ldt_args *uap; - struct user_segment_descriptor *descs; +amd64_set_ldt(struct thread *td, struct i386_ldt_args *uap, + struct user_segment_descriptor *descs) { - int error = 0; - unsigned int largest_ld, i; - struct mdproc *mdp = &td->td_proc->p_md; + struct mdproc *mdp; struct proc_ldt *pldt; struct user_segment_descriptor *dp; struct proc *p; + int error; + unsigned int largest_ld, i; #ifdef DEBUG printf("amd64_set_ldt: start=%d num=%d descs=%p\n", uap->start, uap->num, (void *)uap->descs); #endif + mdp = &td->td_proc->p_md; + error = 0; set_pcb_flags(td->td_pcb, PCB_FULL_IRET); p = td->td_proc; @@ -616,10 +616,9 @@ amd64_set_ldt(td, uap, descs) largest_ld = max_ldt_segment; if (largest_ld < uap->start) return (EINVAL); - i = largest_ld - uap->start; mtx_lock(&dt_lock); - bzero(&((struct user_segment_descriptor *)(pldt->ldt_base)) - [uap->start], sizeof(struct user_segment_descriptor) * i); + for (i = uap->start; i < largest_ld; i++) + ((uint64_t *)(pldt->ldt_base))[i] = 0; mtx_unlock(&dt_lock); return (0); } @@ -741,14 +740,18 @@ int amd64_set_ldt_data(struct thread *td, int start, int num, struct user_segment_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, - &((struct user_segment_descriptor *)(pldt->ldt_base))[start], - num * sizeof(struct user_segment_descriptor)); + mdp = &td->td_proc->p_md; + pldt = mdp->md_ldt; + dst = (uint64_t *)(pldt->ldt_base); + src = (uint64_t *)descs; + for (i = 0; i < num; i++) + dst[start + i] = src[i]; return (0); } Modified: head/sys/i386/i386/sys_machdep.c ============================================================================== --- head/sys/i386/i386/sys_machdep.c Tue Sep 19 17:12:18 2017 (r323771) +++ head/sys/i386/i386/sys_machdep.c Tue Sep 19 17:57:04 2017 (r323772) @@ -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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709191757.v8JHv4aD073675>