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);
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to