Messages in this thread Patch in this message | | | Date | Mon, 4 Jul 2022 15:44:07 +0900 | Subject | [PATCH] char: misc: make misc_open() and misc_register() killable | From | Tetsuo Handa <> |
| |
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.
Link: https://syzkaller.appspot.com/bug?extid=358c9ab4c93da7b7238c [1] Reported-by: syzbot <syzbot+358c9ab4c93da7b7238c@syzkaller.appspotmail.com> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> --- drivers/char/misc.c | 57 +++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 33 deletions(-)
diff --git a/drivers/char/misc.c b/drivers/char/misc.c index cba19bfdc44d..b9a494bc4228 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -100,49 +100,39 @@ static const struct seq_operations misc_seq_ops = { static int misc_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct miscdevice *c = NULL, *iter; + struct miscdevice *iter; int err = -ENODEV; const struct file_operations *new_fops = NULL; + bool retried = false; - mutex_lock(&misc_mtx); - + retry: + if (mutex_lock_killable(&misc_mtx)) + return -EINTR; list_for_each_entry(iter, &misc_list, list) { if (iter->minor != minor) continue; - c = iter; new_fops = fops_get(iter->fops); + if (!new_fops) + break; + /* + * Place the miscdevice in the file's + * private_data so it can be used by the + * file operations, including f_op->open below + */ + file->private_data = iter; + + err = 0; + replace_fops(file, new_fops); + if (file->f_op->open) + err = file->f_op->open(inode, file); break; } - - if (!new_fops) { - mutex_unlock(&misc_mtx); + mutex_unlock(&misc_mtx); + if (!new_fops && !retried) { request_module("char-major-%d-%d", MISC_MAJOR, minor); - mutex_lock(&misc_mtx); - - list_for_each_entry(iter, &misc_list, list) { - if (iter->minor != minor) - continue; - c = iter; - new_fops = fops_get(iter->fops); - break; - } - if (!new_fops) - goto fail; + retried = true; + goto retry; } - - /* - * Place the miscdevice in the file's - * private_data so it can be used by the - * file operations, including f_op->open below - */ - file->private_data = c; - - err = 0; - replace_fops(file, new_fops); - if (file->f_op->open) - err = file->f_op->open(inode, file); -fail: - mutex_unlock(&misc_mtx); return err; } @@ -180,7 +170,8 @@ int misc_register(struct miscdevice *misc) INIT_LIST_HEAD(&misc->list); - mutex_lock(&misc_mtx); + if (mutex_lock_killable(&misc_mtx)) + return -EINTR; if (is_dynamic) { int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); -- 2.18.4
| |