lkml.org 
[lkml]   [2021]   [Nov]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 161/355] nvmet-tcp: fix use-after-free when a port is removed
    Date
    From: Israel Rukshin <israelr@nvidia.com>

    [ Upstream commit 2351ead99ce9164fb42555aee3f96af84c4839e9 ]

    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 <israelr@nvidia.com>
    Reviewed-by: Max Gurtovoy <mgurtovoy@nvidia.com>
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/nvme/target/tcp.c | 16 ++++++++++++++++
    1 file changed, 16 insertions(+)

    diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
    index 6b3d1ba7db7ee..fac1985870765 100644
    --- a/drivers/nvme/target/tcp.c
    +++ b/drivers/nvme/target/tcp.c
    @@ -1667,6 +1667,17 @@ err_port:
    return ret;
    }

    +static void nvmet_tcp_destroy_port_queues(struct nvmet_tcp_port *port)
    +{
    + struct nvmet_tcp_queue *queue;
    +
    + mutex_lock(&nvmet_tcp_queue_mutex);
    + list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list)
    + if (queue->port == port)
    + kernel_sock_shutdown(queue->sock, SHUT_RDWR);
    + mutex_unlock(&nvmet_tcp_queue_mutex);
    +}
    +
    static void nvmet_tcp_remove_port(struct nvmet_port *nport)
    {
    struct nvmet_tcp_port *port = nport->priv;
    @@ -1676,6 +1687,11 @@ static void nvmet_tcp_remove_port(struct nvmet_port *nport)
    port->sock->sk->sk_user_data = NULL;
    write_unlock_bh(&port->sock->sk->sk_callback_lock);
    cancel_work_sync(&port->accept_work);
    + /*
    + * Destroy the remaining queues, which are not belong to any
    + * controller yet.
    + */
    + nvmet_tcp_destroy_port_queues(port);

    sock_release(port->sock);
    kfree(port);
    --
    2.33.0


    \
     
     \ /
      Last update: 2021-11-15 18:47    [W:4.336 / U:0.192 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site