mirror of
https://github.com/opnsense/src.git
synced 2026-06-13 18:50:31 -04:00
domainset(9): Split domainset validation logic into a separate function
This change splits the validation and 'struct domainset'-filling logic from kern_cpuset_setdomain into a separate function - domainset_populate. This function's main use is to validate user-provided domainset(9) policies and populate a struct domainset before handing it off to domainset_create. No functional change intended. Differential Revision: https://reviews.freebsd.org/D46608 Reviewed by: markj
This commit is contained in:
parent
aae23170c8
commit
cf571e0850
3 changed files with 88 additions and 50 deletions
|
|
@ -22,7 +22,7 @@
|
|||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd April 14, 2021
|
||||
.Dd June 24, 2025
|
||||
.Dt DOMAINSET 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
|
@ -54,6 +54,8 @@ struct domainset {
|
|||
.Ft struct domainset *
|
||||
.Fn domainset_create "const struct domainset *key"
|
||||
.Ft int
|
||||
.Fn domainset_populate "struct domainset *domain" "domainset_t *mask" "int policy" "size_t mask_size"
|
||||
.Ft int
|
||||
.Fn sysctl_handle_domainset "SYSCTL_HANDLER_ARGS"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
|
|
@ -137,6 +139,7 @@ These policies should be used in preference to
|
|||
to avoid blocking indefinitely on a
|
||||
.Dv M_WAITOK
|
||||
request.
|
||||
.Pp
|
||||
The
|
||||
.Fn domainset_create
|
||||
function takes a partially filled in domainset as a key and returns a
|
||||
|
|
@ -148,6 +151,17 @@ is an immutable type that is shared among all matching keys and must
|
|||
not be modified after return.
|
||||
.Pp
|
||||
The
|
||||
.Fn domainset_populate
|
||||
function fills a
|
||||
.Vt domainset
|
||||
struct using a domain mask and policy.
|
||||
It is used for validating and
|
||||
translating a domain mask and policy into a
|
||||
.Vt domainset
|
||||
struct when creating a custom domainset using
|
||||
.Vt domainset_create .
|
||||
.Pp
|
||||
The
|
||||
.Fn sysctl_handle_domainset
|
||||
function is provided as a convenience for modifying or viewing domainsets
|
||||
that are not accessible via
|
||||
|
|
|
|||
|
|
@ -530,7 +530,7 @@ _domainset_create(struct domainset *domain, struct domainlist *freelist)
|
|||
* remove them and update the domainset accordingly. If only empty
|
||||
* domains are present, we must return failure.
|
||||
*/
|
||||
static bool
|
||||
bool
|
||||
domainset_empty_vm(struct domainset *domain)
|
||||
{
|
||||
domainset_t empty;
|
||||
|
|
@ -2408,6 +2408,59 @@ sys_cpuset_setdomain(struct thread *td, struct cpuset_setdomain_args *uap)
|
|||
uap->id, uap->domainsetsize, uap->mask, uap->policy, ©_set));
|
||||
}
|
||||
|
||||
int
|
||||
domainset_populate(struct domainset *domain, const domainset_t *mask, int policy,
|
||||
size_t mask_size)
|
||||
{
|
||||
|
||||
if (policy <= DOMAINSET_POLICY_INVALID ||
|
||||
policy > DOMAINSET_POLICY_MAX) {
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that no high bits are set.
|
||||
*/
|
||||
if (mask_size > sizeof(domainset_t)) {
|
||||
const char *end;
|
||||
const char *cp;
|
||||
|
||||
end = cp = (const char *)&mask->__bits;
|
||||
end += mask_size;
|
||||
cp += sizeof(domainset_t);
|
||||
while (cp != end) {
|
||||
if (*cp++ != 0) {
|
||||
return (EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DOMAINSET_EMPTY(mask)) {
|
||||
return (EDEADLK);
|
||||
}
|
||||
DOMAINSET_COPY(mask, &domain->ds_mask);
|
||||
domain->ds_policy = policy;
|
||||
|
||||
/*
|
||||
* Sanitize the provided mask.
|
||||
*/
|
||||
if (!DOMAINSET_SUBSET(&all_domains, &domain->ds_mask)) {
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Translate preferred policy into a mask and fallback. */
|
||||
if (policy == DOMAINSET_POLICY_PREFER) {
|
||||
/* Only support a single preferred domain. */
|
||||
if (DOMAINSET_COUNT(&domain->ds_mask) != 1) {
|
||||
return (EINVAL);
|
||||
}
|
||||
domain->ds_prefer = DOMAINSET_FFS(&domain->ds_mask) - 1;
|
||||
/* This will be constrained by domainset_shadow(). */
|
||||
DOMAINSET_COPY(&all_domains, &domain->ds_mask);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
|
||||
id_t id, size_t domainsetsize, const domainset_t *maskp, int policy,
|
||||
|
|
@ -2421,62 +2474,20 @@ kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
|
|||
domainset_t *mask;
|
||||
int error;
|
||||
|
||||
if (domainsetsize < sizeof(domainset_t) ||
|
||||
domainsetsize > DOMAINSET_MAXSIZE / NBBY)
|
||||
return (ERANGE);
|
||||
if (policy <= DOMAINSET_POLICY_INVALID ||
|
||||
policy > DOMAINSET_POLICY_MAX)
|
||||
return (EINVAL);
|
||||
error = cpuset_check_capabilities(td, level, which, id);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (domainsetsize < sizeof(domainset_t) ||
|
||||
domainsetsize > DOMAINSET_MAXSIZE / NBBY)
|
||||
return (ERANGE);
|
||||
memset(&domain, 0, sizeof(domain));
|
||||
mask = malloc(domainsetsize, M_TEMP, M_WAITOK | M_ZERO);
|
||||
error = cb->cpuset_copyin(maskp, mask, domainsetsize);
|
||||
if (error)
|
||||
goto out;
|
||||
/*
|
||||
* Verify that no high bits are set.
|
||||
*/
|
||||
if (domainsetsize > sizeof(domainset_t)) {
|
||||
char *end;
|
||||
char *cp;
|
||||
|
||||
end = cp = (char *)&mask->__bits;
|
||||
end += domainsetsize;
|
||||
cp += sizeof(domainset_t);
|
||||
while (cp != end)
|
||||
if (*cp++ != 0) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (DOMAINSET_EMPTY(mask)) {
|
||||
error = EDEADLK;
|
||||
error = domainset_populate(&domain, mask, policy, domainsetsize);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
DOMAINSET_COPY(mask, &domain.ds_mask);
|
||||
domain.ds_policy = policy;
|
||||
|
||||
/*
|
||||
* Sanitize the provided mask.
|
||||
*/
|
||||
if (!DOMAINSET_SUBSET(&all_domains, &domain.ds_mask)) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Translate preferred policy into a mask and fallback. */
|
||||
if (policy == DOMAINSET_POLICY_PREFER) {
|
||||
/* Only support a single preferred domain. */
|
||||
if (DOMAINSET_COUNT(&domain.ds_mask) != 1) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
domain.ds_prefer = DOMAINSET_FFS(&domain.ds_mask) - 1;
|
||||
/* This will be constrained by domainset_shadow(). */
|
||||
DOMAINSET_COPY(&all_domains, &domain.ds_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* When given an impossible policy, fall back to interleaving
|
||||
|
|
@ -2484,7 +2495,6 @@ kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
|
|||
*/
|
||||
if (domainset_empty_vm(&domain))
|
||||
domainset_copy(domainset2, &domain);
|
||||
|
||||
switch (level) {
|
||||
case CPU_LEVEL_ROOT:
|
||||
case CPU_LEVEL_CPUSET:
|
||||
|
|
|
|||
|
|
@ -113,6 +113,20 @@ void domainset_zero(void);
|
|||
* returned value will not match the key pointer.
|
||||
*/
|
||||
struct domainset *domainset_create(const struct domainset *);
|
||||
|
||||
/*
|
||||
* Remove empty domains from a given domainset.
|
||||
* Returns 'false' if the domainset consists entirely of empty domains.
|
||||
*/
|
||||
bool domainset_empty_vm(struct domainset *domain);
|
||||
|
||||
/*
|
||||
* Validate and populate a domainset structure according to the specified
|
||||
* policy and mask.
|
||||
*/
|
||||
int domainset_populate(struct domainset *domain, const domainset_t *mask, int policy,
|
||||
size_t mask_size);
|
||||
|
||||
#ifdef _SYS_SYSCTL_H_
|
||||
int sysctl_handle_domainset(SYSCTL_HANDLER_ARGS);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue