Author: kevans Date: Tue Dec 8 18:45:47 2020 New Revision: 368461 URL: https://svnweb.freebsd.org/changeset/base/368461
Log: kern: cpuset: resolve race between cpuset_lookup/cpuset_rel The race plays out like so between threads A and B: 1. A ref's cpuset 10 2. B does a lookup of cpuset 10, grabs the cpuset lock and searches cpuset_ids 3. A rel's cpuset 10 and observes the last ref, waits on the cpuset lock while B is still searching and not yet ref'd 4. B ref's cpuset 10 and drops the cpuset lock 5. A proceeds to free the cpuset out from underneath B Resolve the race by only releasing the last reference under the cpuset lock. Thread A now picks up the spinlock and observes that the cpuset has been revived, returning immediately for B to deal with later. Reported by: syzbot+92dff413e201164c7...@syzkaller.appspotmail.com Reviewed by: markj MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D27498 Modified: head/sys/kern/kern_cpuset.c Modified: head/sys/kern/kern_cpuset.c ============================================================================== --- head/sys/kern/kern_cpuset.c Tue Dec 8 18:44:06 2020 (r368460) +++ head/sys/kern/kern_cpuset.c Tue Dec 8 18:45:47 2020 (r368461) @@ -207,9 +207,13 @@ cpuset_rel(struct cpuset *set) { cpusetid_t id; - if (refcount_release(&set->cs_ref) == 0) + if (refcount_release_if_not_last(&set->cs_ref)) return; mtx_lock_spin(&cpuset_lock); + if (!refcount_release(&set->cs_ref)) { + mtx_unlock_spin(&cpuset_lock); + return; + } LIST_REMOVE(set, cs_siblings); id = set->cs_id; if (id != CPUSET_INVALID) @@ -229,9 +233,13 @@ static void cpuset_rel_defer(struct setlist *head, struct cpuset *set) { - if (refcount_release(&set->cs_ref) == 0) + if (refcount_release_if_not_last(&set->cs_ref)) return; mtx_lock_spin(&cpuset_lock); + if (!refcount_release(&set->cs_ref)) { + mtx_unlock_spin(&cpuset_lock); + return; + } LIST_REMOVE(set, cs_siblings); if (set->cs_id != CPUSET_INVALID) LIST_REMOVE(set, cs_link); _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"