Author: kevans
Date: Tue Dec  8 18:47:22 2020
New Revision: 368462
URL: https://svnweb.freebsd.org/changeset/base/368462

Log:
  cpuset_set{affinity,domain}: do not allow empty masks
  
  cpuset_modify() would not currently catch this, because it only checks that
  the new mask is a subset of the root set and circumvents the EDEADLK check
  in cpuset_testupdate().
  
  This change both directly validates the mask coming in since we can
  trivially detect an empty mask, and it updates cpuset_testupdate to catch
  stuff like this going forward by always ensuring we don't end up with an
  empty mask.
  
  The check_mask argument has been renamed because the 'check' verbiage does
  not imply to me that it's actually doing a different operation. We're either
  augmenting the existing mask, or we are replacing it entirely.
  
  Reported by:  syzbot+4e3b1009de98d2fab...@syzkaller.appspotmail.com
  Discussed with:       andrew
  Reviewed by:  andrew, markj
  MFC after:    1 week
  Differential Revision:        https://reviews.freebsd.org/D27511

Modified:
  head/sys/kern/kern_cpuset.c

Modified: head/sys/kern/kern_cpuset.c
==============================================================================
--- head/sys/kern/kern_cpuset.c Tue Dec  8 18:45:47 2020        (r368461)
+++ head/sys/kern/kern_cpuset.c Tue Dec  8 18:47:22 2020        (r368462)
@@ -633,7 +633,7 @@ domainset_shadow(const struct domainset *pdomain,
  * empty as well as RDONLY flags.
  */
 static int
-cpuset_testupdate(struct cpuset *set, cpuset_t *mask, int check_mask)
+cpuset_testupdate(struct cpuset *set, cpuset_t *mask, int augment_mask)
 {
        struct cpuset *nset;
        cpuset_t newmask;
@@ -642,13 +642,14 @@ cpuset_testupdate(struct cpuset *set, cpuset_t *mask, 
        mtx_assert(&cpuset_lock, MA_OWNED);
        if (set->cs_flags & CPU_SET_RDONLY)
                return (EPERM);
-       if (check_mask) {
-               if (!CPU_OVERLAP(&set->cs_mask, mask))
-                       return (EDEADLK);
+       if (augment_mask) {
                CPU_COPY(&set->cs_mask, &newmask);
                CPU_AND(&newmask, mask);
        } else
                CPU_COPY(mask, &newmask);
+
+       if (CPU_EMPTY(&newmask))
+               return (EDEADLK);
        error = 0;
        LIST_FOREACH(nset, &set->cs_children, cs_siblings) 
                if ((error = cpuset_testupdate(nset, &newmask, 1)) != 0)
@@ -723,7 +724,7 @@ out:
  */
 static int
 cpuset_testupdate_domain(struct cpuset *set, struct domainset *dset,
-    struct domainset *orig, int *count, int check_mask)
+    struct domainset *orig, int *count, int augment_mask __unused)
 {
        struct cpuset *nset;
        struct domainset *domain;
@@ -2001,6 +2002,10 @@ kern_cpuset_setaffinity(struct thread *td, cpulevel_t 
                                goto out;
                        }
        }
+       if (CPU_EMPTY(mask)) {
+               error = EDEADLK;
+               goto out;
+       }
        switch (level) {
        case CPU_LEVEL_ROOT:
        case CPU_LEVEL_CPUSET:
@@ -2254,6 +2259,10 @@ kern_cpuset_setdomain(struct thread *td, cpulevel_t le
                                error = EINVAL;
                                goto out;
                        }
+       }
+       if (DOMAINSET_EMPTY(mask)) {
+               error = EDEADLK;
+               goto out;
        }
        DOMAINSET_COPY(mask, &domain.ds_mask);
        domain.ds_policy = policy;
_______________________________________________
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"

Reply via email to