diff options
author | Kyle Evans <kevans@FreeBSD.org> | 2020-12-08 18:47:22 +0000 |
---|---|---|
committer | Kyle Evans <kevans@FreeBSD.org> | 2020-12-08 18:47:22 +0000 |
commit | f1b18a668deb2aab9e2da908a403d58bce029d80 (patch) | |
tree | 3b1ef66f26d69e4cfa5c392a9eb206328ccfda5c /sys/kern | |
parent | b2780e8537daad67ec9b98c5784f73493cb9c7a7 (diff) | |
download | src-test2-f1b18a668deb2aab9e2da908a403d58bce029d80.tar.gz src-test2-f1b18a668deb2aab9e2da908a403d58bce029d80.zip |
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+4e3b1009de98d2fabcda@syzkaller.appspotmail.com
Discussed with: andrew
Reviewed by: andrew, markj
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D27511
Notes
Notes:
svn path=/head/; revision=368462
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_cpuset.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/sys/kern/kern_cpuset.c b/sys/kern/kern_cpuset.c index be70182b3dea..8b962190a3fa 100644 --- a/sys/kern/kern_cpuset.c +++ b/sys/kern/kern_cpuset.c @@ -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, int check_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 level, cpuwhich_t which, goto out; } } + if (CPU_EMPTY(mask)) { + error = EDEADLK; + goto out; + } switch (level) { case CPU_LEVEL_ROOT: case CPU_LEVEL_CPUSET: @@ -2255,6 +2260,10 @@ kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which, goto out; } } + if (DOMAINSET_EMPTY(mask)) { + error = EDEADLK; + goto out; + } DOMAINSET_COPY(mask, &domain.ds_mask); domain.ds_policy = policy; |