diff --git a/sys/kern/kern_varsym.c b/sys/kern/kern_varsym.c --- a/sys/kern/kern_varsym.c +++ b/sys/kern/kern_varsym.c @@ -507,7 +507,7 @@ nve = kmalloc(sizeof(struct varsyment), M_VARSYM, M_WAITOK|M_ZERO); nve->ve_sym = ve->ve_sym; - ++nve->ve_sym->vs_refs; /* can't be reached, no need for atomic add */ + atomic_add_int(&nve->ve_sym->vs_refs, 1); /* concurrent varsymdrop races */ /* * We're only called through varsymset_init() so vss is not yet reachable, * no need to lock. @@ -523,10 +523,18 @@ TAILQ_INIT(&vss->vx_queue); lockinit(&vss->vx_lock, "vx", 0, 0); if (copy) { + /* + * Hold the source varsymset's lock while copying so a concurrent + * varsym_set()/varsymmake() on another LWP of the same proc cannot + * free entries (or race the non-atomic refcount) out from under our + * TAILQ traversal. + */ + lockmgr(©->vx_lock, LK_SHARED); TAILQ_FOREACH(ve, ©->vx_queue, ve_entry) { varsymdup(vss, ve); } vss->vx_setsize = copy->vx_setsize; + lockmgr(©->vx_lock, LK_RELEASE); } }