tty: hvc: possible use-after-free in resize work during hvc_remove()

From: LI xiao

Date: Mon Oct 19 2026 - 06:11:28 EST


Hi,

I found a possible use-after-free involving the HVC resize work.

A queued hvc_set_winsz() can access hp after hvc_remove() drops the final tty_port reference and hvc_port_destruct() frees the containing hvc_struct.

I reproduced this on Linux mainline commit c03c1a14507dfaf8b856c2608f9ac216021fc222, using a KASAN-enabled x86_64 kernel in a 2-vCPU QEMU guest.

The reproducer is an out-of-tree test module whose removal thread calls hvc_remove() concurrently with a queued hvc_resize() operation. KASAN reports that the queued hvc_set_winsz() work accesses the freed HVC object. This reproduces the HVC API-level lifetime issue, but does not yet exercise the full virtio-console hot-unplug path.

Relevant KASAN report:

BUG: KASAN: slab-use-after-free in tty_port_tty_get+0xa8/0xb0
Read of size 8 at addr ff1100000a55a488 by task kworker/0:0/9
Workqueue: events hvc_set_winsz
Call Trace:
tty_port_tty_get+0xa8/0xb0
hvc_set_winsz+0x6e/0x110
process_one_work+0x68c/0x1180
worker_thread+0x4b7/0xb30

Allocated by task 64:
__kmalloc_noprof+0x1cd/0x4a0
hvc_alloc+0x2e1/0xa20
hvc_lifetime_repro_init+0x60/0xff0 [hvc_lifetime_repro]

Freed by task 66:
kfree+0x127/0x3b0
hvc_remove+0xea/0x150
remove_hvc_port+0x1c/0x40 [hvc_lifetime_repro]

The reproducer also captured the following work-queueing stack:

__queue_work+0x70d/0x11f0
queue_work_on+0x59/0x60
hvc_lifetime_repro_init+0x10d/0xff0 [hvc_lifetime_repro]

KASAN also reported a write to the same freed object while the callback was executing:

BUG: KASAN: slab-use-after-free in
_raw_spin_unlock_irqrestore+0x66/0x80
Write of size 1 at addr ff1100000a55a4a8 by task kworker/0:0/9
Workqueue: events hvc_set_winsz
Call Trace:
_raw_spin_unlock_irqrestore+0x66/0x80
tty_port_tty_get+0x77/0xb0
hvc_set_winsz+0x6e/0x110
process_one_work+0x68c/0x1180
worker_thread+0x4b7/0xb30

The object was allocated from kmalloc-512, and the reported read was 136 bytes into the freed 512-byte region.

The reproducer requires root privileges to load its out-of-tree module, which taints the kernel.

Could you confirm whether this is a valid bug?

Thanks,
LI Xiao