On 21/02/2026 12:57, Julien Grall wrote:
> Hi Michal,
> 
> For the subject title and part of the code, "memory leak" tends to imply 
> the memory is lost forever and therefore can never be recovered. AFAIU, 
> in your case, the memory will be freed when the domain is destroyed. I 
> would suggest to clarify it so it doesn't sound like a security issue.
> 
> What about:
> 
> "xen/arm: mm: Release the old page reference in xenmem_add_to_physmap_one()"
Reads ok.

> 
> On 05/02/2026 12:58, Michal Orzel wrote:
>> When a guest maps pages via XENMEM_add_to_physmap to a GFN that already
>> has an existing mapping, the old page at that GFN was not being removed,
>> causing a memory leak. This affects all mapping spaces including
>> XENMAPSPACE_shared_info, XENMAPSPACE_grant_table, and
>> XENMAPSPACE_gmfn_foreign. The memory would be reclaimed on domain
>> destruction.
>>
>> Add logic to remove the previously mapped page before creating the new
>> mapping, matching the x86 implementation approach.
>>
>> Additionally, skip removal if the same MFN is being remapped.
> 
> Can you explain why we skip the removal but not the insertion in this case?
Hmm, I must have missed that the type is always fixed. In that case, we can skip
the insertion/removal.

> 
>>
>> Signed-off-by: Michal Orzel <[email protected]>
>> ---
>> I'm not sure where to point the Fixes tag to.
>> ---
>>   xen/arch/arm/mm.c | 32 +++++++++++++++++++++++++++++---
>>   1 file changed, 29 insertions(+), 3 deletions(-)
>>
>> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
>> index 6df8b616e464..b9f1a493dcd7 100644
>> --- a/xen/arch/arm/mm.c
>> +++ b/xen/arch/arm/mm.c
>> @@ -166,10 +166,11 @@ int xenmem_add_to_physmap_one(
>>       unsigned long idx,
>>       gfn_t gfn)
>>   {
>> -    mfn_t mfn = INVALID_MFN;
>> +    mfn_t mfn = INVALID_MFN, mfn_old;
>>       int rc;
>>       p2m_type_t t;
>>       struct page_info *page = NULL;
>> +    struct p2m_domain *p2m = p2m_get_hostp2m(d);
>>   
>>       switch ( space )
>>       {
>> @@ -244,6 +245,33 @@ int xenmem_add_to_physmap_one(
>>           return -ENOSYS;
>>       }
>>   
>> +    /*
>> +     * Remove previously mapped page if it was present, to avoid leaking
>> +     * memory.
>> +     */
>> +    mfn_old = gfn_to_mfn(d, gfn);
> 
> I saw Jan mentionned the fact that we have two section with the P2M lock 
> taken. But isn't it in fact 3 sections as gfn_to_mfn(d, gfn) also take a 
> lock?
> 
> I am not against the idea of not solving the locking right now. But I 
> think it would at least be good to document it so this doesn't come as a 
> surprise.
I'll prepare a v2 with a comment and better explanation.

> 
>> +
>> +    if ( mfn_valid(mfn_old) )
>> +    {
>> +        if ( is_special_page(mfn_to_page(mfn_old)) )
>> +        {
>> +            /* Just unmap, don't free */
>> +            p2m_write_lock(p2m);
>> +            rc = p2m_set_entry(p2m, gfn, 1, INVALID_MFN,
>> +                               p2m_invalid, p2m->default_access);
>> +            p2m_write_unlock(p2m);
>> +            if ( rc )
>> +                return rc;
> 
> For here and the second "return" statement below. Above callers may have 
> taken a reference on the new page. So shouldn't we drop it like this is 
> done at the end of the function?
Yes, we should.

> 
>> +        }
>> +        else if ( !mfn_eq(mfn, mfn_old) )
>> +        {
>> +            /* Normal domain memory is freed, to avoid leaking memory */
> 
> Based on the thread with Jan, is this statement actually correct? Could 
> we reach this call with an MMIO (or event foreign mapping). In which 
> case, I am guessing we could fail? If so, is this the intended behavior 
> change?
I wanted to leave MMIO case for a separate change but I can try to fit it all
together.

Let's discuss on v2. I'll try to prepare it taking all the remarks into account.

~Michal


Reply via email to