Skip to content

Commit 0703920

Browse files
israelrugregkh
authored andcommitted
nvmet-tcp: fix use-after-free when a port is removed
[ Upstream commit 2351ead ] When removing a port, all its controllers are being removed, but there are queues on the port that doesn't belong to any controller (during connection time). This causes a use-after-free bug for any command that dereferences req->port (like in nvmet_alloc_ctrl). Those queues should be destroyed before freeing the port via configfs. Destroy the remaining queues after the accept_work was cancelled guarantees that no new queue will be created. Signed-off-by: Israel Rukshin <[email protected]> Reviewed-by: Max Gurtovoy <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 3c82292 commit 0703920

File tree

1 file changed

+16
-0
lines changed

1 file changed

+16
-0
lines changed

drivers/nvme/target/tcp.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,17 @@ static int nvmet_tcp_add_port(struct nvmet_port *nport)
17401740
return ret;
17411741
}
17421742

1743+
static void nvmet_tcp_destroy_port_queues(struct nvmet_tcp_port *port)
1744+
{
1745+
struct nvmet_tcp_queue *queue;
1746+
1747+
mutex_lock(&nvmet_tcp_queue_mutex);
1748+
list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list)
1749+
if (queue->port == port)
1750+
kernel_sock_shutdown(queue->sock, SHUT_RDWR);
1751+
mutex_unlock(&nvmet_tcp_queue_mutex);
1752+
}
1753+
17431754
static void nvmet_tcp_remove_port(struct nvmet_port *nport)
17441755
{
17451756
struct nvmet_tcp_port *port = nport->priv;
@@ -1749,6 +1760,11 @@ static void nvmet_tcp_remove_port(struct nvmet_port *nport)
17491760
port->sock->sk->sk_user_data = NULL;
17501761
write_unlock_bh(&port->sock->sk->sk_callback_lock);
17511762
cancel_work_sync(&port->accept_work);
1763+
/*
1764+
* Destroy the remaining queues, which are not belong to any
1765+
* controller yet.
1766+
*/
1767+
nvmet_tcp_destroy_port_queues(port);
17521768

17531769
sock_release(port->sock);
17541770
kfree(port);

0 commit comments

Comments
 (0)