From: Matthew Dillon Date: Fri, 20 Oct 2017 19:12:54 +0000 (-0700) Subject: kernel - Fix userldt refcnt races X-Git-Tag: v5.3.0~948 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/e845e9dc5c58952132cd9271bfed632bf19ff619 kernel - Fix userldt refcnt races * 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 --- diff --git a/sys/cpu/x86_64/include/segments.h b/sys/cpu/x86_64/include/segments.h index 4976d5aba9..831abc9d6b 100644 --- a/sys/cpu/x86_64/include/segments.h +++ b/sys/cpu/x86_64/include/segments.h @@ -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, diff --git a/sys/platform/pc64/x86_64/machdep.c b/sys/platform/pc64/x86_64/machdep.c index e670d88693..6124d2b2da 100644 --- a/sys/platform/pc64/x86_64/machdep.c +++ b/sys/platform/pc64/x86_64/machdep.c @@ -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) diff --git a/sys/platform/pc64/x86_64/vm_machdep.c b/sys/platform/pc64/x86_64/vm_machdep.c index 07031e6a65..85b16b749d 100644 --- a/sys/platform/pc64/x86_64/vm_machdep.c +++ b/sys/platform/pc64/x86_64/vm_machdep.c @@ -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, diff --git a/sys/platform/vkernel64/x86_64/vm_machdep.c b/sys/platform/vkernel64/x86_64/vm_machdep.c index 477448a599..6827034cbb 100644 --- a/sys/platform/vkernel64/x86_64/vm_machdep.c +++ b/sys/platform/vkernel64/x86_64/vm_machdep.c @@ -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);