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
This commit is contained in:
parent
b2780e8537
commit
f1b18a668d
@ -633,7 +633,7 @@ domainset_shadow(const struct domainset *pdomain,
|
|||||||
* empty as well as RDONLY flags.
|
* empty as well as RDONLY flags.
|
||||||
*/
|
*/
|
||||||
static int
|
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;
|
struct cpuset *nset;
|
||||||
cpuset_t newmask;
|
cpuset_t newmask;
|
||||||
@ -642,13 +642,14 @@ cpuset_testupdate(struct cpuset *set, cpuset_t *mask, int check_mask)
|
|||||||
mtx_assert(&cpuset_lock, MA_OWNED);
|
mtx_assert(&cpuset_lock, MA_OWNED);
|
||||||
if (set->cs_flags & CPU_SET_RDONLY)
|
if (set->cs_flags & CPU_SET_RDONLY)
|
||||||
return (EPERM);
|
return (EPERM);
|
||||||
if (check_mask) {
|
if (augment_mask) {
|
||||||
if (!CPU_OVERLAP(&set->cs_mask, mask))
|
|
||||||
return (EDEADLK);
|
|
||||||
CPU_COPY(&set->cs_mask, &newmask);
|
CPU_COPY(&set->cs_mask, &newmask);
|
||||||
CPU_AND(&newmask, mask);
|
CPU_AND(&newmask, mask);
|
||||||
} else
|
} else
|
||||||
CPU_COPY(mask, &newmask);
|
CPU_COPY(mask, &newmask);
|
||||||
|
|
||||||
|
if (CPU_EMPTY(&newmask))
|
||||||
|
return (EDEADLK);
|
||||||
error = 0;
|
error = 0;
|
||||||
LIST_FOREACH(nset, &set->cs_children, cs_siblings)
|
LIST_FOREACH(nset, &set->cs_children, cs_siblings)
|
||||||
if ((error = cpuset_testupdate(nset, &newmask, 1)) != 0)
|
if ((error = cpuset_testupdate(nset, &newmask, 1)) != 0)
|
||||||
@ -723,7 +724,7 @@ out:
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cpuset_testupdate_domain(struct cpuset *set, struct domainset *dset,
|
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 cpuset *nset;
|
||||||
struct domainset *domain;
|
struct domainset *domain;
|
||||||
@ -2001,6 +2002,10 @@ kern_cpuset_setaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (CPU_EMPTY(mask)) {
|
||||||
|
error = EDEADLK;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case CPU_LEVEL_ROOT:
|
case CPU_LEVEL_ROOT:
|
||||||
case CPU_LEVEL_CPUSET:
|
case CPU_LEVEL_CPUSET:
|
||||||
@ -2255,6 +2260,10 @@ kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (DOMAINSET_EMPTY(mask)) {
|
||||||
|
error = EDEADLK;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
DOMAINSET_COPY(mask, &domain.ds_mask);
|
DOMAINSET_COPY(mask, &domain.ds_mask);
|
||||||
domain.ds_policy = policy;
|
domain.ds_policy = policy;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user