Re: [PATCH v5 35/36] KVM: guest_memfd: bind backing memory to a NUMA node at creation

[email protected] Tue, 21 Jul 2026 21:11:49 +0000
Newsgroups dev.linux.lists.nvdimm,dev.linux.lists.damon,org.kernel.vger.kvm,org.kernel.vger.linux-cxl
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Unconditional validation of flag-gated syscall parameters outside their flag scope breaks ABI compatibility for existing userspace.
- [Medium] Missing lock when calling `mpol_set_nodemask` leads to data race and torn read of `current->mems_allowed`.
--

--- Patch [35]: [PATCH v5 35/36] KVM: guest_memfd: bind backing memory to a NUMA node at creation ---
commit 45130876f6e87292f19cee2648796441ea4622ce
Author: Gregory Price <[email protected]>

KVM: guest_memfd: bind backing memory to a NUMA node at creation

guest_memfd presently allocates its page-cache folios through a per-inode
shared mempolicy. This patch adds GUEST_MEMFD_FLAG_BIND_NODE to set an
MPOL_BIND policy for the requested node and install it over the whole
inode's shared policy.

> diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> index f0e5da4908660..de320df08e0ff 100644
> --- a/virt/kvm/guest_memfd.c
> +++ b/virt/kvm/guest_memfd.c

[ ... ]

> @@ -456,6 +456,26 @@ static struct mempolicy *kvm_gmem_get_policy(struct vm_area_struct *vma,
>  	 */
>  	return mpol_shared_policy_lookup(&GMEM_I(inode)->policy, pgoff);
>  }
> +
> +static int kvm_gmem_bind_node(struct inode *inode, int node)
> +{
> +	struct mempolicy *pol;
> +	int err;
> +
> +	pol = mpol_bind_node(node);

[Severity: Medium]
Can calling mpol_bind_node() here without holding task_lock(current)
cause a data race?

Looking at mpol_bind_node(), it calls __mpol_bind_node() which then calls
mpol_set_nodemask(). This accesses current->mems_allowed locklessly.

If a task's cpuset is concurrently modified, this could lead to a torn read
of current->mems_allowed on systems with >64 NUMA nodes, potentially
failing or creating a policy with an incorrect or empty nodemask.

> +	if (IS_ERR(pol))
> +		return PTR_ERR(pol);
> +
> +	err = mpol_set_shared_policy_range(&GMEM_I(inode)->policy, 0,
> +					  MAX_LFS_FILESIZE >> PAGE_SHIFT, pol);
> +	mpol_put(pol);
> +	return err;
> +}

[ ... ]

> @@ -630,6 +656,7 @@ int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args)
>  {
>  	loff_t size = args->size;
>  	u64 flags = args->flags;
> +	int node = NUMA_NO_NODE;
>  
>  	if (flags & ~kvm_gmem_get_supported_flags(kvm))
>  		return -EINVAL;
> @@ -637,7 +664,15 @@ int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args)
>  	if (size <= 0 || !PAGE_ALIGNED(size))
>  		return -EINVAL;
>  
> -	return __kvm_gmem_create(kvm, size, flags);
> +	if (flags & GUEST_MEMFD_FLAG_BIND_NODE) {
> +		if (args->pad || args->node >= MAX_NUMNODES)
> +			return -EINVAL;
> +		node = args->node;
> +	} else if (args->node || args->pad) {

[Severity: Critical]
Does unconditionally checking args->node and args->pad when the
GUEST_MEMFD_FLAG_BIND_NODE flag is absent break ABI compatibility?

Since these fields were previously part of the unused reserved[] array,
existing userspace binaries might allocate struct kvm_create_guest_memfd
on the stack without zeroing them. 

If an older binary calls the ioctl without the new flag, and the stack
garbage happens to be non-zero, this will now fail with -EINVAL.

> +		return -EINVAL;
> +	}
> +
> +	return __kvm_gmem_create(kvm, size, flags, node);
>  }

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=35