kernel - Fix userldt refcnt races
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 20 Oct 2017 19:12:54 +0000 (12:12 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 31 Oct 2017 17:49:47 +0000 (10:49 -0700)
* Fix userldt refcnt races.  Note that at the moment, DragonFlyBSD
  doesn't implement userldt support anyway, so this does not fix
  any actual bugs.  But make sure the code is correct.

Suggested-by: mjg
sys/cpu/x86_64/include/segments.h
sys/platform/pc64/x86_64/machdep.c
sys/platform/pc64/x86_64/vm_machdep.c
sys/platform/vkernel64/x86_64/vm_machdep.c

index 4976d5a..831abc9 100644 (file)
@@ -258,7 +258,6 @@ extern struct user_segment_descriptor gdt[];
 extern struct soft_segment_descriptor gdt_segs[];
 extern struct gate_descriptor idt_arr[MAXCPU][NIDT];
 extern struct region_descriptor r_idt_arr[];
-extern struct mtx dt_lock;
 
 void   lgdt(struct region_descriptor *rdp);
 void   sdtossd(struct user_segment_descriptor *sdp,
index e670d88..6124d2b 100644 (file)
@@ -253,7 +253,6 @@ int imcr_present = 0;
 int naps = 0; /* # of Applications processors */
 
 u_int base_memory;
-struct mtx dt_lock;            /* lock for GDT and LDT */
 
 static int
 sysctl_hw_physmem(SYSCTL_HANDLER_ARGS)
index 07031e6..85b16b7 100644 (file)
@@ -91,9 +91,15 @@ cpu_fork(struct lwp *lp1, struct lwp *lp2, int flags)
 
        if ((flags & RFPROC) == 0) {
                if ((flags & RFMEM) == 0) {
-                       /* unshare user LDT */
+                       /*
+                        * Unshare user LDT.  > 1 test is MPSAFE.  While
+                        * it can potentially race a 2->1 transition, the
+                        * worst that happens is that we do an unnecessary
+                        * ldt replacement.
+                        */
                        struct pcb *pcb1 = lp1->lwp_thread->td_pcb;
                        struct pcb_ldt *pcb_ldt = pcb1->pcb_ldt;
+
                        if (pcb_ldt && pcb_ldt->ldt_refcnt > 1) {
                                pcb_ldt = user_ldt_alloc(pcb1,pcb_ldt->ldt_len);
                                user_ldt_free(pcb1);
@@ -171,10 +177,10 @@ cpu_fork(struct lwp *lp1, struct lwp *lp2, int flags)
         /* Copy the LDT, if necessary. */
         if (pcb2->pcb_ldt != NULL) {
                if (flags & RFMEM) {
-                       pcb2->pcb_ldt->ldt_refcnt++;
+                       atomic_add_int(&pcb2->pcb_ldt->ldt_refcnt, 1);
                } else {
                        pcb2->pcb_ldt = user_ldt_alloc(pcb2,
-                               pcb2->pcb_ldt->ldt_len);
+                                                      pcb2->pcb_ldt->ldt_len);
                }
         }
        bcopy(&lp1->lwp_thread->td_tls, &lp2->lwp_thread->td_tls,
index 477448a..6827034 100644 (file)
@@ -173,7 +173,7 @@ cpu_fork(struct lwp *lp1, struct lwp *lp2, int flags)
         /* Copy the LDT, if necessary. */
         if (pcb2->pcb_ldt != NULL) {
                if (flags & RFMEM) {
-                       pcb2->pcb_ldt->ldt_refcnt++;
+                       atomic_add_int(&pcb2->pcb_ldt->ldt_refcnt, 1);
                } else {
                        pcb2->pcb_ldt = user_ldt_alloc(pcb2,
                                pcb2->pcb_ldt->ldt_len);