xen/sched: core: skip missing vcpu slots in sched_move_domain()

sched_move_domain() derives the number of units to rebuild from
d->max_vcpus, which is fixed at domain creation and never rolled
back if vcpu_create() fails partway through building a domain. So
d->vcpu[i] can be NULL for some i even though max_vcpus still
counts it - this happens if sched_alloc_udata() returns NULL.

The per-unit loop doesn't check for this: it sets
unit->vcpu_list = d->vcpu[unit_id] (NULL) and hands that broken
unit straight to the destination scheduler's alloc_udata(),
which assumes vcpu_list is always valid and crashes Xen when
it is not.

Reproduced by building a domain in a non-default cpupool where
vcpu creation fails partway through, then destroying it.
domain_kill() moves the domain back to the default cpupool via
sched_move_domain() before actually destroying it, crashing
inside the destination scheduler's alloc_udata() (seen in
Credit2's csched2_alloc_udata() -> is_idle_unit() -> NULL deref).

Before building a unit in sched_move_domain(), check whether all
vpcu slots belonging to that unit are populated. If any of its
vpcus is missing:
 - For a dying domain, skip the unit allocation.
 - For an active domain, abort the move and return -EINVAL to
   prevent running with dropped vCPUs.

Fixes: 70fadc4163 ("xen/cpupool: support moving domain between cpupools with different granularity")
Signed-off-by: Furkan Caliskan <frn1furkan10@gmail.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
master commit: 4835c078e5
master date: 2026-09-21 09:54:12 +0200
This commit is contained in:
Furkan Caliskan authored and Jan Beulich committed 2026-09-30 13:06:39 +02:00
1 parent 47f84fcb06
commit b85247239d
1 file changed
+32
+32
View File
@@ -722,6 +722,38 @@ int sched_move_domain(struct domain *d, struct cpupool *c)
for ( unit_idx = 0; unit_idx < n_units; unit_idx++ )
{
/*
* A vcpu slot can be missing if creation failed partway
* through. A dying domain is being torn down regardless, so
* skip the unit -- but a domain that isn't dying still needs
* every vcpu it has schedulable, so fail instead of silently
* dropping some of them.
*/
bool vcpu_failed = false;
for ( unsigned int i = 0;
i < gran && unit_idx * gran + i < d->max_vcpus; i++ )
{
if ( !d->vcpu[unit_idx * gran + i] )
{
vcpu_failed = true;
break;
}
}
if ( vcpu_failed )
{
if ( !d->is_dying )
{
sched_move_domain_cleanup(c->sched, new_units, domdata);
rcu_read_unlock(&sched_res_rculock);
return -EINVAL;
}
continue;
}
unit = sched_alloc_unit_mem();
if ( unit )
{
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.