Message ID | 20240822192543.3359552-13-Liam.Howlett@oracle.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Avoid MAP_FIXED gap exposure | expand |
Hi Liam, On Thu, Aug 22, 2024 at 9:27 PM Liam R. Howlett <Liam.Howlett@oracle.com> wrote: > From: "Liam R. Howlett" <Liam.Howlett@Oracle.com> > > Set the start and end address for munmap when the prev and next are > gathered. This is needed to avoid incorrect addresses being used during > the vms_complete_munmap_vmas() function if the prev/next vma are > expanded. > > Add a new helper vms_complete_pte_clear(), which is needed later and > will avoid growing the argument list to unmap_region() beyond the 9 it > already has. > > Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com> > Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Thanks for your patch, which is now commit ca39aca8db2d78ff ("mm/vma: track start and end for munmap in vma_munmap_struct") in next-20240826. > --- a/mm/vma.h > +++ b/mm/vma.h > @@ -38,6 +38,8 @@ struct vma_munmap_struct { > struct list_head *uf; /* Userfaultfd list_head */ > unsigned long start; /* Aligned start addr (inclusive) */ > unsigned long end; /* Aligned end addr (exclusive) */ > + unsigned long unmap_start; /* Unmap PTE start */ > + unsigned long unmap_end; /* Unmap PTE end */ > int vma_count; /* Number of vmas that will be removed */ > unsigned long nr_pages; /* Number of pages being removed */ > unsigned long locked_vm; /* Number of locked pages */ > @@ -108,6 +110,8 @@ static inline void init_vma_munmap(struct vma_munmap_struct *vms, > vms->vma_count = 0; > vms->nr_pages = vms->locked_vm = vms->nr_accounted = 0; > vms->exec_vm = vms->stack_vm = vms->data_vm = 0; > + vms->unmap_start = FIRST_USER_ADDRESS; > + vms->unmap_end = USER_PGTABLES_CEILING; noreply@ellerman.id.au reported build failures for m5272c3_defconfig http://kisskb.ellerman.id.au/kisskb/buildresult/15224802/ $ make ARCH=m68k m5272c3_defconfig mm/filemap.o In file included from mm/internal.h:22, from mm/filemap.c:52: mm/vma.h: In function ‘init_vma_munmap’: mm/vma.h:113:21: error: ‘FIRST_USER_ADDRESS’ undeclared (first use in this function) 113 | vms->unmap_start = FIRST_USER_ADDRESS; | ^~~~~~~~~~~~~~~~~~ mm/vma.h:113:21: note: each undeclared identifier is reported only once for each function it appears in mm/vma.h:114:19: error: ‘USER_PGTABLES_CEILING’ undeclared (first use in this function) 114 | vms->unmap_end = USER_PGTABLES_CEILING; | ^~~~~~~~~~~~~~~~~~~~~ Both are defined in include/linux/pgtable.h inside #ifdef CONFIG_MMU, so they are not available on nommu. > } > > int vms_gather_munmap_vmas(struct vma_munmap_struct *vms, Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
On Mon, Aug 26, 2024 at 04:01:10PM GMT, Geert Uytterhoeven wrote: > Hi Liam, > > On Thu, Aug 22, 2024 at 9:27 PM Liam R. Howlett <Liam.Howlett@oracle.com> wrote: > > From: "Liam R. Howlett" <Liam.Howlett@Oracle.com> > > > > Set the start and end address for munmap when the prev and next are > > gathered. This is needed to avoid incorrect addresses being used during > > the vms_complete_munmap_vmas() function if the prev/next vma are > > expanded. > > > > Add a new helper vms_complete_pte_clear(), which is needed later and > > will avoid growing the argument list to unmap_region() beyond the 9 it > > already has. > > > > Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com> > > Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> > > Thanks for your patch, which is now commit ca39aca8db2d78ff ("mm/vma: > track start and end for munmap in vma_munmap_struct") in next-20240826. > > > --- a/mm/vma.h > > +++ b/mm/vma.h > > @@ -38,6 +38,8 @@ struct vma_munmap_struct { > > struct list_head *uf; /* Userfaultfd list_head */ > > unsigned long start; /* Aligned start addr (inclusive) */ > > unsigned long end; /* Aligned end addr (exclusive) */ > > + unsigned long unmap_start; /* Unmap PTE start */ > > + unsigned long unmap_end; /* Unmap PTE end */ > > int vma_count; /* Number of vmas that will be removed */ > > unsigned long nr_pages; /* Number of pages being removed */ > > unsigned long locked_vm; /* Number of locked pages */ > > @@ -108,6 +110,8 @@ static inline void init_vma_munmap(struct vma_munmap_struct *vms, > > vms->vma_count = 0; > > vms->nr_pages = vms->locked_vm = vms->nr_accounted = 0; > > vms->exec_vm = vms->stack_vm = vms->data_vm = 0; > > + vms->unmap_start = FIRST_USER_ADDRESS; > > + vms->unmap_end = USER_PGTABLES_CEILING; > > noreply@ellerman.id.au reported build failures for m5272c3_defconfig > http://kisskb.ellerman.id.au/kisskb/buildresult/15224802/ > > $ make ARCH=m68k m5272c3_defconfig mm/filemap.o > In file included from mm/internal.h:22, > from mm/filemap.c:52: > mm/vma.h: In function ‘init_vma_munmap’: > mm/vma.h:113:21: error: ‘FIRST_USER_ADDRESS’ undeclared (first use in > this function) > 113 | vms->unmap_start = FIRST_USER_ADDRESS; > | ^~~~~~~~~~~~~~~~~~ > mm/vma.h:113:21: note: each undeclared identifier is reported only > once for each function it appears in > mm/vma.h:114:19: error: ‘USER_PGTABLES_CEILING’ undeclared (first use > in this function) > 114 | vms->unmap_end = USER_PGTABLES_CEILING; > | ^~~~~~~~~~~~~~~~~~~~~ > > Both are defined in include/linux/pgtable.h inside #ifdef CONFIG_MMU, > so they are not available on nommu. Thanks for the report, this was already resolved (or should be :) via fix-patch in [0]. [0}:https://lore.kernel.org/all/7d0ea994-f750-49c5-b392-ae7117369cf3@lucifer.local/ > > > > } > > > > int vms_gather_munmap_vmas(struct vma_munmap_struct *vms, > > Gr{oetje,eeting}s, > > Geert > > > -- > Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org > > In personal conversations with technical people, I call myself a hacker. But > when I'm talking to journalists I just say "programmer" or something like that. > -- Linus Torvalds
diff --git a/mm/vma.c b/mm/vma.c index 9de41e1bf3b2..dda0dae069e2 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -646,6 +646,26 @@ void vma_complete(struct vma_prepare *vp, uprobe_mmap(vp->insert); } +static void vms_complete_pte_clear(struct vma_munmap_struct *vms, + struct ma_state *mas_detach, bool mm_wr_locked) +{ + struct mmu_gather tlb; + + /* + * We can free page tables without write-locking mmap_lock because VMAs + * were isolated before we downgraded mmap_lock. + */ + mas_set(mas_detach, 1); + lru_add_drain(); + tlb_gather_mmu(&tlb, vms->mm); + update_hiwater_rss(vms->mm); + unmap_vmas(&tlb, mas_detach, vms->vma, vms->start, vms->end, vms->vma_count, mm_wr_locked); + mas_set(mas_detach, 1); + /* start and end may be different if there is no prev or next vma. */ + free_pgtables(&tlb, mas_detach, vms->vma, vms->unmap_start, vms->unmap_end, mm_wr_locked); + tlb_finish_mmu(&tlb); +} + /* * vms_complete_munmap_vmas() - Finish the munmap() operation * @vms: The vma munmap struct @@ -667,13 +687,7 @@ void vms_complete_munmap_vmas(struct vma_munmap_struct *vms, if (vms->unlock) mmap_write_downgrade(mm); - /* - * We can free page tables without write-locking mmap_lock because VMAs - * were isolated before we downgraded mmap_lock. - */ - mas_set(mas_detach, 1); - unmap_region(mm, mas_detach, vms->vma, vms->prev, vms->next, - vms->start, vms->end, vms->vma_count, !vms->unlock); + vms_complete_pte_clear(vms, mas_detach, !vms->unlock); /* Update high watermark before we lower total_vm */ update_hiwater_vm(mm); /* Stat accounting */ @@ -746,6 +760,8 @@ int vms_gather_munmap_vmas(struct vma_munmap_struct *vms, goto start_split_failed; } vms->prev = vma_prev(vms->vmi); + if (vms->prev) + vms->unmap_start = vms->prev->vm_end; /* * Detach a range of VMAs from the mm. Using next as a temp variable as @@ -810,6 +826,8 @@ int vms_gather_munmap_vmas(struct vma_munmap_struct *vms, } vms->next = vma_next(vms->vmi); + if (vms->next) + vms->unmap_end = vms->next->vm_start; #if defined(CONFIG_DEBUG_VM_MAPLE_TREE) /* Make sure no VMAs are about to be lost. */ diff --git a/mm/vma.h b/mm/vma.h index c85fc7c888a8..7bc0f9e7751b 100644 --- a/mm/vma.h +++ b/mm/vma.h @@ -38,6 +38,8 @@ struct vma_munmap_struct { struct list_head *uf; /* Userfaultfd list_head */ unsigned long start; /* Aligned start addr (inclusive) */ unsigned long end; /* Aligned end addr (exclusive) */ + unsigned long unmap_start; /* Unmap PTE start */ + unsigned long unmap_end; /* Unmap PTE end */ int vma_count; /* Number of vmas that will be removed */ unsigned long nr_pages; /* Number of pages being removed */ unsigned long locked_vm; /* Number of locked pages */ @@ -108,6 +110,8 @@ static inline void init_vma_munmap(struct vma_munmap_struct *vms, vms->vma_count = 0; vms->nr_pages = vms->locked_vm = vms->nr_accounted = 0; vms->exec_vm = vms->stack_vm = vms->data_vm = 0; + vms->unmap_start = FIRST_USER_ADDRESS; + vms->unmap_end = USER_PGTABLES_CEILING; } int vms_gather_munmap_vmas(struct vma_munmap_struct *vms,