
hulk inclusion category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/ICPTGF CVE: NA -------------------------------- kmemleak_scan_thread() invokes scan_block() which may invoke a nomal printk() to print warning message. This can cause a deadlock in the scenario reported below: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(kmemleak_lock); lock(&(&port->lock)->rlock); lock(kmemleak_lock); lock(console_owner); To solve this problem, switch to printk_safe mode before printing warning message, this will redirect all printk()-s to a special per-CPU buffer, which will be flushed later from a safe context (irq work), and this deadlock problem can be avoided. Our syztester report the following lockdep error: ====================================================== WARNING: possible circular locking dependency detected 4.19.90-00049-g58693b1f5fa8-dirty #3 Tainted: G O ------------------------------------------------------ systemd-journal/150 is trying to acquire lock: 00000000ef13bd01 (console_owner){-...}, at: vprintk_emit+0x252/0x420 but task is already holding lock: 0000000078c4087b (kmemleak_lock){-.-.}, at: find_and_remove_object+0x1d/0x120 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #3 (kmemleak_lock){-.-.}: _raw_write_lock_irqsave+0x3a/0x50 create_object+0x435/0x960 __kmalloc+0x243/0x310 __tty_buffer_request_room+0x1bc/0x580 tty_insert_flip_string_fixed_flag+0x91/0x1c0 tty_insert_flip_string_and_push_buffer+0x43/0x160 pty_write+0xc8/0xf0 do_output_char+0x500/0x770 n_tty_write+0x43c/0xeb0 tty_write+0x3d9/0x6d0 __vfs_write+0xfe/0x690 vfs_write+0x16d/0x490 ksys_write+0x106/0x250 do_syscall_64+0xfa/0xee0 entry_SYSCALL_64_after_hwframe+0x61/0xd6 -> #2 (&(&port->lock)->rlock){-.-.}: _raw_spin_lock_irqsave+0x3a/0x50 tty_port_tty_get+0x22/0x90 tty_port_default_wakeup+0x16/0x40 serial8250_tx_chars+0x415/0xab0 serial8250_handle_irq.part.0+0x2d4/0x390 serial8250_default_handle_irq+0xa1/0x110 serial8250_interrupt+0xfe/0x220 __handle_irq_event_percpu+0xf5/0x680 handle_irq_event_percpu+0x7b/0x150 handle_irq_event+0xa6/0x131 handle_edge_irq+0x220/0x830 handle_irq+0x40/0x60 do_IRQ+0x84/0x1c0 ret_from_intr+0x0/0x1d -> #1 (&port_lock_key){-.-.}: _raw_spin_lock_irqsave+0x3a/0x50 serial8250_console_write+0x424/0x860 console_unlock+0x6ab/0xc70 register_console+0x5bd/0x9f0 univ8250_console_init+0x34/0x3f console_init+0x398/0x549 start_kernel+0x443/0x7a0 secondary_startup_64+0xb6/0xc0 -> #0 (console_owner){-...}: lock_acquire+0x109/0x300 vprintk_emit+0x28f/0x420 vprintk_func+0x5d/0x157 printk+0xbf/0xf2 lookup_object.cold+0x3d/0x64 find_and_remove_object+0x2b/0x120 delete_object_full+0xc/0x20 kmem_cache_free+0x1d5/0x2b0 putname+0xd2/0x110 do_sys_open+0x21e/0x440 do_syscall_64+0xfa/0xee0 entry_SYSCALL_64_after_hwframe+0x61/0xd6 other info that might help us debug this: Chain exists of: console_owner --> &(&port->lock)->rlock --> kmemleak_lock Signed-off-by: Gu Bowen <gubowen5@huawei.com> --- mm/kmemleak.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index f54734abf946..5c90c54529a7 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -423,9 +423,16 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias) else if (object->pointer == ptr || alias) return object; else { + /* + * Printk deferring due to the kmemleak_lock held. + * This is done to avoid deadlock. + */ + printk_safe_enter(); kmemleak_warn("Found object by alias at 0x%08lx\n", ptr); dump_object_info(object); + printk_safe_exit(); + break; } } -- 2.25.1