| From 153f4a9bdf93ce12e1a93b9e2562e84a8b849c4f Mon Sep 17 00:00:00 2001 |
| From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
| Date: Sun, 17 Mar 2019 14:02:31 +0900 |
| Subject: kobject: Don't trigger kobject_uevent(KOBJ_REMOVE) twice. |
| |
| [ Upstream commit c03a0fd0b609e2f5c669c2b7f27c8e1928e9196e ] |
| |
| syzbot is hitting use-after-free bug in uinput module [1]. This is because |
| kobject_uevent(KOBJ_REMOVE) is called again due to commit 0f4dafc0563c6c49 |
| ("Kobject: auto-cleanup on final unref") after memory allocation fault |
| injection made kobject_uevent(KOBJ_REMOVE) from device_del() from |
| input_unregister_device() fail, while uinput_destroy_device() is expecting |
| that kobject_uevent(KOBJ_REMOVE) is not called after device_del() from |
| input_unregister_device() completed. |
| |
| That commit intended to catch cases where nobody even attempted to send |
| "remove" uevents. But there is no guarantee that an event will ultimately |
| be sent. We are at the point of no return as far as the rest of the kernel |
| is concerned; there are no repeats or do-overs. |
| |
| Also, it is not clear whether some subsystem depends on that commit. |
| If no subsystem depends on that commit, it will be better to remove |
| the state_{add,remove}_uevent_sent logic. But we don't want to risk |
| a regression (in a patch which will be backported) by trying to remove |
| that logic. Therefore, as a first step, let's avoid the use-after-free bug |
| by making sure that kobject_uevent(KOBJ_REMOVE) won't be triggered twice. |
| |
| [1] https://syzkaller.appspot.com/bug?id=8b17c134fe938bbddd75a45afaa9e68af43a362d |
| |
| Reported-by: syzbot <syzbot+f648cfb7e0b52bf7ae32@syzkaller.appspotmail.com> |
| Analyzed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| Fixes: 0f4dafc0563c6c49 ("Kobject: auto-cleanup on final unref") |
| Cc: Kay Sievers <kay@vrfy.org> |
| Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| lib/kobject_uevent.c | 11 +++++++---- |
| 1 file changed, 7 insertions(+), 4 deletions(-) |
| |
| diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c |
| index f05802687ba4d..7998affa45d49 100644 |
| --- a/lib/kobject_uevent.c |
| +++ b/lib/kobject_uevent.c |
| @@ -466,6 +466,13 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, |
| int i = 0; |
| int retval = 0; |
| |
| + /* |
| + * Mark "remove" event done regardless of result, for some subsystems |
| + * do not want to re-trigger "remove" event via automatic cleanup. |
| + */ |
| + if (action == KOBJ_REMOVE) |
| + kobj->state_remove_uevent_sent = 1; |
| + |
| pr_debug("kobject: '%s' (%p): %s\n", |
| kobject_name(kobj), kobj, __func__); |
| |
| @@ -567,10 +574,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, |
| kobj->state_add_uevent_sent = 1; |
| break; |
| |
| - case KOBJ_REMOVE: |
| - kobj->state_remove_uevent_sent = 1; |
| - break; |
| - |
| case KOBJ_UNBIND: |
| zap_modalias_env(env); |
| break; |
| -- |
| 2.20.1 |
| |