Messages in this thread | | | Date | Mon, 4 Jul 2022 12:59:19 +0000 | From | Wedson Almeida Filho <> | Subject | Re: [PATCH] char: misc: make misc_open() and misc_register() killable |
| |
On Mon, Jul 04, 2022 at 09:34:04PM +0900, Tetsuo Handa wrote: > On 2022/07/04 20:01, Greg KH wrote: > > On Mon, Jul 04, 2022 at 07:25:44PM +0900, Tetsuo Handa wrote: > >> On 2022/07/04 16:29, Greg KH wrote: > >>> On Mon, Jul 04, 2022 at 03:44:07PM +0900, Tetsuo Handa wrote: > >>>> syzbot is reporting hung task at misc_open() [1], for snapshot_open() from > >>>> misc_open() might sleep for long with misc_mtx held whereas userspace can > >>>> flood with concurrent misc_open() requests. Mitigate this problem by making > >>>> misc_open() and misc_register() killable. > >>> > >>> I do not understand, why not just fix snapshot_open()? Why add this > >>> complexity to the misc core for a foolish individual misc device? Why > >>> not add the fix there where it is spinning instead? > >> > >> Quoting an example from [1]. Multiple processes are calling misc_open() and > >> all but one processes are blocked at mutex_lock(&misc_mtx). The one which is > >> not blocked at mutex_lock(&misc_mtx) is also holding system_transition_mutex. > > > > And that is because of that one misc device, right? Why not fix that > > instead of papering over the issue in the misc core? > > Since "struct file_operations"->open() is allowed to sleep, calling > "struct file_operations"->open() via reassignment by "struct miscdevice"->fops > with locks held can cause problems. > > Assuming that this is not a deadlock hidden by device_initialize(), current > mutex_lock(&misc_mtx) is as problematic as major_names_lock mentioned at > https://lkml.kernel.org/r/b2af8a5b-3c1b-204e-7f56-bea0b15848d6@i-love.sakura.ne.jp . > > >> If you don't like mutex_lock_killable(&misc_mtx), we will need to consider moving > >> file->f_op->open() from misc_open() to after mutex_unlock(&misc_mtx). > > Below is minimal changes for avoid calling "struct file_operations"->open() with > misc_mtx held. This would be nothing but moving hung task warning from misc_open() > to snapshot_open() (and therefore we would need to introduce killable version of > lock_system_sleep()), but we can avoid making misc_mtx like major_names_lock above. > > Greg, can you accept this minimal change? > > drivers/char/misc.c | 4 ++++ > include/linux/miscdevice.h | 1 + > kernel/power/user.c | 1 + > 3 files changed, 6 insertions(+) > > diff --git a/drivers/char/misc.c b/drivers/char/misc.c > index cba19bfdc44d..292c86c090b9 100644 > --- a/drivers/char/misc.c > +++ b/drivers/char/misc.c > @@ -139,6 +139,10 @@ static int misc_open(struct inode *inode, struct file *file) > > err = 0; > replace_fops(file, new_fops); > + if (iter->unlocked_open && file->f_op->open) { > + mutex_unlock(&misc_mtx); > + return file->f_op->open(inode, file); > + }
One of the invariants of miscdev is that once misc_deregister() returns, no new calls to f_op->open() are made. (Although, of course, you can still have open files but that's a whole different problem.)
This change breaks this invariant which I think is problematic because drivers then can't know when new calls to open() are guaranteed to stop coming.
> if (file->f_op->open) > err = file->f_op->open(inode, file); > fail: > diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h > index 0676f18093f9..e112ef9e3b7b 100644 > --- a/include/linux/miscdevice.h > +++ b/include/linux/miscdevice.h > @@ -86,6 +86,7 @@ struct miscdevice { > const struct attribute_group **groups; > const char *nodename; > umode_t mode; > + bool unlocked_open; > }; > > extern int misc_register(struct miscdevice *misc); > diff --git a/kernel/power/user.c b/kernel/power/user.c > index ad241b4ff64c..69a269c4fb46 100644 > --- a/kernel/power/user.c > +++ b/kernel/power/user.c > @@ -441,6 +441,7 @@ static struct miscdevice snapshot_device = { > .minor = SNAPSHOT_MINOR, > .name = "snapshot", > .fops = &snapshot_fops, > + .unlocked_open = true, > }; > > static int __init snapshot_device_init(void) > -- > 2.34.1 >
| |