Message ID | 20201117132751.14863-1-yangyingliang@huawei.com |
---|---|
State | New |
Headers | show |
Series | Input: sunkbd - fix UAF in sunkbd_reinit() | expand |
Hi Yang, On Tue, Nov 17, 2020 at 09:27:51PM +0800, Yang Yingliang wrote: > > After sunkbd->tq is added to workqueue, before scheduled work finish, sunkbd is > freed by sunkbd_disconnect(), when sunkbd is used in sunkbd_reinit(), it causes > a UAF. Fix this by calling flush_scheduled_work() before free sunkbd. > > This fixes CVE-2020-25669. > > Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> > --- > drivers/input/keyboard/sunkbd.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c > index 27126e621eb6..b6222896acdf 100644 > --- a/drivers/input/keyboard/sunkbd.c > +++ b/drivers/input/keyboard/sunkbd.c > @@ -316,6 +316,7 @@ static void sunkbd_disconnect(struct serio *serio) > { > struct sunkbd *sunkbd = serio_get_drvdata(serio); > > + flush_scheduled_work(); This is unfortunately racy as we may get interrupt and reschedule the work again before we get to disabling the port. It is properly fixed by 77e70d351db7de07a46ac49b87a6c3c7a60fca7e. > sunkbd_enable(sunkbd, false); > input_unregister_device(sunkbd->dev); > serio_close(serio); > -- > 2.17.1 > Thanks. -- Dmitry
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 27126e621eb6..b6222896acdf 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -316,6 +316,7 @@ static void sunkbd_disconnect(struct serio *serio) { struct sunkbd *sunkbd = serio_get_drvdata(serio); + flush_scheduled_work(); sunkbd_enable(sunkbd, false); input_unregister_device(sunkbd->dev); serio_close(serio);
According the PoC in link: https://www.openwall.com/lists/oss-security/2020/11/05/2 Here is UAF log: [ 235.504246] ================================================================== [ 235.508297] BUG: KASAN: use-after-free in __lock_acquire+0x2c75/0x34e0 [ 235.511906] Read of size 8 at addr ffff88812d4754f0 by task kworker/2:1/124 [ 235.515752] [ 235.516641] CPU: 2 PID: 124 Comm: kworker/2:1 Not tainted 5.10.0-rc4 #1169 [ 235.520390] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.13.0-48-gd9c812dda519-prebuilt.qemu.org 04/01/2014 [ 235.526648] Workqueue: events sunkbd_reinit [ 235.528869] Call Trace: [ 235.530140] dump_stack+0xe6/0x136 [ 235.531881] ? __lock_acquire+0x2c75/0x34e0 [ 235.533954] print_address_description.constprop.8+0x3e/0x60 [ 235.536781] ? rcu_read_lock_bh_held+0xc0/0xc0 [ 235.539005] ? vprintk_func+0xaf/0x1b0 [ 235.540830] ? __lock_acquire+0x2c75/0x34e0 [ 235.542709] ? __lock_acquire+0x2c75/0x34e0 [ 235.544613] kasan_report.cold.10+0x1f/0x37 [ 235.546506] ? __lock_acquire+0x2c75/0x34e0 [ 235.548410] __lock_acquire+0x2c75/0x34e0 [ 235.550241] ? lock_is_held_type+0xae/0xe0 [ 235.552130] ? rcu_read_lock_sched_held+0xaf/0xe0 [ 235.554237] ? rcu_read_lock_bh_held+0xc0/0xc0 [ 235.556239] lock_acquire+0x19c/0x8f0 [ 235.557908] ? prepare_to_wait_event+0x73/0x660 [ 235.559946] ? rcu_read_unlock+0x50/0x50 [ 235.561715] ? del_timer_sync+0xe3/0x130 [ 235.563548] ? schedule_timeout+0x43b/0x950 [ 235.565278] _raw_spin_lock_irqsave+0x43/0x60 [ 235.567047] ? prepare_to_wait_event+0x73/0x660 [ 235.568910] prepare_to_wait_event+0x73/0x660 [ 235.570701] ? __next_timer_interrupt+0x1b0/0x1b0 [ 235.572647] ? wait_woken+0x280/0x280 [ 235.574187] sunkbd_reinit+0x579/0x700 [ 235.575744] ? sunkbd_event+0x3d0/0x3d0 [ 235.577189] ? finish_wait+0x280/0x280 [ 235.578623] ? rcu_read_lock_bh_held+0xc0/0xc0 [ 235.580303] ? lockdep_hardirqs_on_prepare+0x294/0x3e0 [ 235.582253] process_one_work+0x8ef/0x1560 [ 235.583815] ? pwq_dec_nr_in_flight+0x330/0x330 [ 235.585537] ? do_raw_spin_lock+0x126/0x290 [ 235.587133] worker_thread+0x91/0xc30 [ 235.588601] ? process_one_work+0x1560/0x1560 [ 235.590233] kthread+0x37a/0x450 [ 235.591487] ? _raw_spin_unlock_irq+0x24/0x40 [ 235.593131] ? kthread_mod_delayed_work+0x190/0x190 [ 235.594965] ret_from_fork+0x22/0x30 [ 235.596346] [ 235.596945] Allocated by task 85: [ 235.598200] kasan_save_stack+0x19/0x40 [ 235.599685] __kasan_kmalloc.constprop.13+0xc1/0xd0 [ 235.601389] kmem_cache_alloc_trace+0x11b/0x1d0 [ 235.602969] sunkbd_connect+0xa7/0x10e0 [ 235.604330] serio_connect_driver+0x50/0x70 [ 235.605810] really_probe+0x287/0xd90 [ 235.607102] driver_probe_device+0x267/0x3d0 [ 235.608611] __device_attach_driver+0x1cc/0x280 [ 235.610209] bus_for_each_drv+0x154/0x1d0 [ 235.611638] __device_attach+0x234/0x3a0 [ 235.612912] bus_probe_device+0x1dd/0x290 [ 235.614223] device_add+0xc5f/0x1880 [ 235.615415] serio_handle_event+0x4ae/0x8f0 [ 235.616788] process_one_work+0x8ef/0x1560 [ 235.618124] worker_thread+0x91/0xc30 [ 235.619351] kthread+0x37a/0x450 [ 235.620427] ret_from_fork+0x22/0x30 [ 235.621582] [ 235.622097] Freed by task 2609: [ 235.623130] kasan_save_stack+0x19/0x40 [ 235.624396] kasan_set_track+0x1c/0x30 [ 235.625612] kasan_set_free_info+0x1b/0x30 [ 235.626944] __kasan_slab_free+0x111/0x160 [ 235.628282] slab_free_freelist_hook+0x5a/0x150 [ 235.629754] kfree+0xe5/0x660 [ 235.630731] serio_disconnect_driver+0x78/0xa0 [ 235.632187] serio_driver_remove+0x1a/0x20 [ 235.633537] device_release_driver_internal+0x239/0x520 [ 235.635250] serio_unregister_port+0x24/0x40 [ 235.636634] serport_ldisc_read+0x416/0x5f0 [ 235.638008] tty_read+0x17d/0x270 [ 235.639096] vfs_read+0x156/0x4c0 [ 235.640203] ksys_read+0x104/0x200 [ 235.641318] do_syscall_64+0x33/0x40 [ 235.642475] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 235.644099] [ 235.644631] The buggy address belongs to the object at ffff88812d475400 [ 235.644631] which belongs to the cache kmalloc-512 of size 512 [ 235.648610] The buggy address is located 240 bytes inside of [ 235.648610] 512-byte region [ffff88812d475400, ffff88812d475600) [ 235.652304] The buggy address belongs to the page: [ 235.653862] page:(____ptrval____) refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x12d470 [ 235.656841] head:(____ptrval____) order:3 compound_mapcount:0 compound_pincount:0 [ 235.659232] flags: 0x2fffff80010200(slab|head) [ 235.660688] raw: 002fffff80010200 dead000000000100 dead000000000122 ffff8881000432c0 [ 235.663141] raw: 0000000000000000 0000000000200020 00000001ffffffff 0000000000000000 [ 235.665605] page dumped because: kasan: bad access detected [ 235.667390] [ 235.667898] Memory state around the buggy address: [ 235.669433] ffff88812d475380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 235.671755] ffff88812d475400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 235.674072] >ffff88812d475480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 235.676390] ^ [ 235.678576] ffff88812d475500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 235.680880] ffff88812d475580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 235.683221] ================================================================== After sunkbd->tq is added to workqueue, before scheduled work finish, sunkbd is freed by sunkbd_disconnect(), when sunkbd is used in sunkbd_reinit(), it causes a UAF. Fix this by calling flush_scheduled_work() before free sunkbd. This fixes CVE-2020-25669. Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> --- drivers/input/keyboard/sunkbd.c | 1 + 1 file changed, 1 insertion(+)