On Tue, Feb 22, 2022 at 12:06 AM Michal Hocko <mhocko@xxxxxxxx> wrote: > > On Mon 21-02-22 21:40:25, Suren Baghdasaryan wrote: > > When adjacent vmas are being merged it can result in the vma that was > > originally passed to madvise_update_vma being destroyed. In the current > > implementation, the name parameter passed to madvise_update_vma points > > directly to vma->anon_name->name and it is used after the call to > > vma_merge. In the cases when vma_merge merges the original vma and > > destroys it, this will result in use-after-free bug as shown below: > > > > madvise_vma_behavior << passes vma->anon_name->name as name param > > madvise_update_vma(name) > > vma_merge > > __vma_adjust > > vm_area_free <-- frees the vma > > replace_vma_anon_name(name) <-- UAF > > This seems to be stale because bare const char pointer is not passed in > the call chain. In fact I am not even sure there is any actual UAF here > after the rework. > Could you be more specific in describing the scenario? Yes, sorry, I need to update the part of the description talking about passing vma->anon_name->name directly. I think UAF is still there, it's just harder to reproduce (admittedly I could not reproduce it with the previous reproducer). The scenario would be when a vma with vma->anon_name->kref == 1 is being merged with another one and freed in the process: madvise_vma_behavior anon_name = vma_anon_name(vma) <-- does not increase refcount madvise_update_vma(anon_name) *prev = vma_merge <-- returns another vma __vma_adjust vm_area_free(vma) free_vma_anon_name anon_vma_name_put vma_anon_name_free <-- frees the vma->anon_name vma = *prev <-- original vma was freed replace_vma_anon_name(vma, >>anon_name<<) <-- UAF Does this make sense or did I miss something? Thanks, Suren. > > > Fix this by raising the name refcount and stabilizing it. > > > > Fixes: 9a10064f5625 ("mm: add a field to store names for private anonymous memory") > > Signed-off-by: Suren Baghdasaryan <surenb@xxxxxxxxxx> > > Reported-by: syzbot+aa7b3d4b35f9dc46a366@xxxxxxxxxxxxxxxxxxxxxxxxx > > --- > > changes in v3: > > - Reapplied the fix after code refactoring, per Michal Hocko > > > > mm/madvise.c | 4 ++++ > > 1 file changed, 4 insertions(+) > > > > diff --git a/mm/madvise.c b/mm/madvise.c > > index a395884aeecb..00e8105430e9 100644 > > --- a/mm/madvise.c > > +++ b/mm/madvise.c > > @@ -140,6 +140,8 @@ static int replace_vma_anon_name(struct vm_area_struct *vma, > > /* > > * Update the vm_flags on region of a vma, splitting it or merging it as > > * necessary. Must be called with mmap_sem held for writing; > > + * Caller should ensure anon_name stability by raising its refcount even when > > + * anon_name belongs to a valid vma because this function might free that vma. > > */ > > static int madvise_update_vma(struct vm_area_struct *vma, > > struct vm_area_struct **prev, unsigned long start, > > @@ -1021,8 +1023,10 @@ static int madvise_vma_behavior(struct vm_area_struct *vma, > > } > > > > anon_name = vma_anon_name(vma); > > + anon_vma_name_get(anon_name); > > error = madvise_update_vma(vma, prev, start, end, new_flags, > > anon_name); > > + anon_vma_name_put(anon_name); > > > > out: > > /* > > -- > > 2.35.1.473.g83b2b277ed-goog > > -- > Michal Hocko > SUSE Labs