[SRU][F][PATCH 1/1] UBUNTU: SAUCE: overlayfs: fix reference count mismatch

Aleksandr Mikhalitsyn aleksandr.mikhalitsyn at canonical.com
Thu Jun 29 09:33:50 UTC 2023


On Thu, Jun 29, 2023 at 8:03 AM Andrea Righi <andrea.righi at canonical.com> wrote:
>
> On Wed, Jun 28, 2023 at 05:32:21PM +0200, Aleksandr Mikhalitsyn wrote:
> > On Thu, Jun 22, 2023 at 11:38 AM Andrea Righi
> > <andrea.righi at canonical.com> wrote:
> > >
> > > BugLink: https://bugs.launchpad.net/bugs/2016398
> > >
> > > Opened files reported in /proc/pid/map_files can be shows with the wrong
> > > mount point using overlayfs with filesystem namspaces.
> > >
> > > This incorrect behavior is fixed:
> > >
> > >   UBUNTU: SAUCE: overlayfs: fix incorrect mnt_id of files opened from map_files
> > >
> > > However, the fix introduced a new regression, the reference to the
> > > original file stored in vma->vm_prfile is not properly released when
> > > vma->vm_prfile is replaced with a new file.
> > >
> > > This can cause a reference counter unbalance, leading errors such as
> > > "target is busy" when trying to unmount overlayfs, even if the
> > > filesystem has not active reference.
> > >
> > > Fix by properly releasing the original file stored in vm_prfile.
> > >
> > > Fixes: 508fdae3f62dd ("UBUNTU: SAUCE: overlayfs: fix incorrect mnt_id of files opened from map_files")
> > > Signed-off-by: Andrea Righi <andrea.righi at canonical.com>
> > > ---
> > >  fs/overlayfs/file.c | 59 +++++++++++++++++++++++++++------------------
> > >  1 file changed, 36 insertions(+), 23 deletions(-)
> > >
> > > diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
> > > index 366a4267d5f8..565010d2c9dd 100644
> > > --- a/fs/overlayfs/file.c
> > > +++ b/fs/overlayfs/file.c
> > > @@ -373,17 +373,48 @@ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
> > >         return ret;
> > >  }
> > >
> > > -/* handle vma->vm_prfile */
> > > +/*
> > > + * In map_files_get_link() (fs/proc/base.c)
> > > + * we need to determine correct path from overlayfs.
> > > + * But real_mount(realfile->f_path.mnt) may be not
> > > + * equal to real_mount(file->f_path.mnt). In such case
> > > + * fdinfo of the same file which was opened from
> > > + * /proc/<pid>/map_files/... and "usual" path
> > > + * will show different mnt_id.
> > > + *
> > > + * We solve issue like in aufs by using additional
> > > + * field on struct vm_area_struct called "vm_prfile"
> > > + * which is used only for fdinfo/"printing" needs.
> > > + *
> > > + * See also mm/prfile.c
> > > + */
> > > +#ifdef CONFIG_MMU
> > >  static void ovl_vm_prfile_set(struct vm_area_struct *vma,
> > >                               struct file *file)
> > >  {
> > >         get_file(file);
> > > -       vma->vm_prfile = file;
> > > -#ifndef CONFIG_MMU
> > > +       swap(vma->vm_prfile, file);
> > > +       /* Drop reference count from previous file value */
> > > +       if (file)
> > > +               fput(file);
> > > +}
> > > +#else
> > > +static void ovl_vm_prfile_set(struct vm_area_struct *vma,
> > > +                             struct file *file)
> > > +{
> > > +       struct file *vm_region_file = file;
> > > +
> > >         get_file(file);
> > > -       vma->vm_region->vm_prfile = file;
> > > -#endif
> > > +       get_file(vm_region_file);
> > > +       swap(vma->vm_prfile, file);
> > > +       swap(vma->vm_region->vm_prfile, vm_region_file);
> > > +       /* Drop reference count from previous file values */
> > > +       if (file)
> > > +               fput(file);
> > > +       if (vm_region_file)
> > > +               fput(vm_region_file);
> > >  }
> > > +#endif
> > >
> > >  static int ovl_mmap(struct file *file, struct vm_area_struct *vma)
> > >  {
> > > @@ -411,25 +442,7 @@ static int ovl_mmap(struct file *file, struct vm_area_struct *vma)
> > >                 vma->vm_file = file;
> > >                 fput(realfile);
> > >         } else {
> > > -               /*
> > > -                * In map_files_get_link() (fs/proc/base.c)
> > > -                * we need to determine correct path from overlayfs.
> > > -                * But real_mount(realfile->f_path.mnt) may be not
> > > -                * equal to real_mount(file->f_path.mnt). In such case
> > > -                * fdinfo of the same file which was opened from
> > > -                * /proc/<pid>/map_files/... and "usual" path
> > > -                * will show different mnt_id.
> > > -                *
> > > -                * We solve issue like in aufs by using additional
> > > -                * field on struct vm_area_struct called "vm_prfile"
> > > -                * which is used only for fdinfo/"printing" needs.
> > > -                *
> > > -                * See also mm/prfile.c
> > > -                */
> > >                 ovl_vm_prfile_set(vma, file);
> > > -
> > > -               /* Drop reference count from previous vm_file value */
> > > -               fput(file);
> >
> > I'm not sure that we need to touch this line because it is not from
> > the Ubuntu Sauce patch, but from the original Linux kernel tree.
> > Removing it can cause a leak.
>
> That line is not from the SAUCE patch, but before my change
> ovl_vm_prfile_set() wasn't doing an fput(file). Now that
> ovl_vm_prfile_set() is also taking care of doing fput(file), I think we
> need to remove that line, otherwise we would release the file twice.

fput inside ovl_vm_prfile_set releases the struct file that was in
vma->vm_prfile (if it is not NULL),
but this fput(file) is not about that. It releases and an old struct
file reference that was in vma->vm_file
when ovl_mmap() was called. This reference was taken in mmap_region()
just before the call_mmap() call.
So, as in ovl_mmap we replace vma->vm_file with a new one, we need to
release an old reference.

Please note, that vma->vm_file != vma->vm_prfile.

Kind regards,
Alex

>
> -Andrea



More information about the kernel-team mailing list