Unbinding ntb_transport can call ntb_transport_free() while ntb_netdev is still bound. The transport frees MWs and QP resources before unregistering the clients, so the netdev's transmit path and timer can access freed memory. Its remove callback also calls ntb_transport_free_queue() on a QP whose resources have already been released. This teardown order is unsafe and somewhat unintuitive. The crash can be reproduced with an intensive TX load, during which you unbind the NTB device. The following is a KASAN report from my VHOST/HOST setup using vNTB. VHOST# sudo iperf3 -ub0 -c $HOST -l 100 -P 100 & VHOST# echo $VHOST_NTB_DEV > /sys/bus/ntb/drivers/ntb_transport/unbind ================================================================== BUG: KASAN: vmalloc-out-of-bounds in ntb_transport_tx_free_entry+0xf0 ... Call trace: ... __asan_report_load4_noabort+0x1c/0x30 ntb_transport_tx_free_entry+0xf0/0x130 [ntb_transport] ntb_netdev_tx_timer+0x78/0x260 [ntb_netdev] ... Disable and drain transport link work first, then unregister the clients so they stop using and release their QPs. After that, free any QPs left over before running transport link cleanup. Disabling the work keeps link events from restarting setup or cleanup during client removal. Fixes: fce8a7bb5b4b ("PCI-Express Non-Transparent Bridge Support") Cc: stable@vger.kernel.org Reviewed-by: Logan Gunthorpe Reviewed-by: Dave Jiang Signed-off-by: Koichiro Den --- Changes in v3: - Add Reviewed-by tag. No code changes. drivers/ntb/ntb_transport.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index af7f240479f4..eef3a214d91a 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1484,9 +1484,11 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev) debugfs_remove_recursive(nt->debugfs_node_dir); - ntb_transport_link_cleanup(nt); - cancel_work_sync(&nt->link_cleanup); - cancel_delayed_work_sync(&nt->link_work); + /* Stop transport work before clients release their QPs. */ + disable_delayed_work_sync(&nt->link_work); + disable_work_sync(&nt->link_cleanup); + + ntb_bus_remove(nt); qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free; @@ -1497,11 +1499,10 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev) ntb_transport_free_queue(qp); } + ntb_transport_link_cleanup(nt); ntb_link_disable(ndev); ntb_clear_ctx(ndev); - ntb_bus_remove(nt); - for (i = nt->mw_count; i--; ) { ntb_free_mw(nt, i); iounmap(nt->mw_vec[i].vbase); -- 2.51.0