diff options
author | Maor Gottlieb <maorg@nvidia.com> | 2020-10-12 07:56:00 +0300 |
---|---|---|
committer | Jason Gunthorpe <jgg@nvidia.com> | 2020-10-16 14:07:08 -0300 |
commit | c7a198c700763ac89abbb166378f546aeb9afb33 (patch) | |
tree | 7a6f45e11a3c4dfc92d0d6194e0d008877ca8ee3 /drivers/infiniband/core | |
parent | 71abf20b28ff87fee6951ec2218d5ce7969c4e87 (diff) |
RDMA/ucma: Fix use after free in destroy id flow
ucma_free_ctx() should call to __destroy_id() on all the connection requests
that have not been delivered to user space. Currently it calls on the
context itself and cause to use after free.
Fixes the trace:
BUG: Unable to handle kernel data access on write at 0x5deadbeef0000108
Faulting instruction address: 0xc0080000002428f4
Oops: Kernel access of bad area, sig: 11 [#1]
Call Trace:
[c000000207f2b680] [c00800000024280c] .__destroy_id+0x28c/0x610 [rdma_ucm] (unreliable)
[c000000207f2b750] [c0080000002429c4] .__destroy_id+0x444/0x610 [rdma_ucm]
[c000000207f2b820] [c008000000242c24] .ucma_close+0x94/0xf0 [rdma_ucm]
[c000000207f2b8c0] [c00000000046fbdc] .__fput+0xac/0x330
[c000000207f2b960] [c00000000015d48c] .task_work_run+0xbc/0x110
[c000000207f2b9f0] [c00000000012fb00] .do_exit+0x430/0xc50
[c000000207f2bae0] [c0000000001303ec] .do_group_exit+0x5c/0xd0
[c000000207f2bb70] [c000000000144a34] .get_signal+0x194/0xe30
[c000000207f2bc60] [c00000000001f6b4] .do_notify_resume+0x124/0x470
[c000000207f2bd60] [c000000000032484] .interrupt_exit_user_prepare+0x1b4/0x240
[c000000207f2be20] [c000000000010034] interrupt_return+0x14/0x1c0
Rename listen_ctx to conn_req_ctx as the poor name was the cause of this
bug.
Fixes: a1d33b70dbbc ("RDMA/ucma: Rework how new connections are passed through event delivery")
Link: https://lore.kernel.org/r/20201012045600.418271-4-leon@kernel.org
Signed-off-by: Maor Gottlieb <maorg@nvidia.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Diffstat (limited to 'drivers/infiniband/core')
-rw-r--r-- | drivers/infiniband/core/ucma.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 08a628246bd6..ffe2563ad345 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -112,7 +112,7 @@ struct ucma_multicast { struct ucma_event { struct ucma_context *ctx; - struct ucma_context *listen_ctx; + struct ucma_context *conn_req_ctx; struct ucma_multicast *mc; struct list_head list; struct rdma_ucm_event_resp resp; @@ -308,7 +308,7 @@ static int ucma_connect_event_handler(struct rdma_cm_id *cm_id, uevent = ucma_create_uevent(listen_ctx, event); if (!uevent) goto err_alloc; - uevent->listen_ctx = listen_ctx; + uevent->conn_req_ctx = ctx; uevent->resp.id = ctx->id; ctx->cm_id->context = ctx; @@ -534,7 +534,7 @@ static int ucma_free_ctx(struct ucma_context *ctx) /* Cleanup events not yet reported to the user. */ mutex_lock(&ctx->file->mut); list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) { - if (uevent->ctx == ctx || uevent->listen_ctx == ctx) + if (uevent->ctx == ctx || uevent->conn_req_ctx == ctx) list_move_tail(&uevent->list, &list); } list_del(&ctx->list); @@ -548,8 +548,9 @@ static int ucma_free_ctx(struct ucma_context *ctx) */ list_for_each_entry_safe(uevent, tmp, &list, list) { list_del(&uevent->list); - if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) - __destroy_id(uevent->ctx); + if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST && + uevent->conn_req_ctx != ctx) + __destroy_id(uevent->conn_req_ctx); kfree(uevent); } |