Thank you for your contribution! Sashiko AI review found 3 potential issue(s) 
to consider:

Pre-existing issues:
- [Critical] Missing VMA boundary check in panthor PMD mapping insertion causes 
kernel panic or memory overlap.
- [High] Incorrect GEM object page offset calculation causes mapping corruption 
on VMA split or partial unmap.
- [High] Normal refcounted shmem folios are mapped using raw PFN helpers, 
improperly marking them as special.
--

commit 07cb1bde7a0031ea636a380e71bef2ca1d93de8c
Author: Christian A. Ehrhardt <[email protected]>

drm/shmem_helper: Check VMA boundaries for PMD mappings

This commit adds a boundary check in the try_insert_pfn() function to ensure
that a PMD huge page mapping is not installed if it exceeds the boundaries
of the VMA.

> In the ->huge_fault handler do not install a PMD huge page
> mapping if the huge page exceeds the boundaries of the VMA.
> 
> All other ->huge_fault handlers have similar checks and the
> resulting mapping will trigger a VM_BUG_ON_VMA() if it ever
> reaches copy_pmd_range().

[Severity: Critical]
This is a pre-existing issue, but does panthor_gem.c also need this fix?

Looking at insert_page() in drivers/gpu/drm/panthor/panthor_gem.c at line 802,
it inserts a PMD mapping if the address is aligned, but it lacks the
vma->vm_start <= start && end <= vma->vm_end bounds check:

        } else if (order == PMD_ORDER) {
                unsigned long pfn = page_to_pfn(page);
                unsigned long paddr = pfn << PAGE_SHIFT;
                bool aligned = (vmf->address & ~PMD_MASK) == (paddr & 
~PMD_MASK);

                if (aligned &&
                    folio_test_pmd_mappable(page_folio(page))) {
                        pfn &= PMD_MASK >> PAGE_SHIFT;
                        return vmf_insert_pfn_pmd(vmf, pfn, vmf->flags & 
FAULT_FLAG_WRITE);
                }

If userspace mmaps the panthor GEM object, shrinks the VMA to a
non-PMD-aligned size using munmap(), and triggers a page fault at a
PMD-aligned address near the end before calling fork(), couldn't this cause a
VM_BUG_ON_VMA() in copy_pmd_range() or allow memory overlap?

> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c 
> b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index c989459eb2159..00807039f8d7d 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -597,9 +597,13 @@ static vm_fault_t try_insert_pfn(struct vm_fault *vmf, 
> unsigned int order,
>  #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
>       } else if (order == PMD_ORDER) {
>               unsigned long paddr = pfn << PAGE_SHIFT;
> +             struct vm_area_struct *vma = vmf->vma;
> +             unsigned long start = ALIGN_DOWN(vmf->address, PMD_SIZE);
> +             unsigned long end = start + PMD_SIZE;
> +             bool in_range = vma->vm_start <= start && end <= vma->vm_end;
>               bool aligned = (vmf->address & ~PMD_MASK) == (paddr & 
> ~PMD_MASK);
>  
> -             if (aligned &&
> +             if (aligned && in_range &&
>                   folio_test_pmd_mappable(page_folio(pfn_to_page(pfn)))) {
>                       vm_fault_t ret;
>  
> @@ -608,8 +612,10 @@ static vm_fault_t try_insert_pfn(struct vm_fault *vmf, 
> unsigned int order,
>                        * .huge_fault(). Make sure we pass the "write" info
>                        * along in that case.
>                        * This also means we have to record the write fault
>                        * here, instead of in .pfn_mkwrite().
>                        */

[Severity: High]
This isn't a bug introduced by this patch, but are we improperly marking
normal refcounted shmem folios as special?

The try_insert_pfn() function uses raw PFN insertion helpers like
vmf_insert_pfn_pmd() and vmf_insert_pfn() to map these folios. According to
MM guidelines, this marks the folios with VM_PFNMAP and pte_special(), which
hides them from vm_normal_page() and breaks GUP (get_user_pages) and refcount
tracking.

Should this code use vmf_insert_folio() or vmf_insert_page() instead?

> -                     ret = vmf_insert_pfn_pmd(vmf, pfn,
> -                                              vmf->flags & FAULT_FLAG_WRITE);
> +                     ret = vmf_insert_pfn_pmd(vmf, pfn,
> +                                              vmf->flags & FAULT_FLAG_WRITE);
> +                     if (ret == VM_FAULT_NOPAGE && (vmf->flags & 
> FAULT_FLAG_WRITE))
> +                             drm_gem_shmem_record_mkwrite(vmf);

[Severity: High]
This is a pre-existing issue, but does drm_gem_shmem_record_mkwrite() calculate
the page offset incorrectly when a VMA is split?

In drm_gem_shmem_record_mkwrite() at line 576 (and also in
drm_gem_shmem_any_fault() at line 640), the page offset is calculated relative
to the current VMA rather than the GEM object:

        pgoff_t page_offset = vmf->pgoff - vma->vm_pgoff;
        ...
        folio_mark_dirty(page_folio(shmem->pages[page_offset]));

If userspace partially unmaps the beginning of the VMA via
munmap(vma->vm_start, PAGE_SIZE), the VMA split increments vma->vm_pgoff.
Because vmf->pgoff - vma->vm_pgoff evaluates exactly to
(vmf->address - vma->vm_start) >> PAGE_SHIFT, this completely ignores the
split offset and accesses pages[0] for the new VMA instead of the correct
shifted page.

Could this cause mapping corruption by marking the wrong page dirty or
exposing the wrong memory pages?

>  
>                       return ret;
>               }

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

Reply via email to