diff options
author | Cong Wang <xiyou.wangcong@gmail.com> | 2018-06-01 11:31:44 -0700 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2018-09-25 23:47:30 +0100 |
commit | c62b25af5f51f49e9f93f828cc38a82c23e8a0c5 (patch) | |
tree | 5505d09cd0a5e789a6f879a717cf5cbb1004f3b5 | |
parent | 78ff116fd34c3d86db2b15b9213591c8f929111f (diff) |
infiniband: fix a possible use-after-free bug
commit cb2595c1393b4a5211534e6f0a0fbad369e21ad8 upstream.
ucma_process_join() will free the new allocated "mc" struct,
if there is any error after that, especially the copy_to_user().
But in parallel, ucma_leave_multicast() could find this "mc"
through idr_find() before ucma_process_join() frees it, since it
is already published.
So "mc" could be used in ucma_leave_multicast() after it is been
allocated and freed in ucma_process_join(), since we don't refcnt
it.
Fix this by separating "publish" from ID allocation, so that we
can get an ID first and publish it later after copy_to_user().
Fixes: c8f6a362bf3e ("RDMA/cma: Add multicast communication support")
Reported-by: Noam Rathaus <noamr@beyondsecurity.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r-- | drivers/infiniband/core/ucma.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 29e646836cde..9acf67de4e9a 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -180,7 +180,7 @@ static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) return NULL; mutex_lock(&mut); - mc->id = idr_alloc(&multicast_idr, mc, 0, 0, GFP_KERNEL); + mc->id = idr_alloc(&multicast_idr, NULL, 0, 0, GFP_KERNEL); mutex_unlock(&mut); if (mc->id < 0) goto error; @@ -1285,6 +1285,10 @@ static ssize_t ucma_process_join(struct ucma_file *file, goto err3; } + mutex_lock(&mut); + idr_replace(&multicast_idr, mc, mc->id); + mutex_unlock(&mut); + mutex_unlock(&file->mut); ucma_put_ctx(ctx); return 0; |