lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 08 Mar 2023 10:14:06 +0100
From:   Takashi Iwai <tiwai@...e.de>
To:     Patrik Jakobsson <patrik.r.jakobsson@...il.com>
Cc:     Takashi Iwai <tiwai@...e.de>,
        Thomas Zimmermann <tzimmermann@...e.de>,
        linux-fbdev@...r.kernel.org, Miko Larsson <mikoxyzzz@...il.com>,
        Helge Deller <deller@....de>, linux-kernel@...r.kernel.org,
        dri-devel@...ts.freedesktop.org,
        Patrik Jakobsson <pjakobsson@...e.de>
Subject: Re: [PATCH] fbdev: Fix incorrect page mapping clearance at fb_deferred_io_release()

On Wed, 08 Mar 2023 10:08:24 +0100,
Patrik Jakobsson wrote:
> 
> On Wed, Mar 8, 2023 at 7:36 AM Takashi Iwai <tiwai@...e.de> wrote:
> >
> > The recent fix for the deferred I/O by the commit
> >   3efc61d95259 ("fbdev: Fix invalid page access after closing deferred I/O devices")
> > caused a regression when the same fb device is opened/closed while
> > it's being used.  It resulted in a frozen screen even if something
> > is redrawn there after the close.  The breakage is because the patch
> > was made under a wrong assumption of a single open; in the current
> > code, fb_deferred_io_release() cleans up the page mapping of the
> > pageref list and it calls cancel_delayed_work_sync() unconditionally,
> > where both are no correct behavior for multiple opens.
> >
> > This patch adds a refcount for the opens of the device, and applies
> > the cleanup only when all files get closed.
> >
> > Fixes: 3efc61d95259 ("fbdev: Fix invalid page access after closing deferred I/O devices")
> > Cc: <stable@...r.kernel.org>
> > Signed-off-by: Takashi Iwai <tiwai@...e.de>
> > ---
> >  drivers/video/fbdev/core/fb_defio.c | 16 +++++++++++++---
> >  include/linux/fb.h                  |  1 +
> >  2 files changed, 14 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c
> > index aa5f059d0222..9dcec9e020b6 100644
> > --- a/drivers/video/fbdev/core/fb_defio.c
> > +++ b/drivers/video/fbdev/core/fb_defio.c
> > @@ -305,17 +305,19 @@ void fb_deferred_io_open(struct fb_info *info,
> >                          struct inode *inode,
> >                          struct file *file)
> >  {
> > +       struct fb_deferred_io *fbdefio = info->fbdefio;
> > +
> >         file->f_mapping->a_ops = &fb_deferred_io_aops;
> > +       fbdefio->opens++;
> >  }
> >  EXPORT_SYMBOL_GPL(fb_deferred_io_open);
> >
> > -void fb_deferred_io_release(struct fb_info *info)
> > +static void fb_deferred_io_release_internal(struct fb_info *info)
> 
> Maybe a better name would be fb_deferred_io_lastclose() to be more in
> line with DRM?

Sounds good.

> >  {
> >         struct fb_deferred_io *fbdefio = info->fbdefio;
> >         struct page *page;
> >         int i;
> >
> > -       BUG_ON(!fbdefio);
> 
> Should the BUG_ON be put back into fb_deferred_io_release()?

It can be, but honestly speaking, such a BUG_ON() is utterly useless.
It should be WARN_ON() and return, if the sanity check is inevitably
needed.

> >         cancel_delayed_work_sync(&info->deferred_work);
> >
> >         /* clear out the mapping that we setup */
> > @@ -324,13 +326,21 @@ void fb_deferred_io_release(struct fb_info *info)
> >                 page->mapping = NULL;
> >         }
> >  }
> > +
> > +void fb_deferred_io_release(struct fb_info *info)
> > +{
> > +       struct fb_deferred_io *fbdefio = info->fbdefio;
> > +
> > +       if (!--fbdefio->opens)
> > +               fb_deferred_io_release_internal(info);
> 
> I think this can race so we need locking.

This one is fine, as it's always called inside the fb lock in the
caller side.  Maybe worth to comment in the code.

> > +}
> >  EXPORT_SYMBOL_GPL(fb_deferred_io_release);
> >
> >  void fb_deferred_io_cleanup(struct fb_info *info)
> >  {
> >         struct fb_deferred_io *fbdefio = info->fbdefio;
> >
> > -       fb_deferred_io_release(info);
> > +       fb_deferred_io_release_internal(info);
> >
> >         kvfree(info->pagerefs);
> >         mutex_destroy(&fbdefio->lock);
> > diff --git a/include/linux/fb.h b/include/linux/fb.h
> > index d8d20514ea05..29674a29d1c4 100644
> > --- a/include/linux/fb.h
> > +++ b/include/linux/fb.h
> > @@ -212,6 +212,7 @@ struct fb_deferred_io {
> >         /* delay between mkwrite and deferred handler */
> >         unsigned long delay;
> >         bool sort_pagereflist; /* sort pagelist by offset */
> > +       int opens; /* number of opened files */
> 
> I would prefer the name num_opens (or open_count as in DRM) instead of
> opens since it can be interpreted as a verb.

I don't mind either way.  I'd choose the latter.

> Also, don't we need it to be atomic_t?

It's always in the fb lock, so that should be fine with the standard
int.


thanks,

Takashi

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ