aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2020-12-15 21:53:15 +0000
committerKyle Evans <kevans@FreeBSD.org>2020-12-15 21:53:15 +0000
commit21d35411c119c694f333b979334ae119852caa49 (patch)
tree8cad84786d0cd6bbd0820e13eb791be50ce78da7
parent878170c334dfd246835f9a8baf7a579817a02b30 (diff)
downloadsrc-21d35411c119c694f333b979334ae119852caa49.tar.gz
src-21d35411c119c694f333b979334ae119852caa49.zip
MFC r368462: 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.
Notes
Notes: svn path=/stable/12/; revision=368681
-rw-r--r--sys/kern/kern_cpuset.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/sys/kern/kern_cpuset.c b/sys/kern/kern_cpuset.c
index 07b40c179edc..27440aea5cc5 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;
@@ -1923,6 +1924,10 @@ kern_cpuset_setaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which,
}
}
+ if (CPU_EMPTY(mask)) {
+ error = EDEADLK;
+ goto out;
+ }
switch (level) {
case CPU_LEVEL_ROOT:
case CPU_LEVEL_CPUSET:
@@ -2178,6 +2183,10 @@ kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
}
}
+ if (DOMAINSET_EMPTY(mask)) {
+ error = EDEADLK;
+ goto out;
+ }
DOMAINSET_COPY(mask, &domain.ds_mask);
domain.ds_policy = policy;