[PATCH -next 2/2] scsi: iscsi: Fix use-after-free in iscsi_conn_release() for cleanup_work
Ye Bin <[email protected]>
| Newsgroups | org.kernel.vger.linux-scsi |
|---|---|
| Message-ID | <[email protected]> |
From: Ye Bin <[email protected]> iscsi_conn_error_event() queues conn->cleanup_work without taking a reference to the connection. If the connection's refcount drops to zero while the work is still pending or running, iscsi_conn_release() frees the connection memory without canceling the work, leading to a use-after-free when iscsi_cleanup_conn_work_fn() later dereferences the freed conn struct. This can happen when a session is torn down via iscsi_remove_session(), which calls iscsi_iter_destroy_conn_fn() to remove and drop the final reference on each remaining connection. Unlike iscsi_if_destroy_conn() (which flushes the work) and iscsi_if_stop_conn() (which cancels or flushes the work), the iscsi_iter_destroy_conn_fn() path does not handle the pending cleanup_work before dropping the connection reference. Trigger flow: CPU 0 (error path) CPU 1 (session teardown) ----------------------- -------------------------- iscsi_conn_error_event(conn) queue_work(cleanup_work) [no conn reference taken] iscsi_remove_session() iscsi_iter_destroy_conn_fn() iscsi_remove_conn(conn) iscsi_put_conn(conn) refcount == 0 iscsi_conn_release() kfree(conn) [workqueue picks up work] iscsi_cleanup_conn_work_fn() container_of(work, ...) mutex_lock(&conn->ep_mutex) *** USE-AFTER-FREE *** Fix this by calling cancel_work_sync(&conn->cleanup_work) in iscsi_conn_release() before freeing the connection. This is safe because: - iscsi_conn_release() is always called in process context - iscsi_cleanup_conn_work_fn() never drops a conn reference, so there is no deadlock risk - If the work is running, cancel_work_sync() waits for it to complete before kfree(conn), keeping conn valid during execution - If the work is pending, it is simply canceled, which is harmless since the connection is being destroyed Fixes: 23d6fefbb3f6 ("scsi: iscsi: Fix in-kernel conn failure handling") Signed-off-by: Ye Bin <[email protected]> --- drivers/scsi/scsi_transport_iscsi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index aea319c1e72f..cdc337b0fc26 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2128,6 +2128,13 @@ static void iscsi_conn_release(struct device *dev) struct device *parent = conn->dev.parent; ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n"); + /* + * iscsi_conn_error_event() may have queued conn->cleanup_work without + * holding a reference to the connection. Cancel any pending or + * running work before freeing the connection to prevent a + * use-after-free. + */ + cancel_work_sync(&conn->cleanup_work); kfree(conn); put_device(parent); } -- 2.34.1