[15/49] IB/uverbs: Protect QP multicast list

From: Greg KH
Date: Tue Jan 10 2012 - 18:02:09 EST


3.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eli Cohen <eli@xxxxxxxxxxxxxxxxxx>

commit e214a0fe2b382fa302c036ecd6e6ffe99e3b9875 upstream.

Userspace verbs multicast attach/detach operations on a QP are done
while holding the rwsem of the QP for reading. That's not sufficient
since a reader lock allows more than one reader to acquire the
lock. However, multicast attach/detach does list manipulation that
can corrupt the list if multiple threads run in parallel.

Fix this by acquiring the rwsem as a writer to serialize attach/detach
operations. Add idr_write_qp() and put_qp_write() to encapsulate
this.

This fixes oops seen when running applications that perform multicast
joins/leaves.

Reported by: Mike Dubman <miked@xxxxxxxxxxxx>
Signed-off-by: Eli Cohen <eli@xxxxxxxxxxxx>
Signed-off-by: Roland Dreier <roland@xxxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxx>

---
drivers/infiniband/core/uverbs_cmd.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)

--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -241,11 +241,24 @@ static struct ib_qp *idr_read_qp(int qp_
return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0);
}

+static struct ib_qp *idr_write_qp(int qp_handle, struct ib_ucontext *context)
+{
+ struct ib_uobject *uobj;
+
+ uobj = idr_write_uobj(&ib_uverbs_qp_idr, qp_handle, context);
+ return uobj ? uobj->object : NULL;
+}
+
static void put_qp_read(struct ib_qp *qp)
{
put_uobj_read(qp->uobject);
}

+static void put_qp_write(struct ib_qp *qp)
+{
+ put_uobj_write(qp->uobject);
+}
+
static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context)
{
return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context, 0);
@@ -2375,7 +2388,7 @@ ssize_t ib_uverbs_attach_mcast(struct ib
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;

- qp = idr_read_qp(cmd.qp_handle, file->ucontext);
+ qp = idr_write_qp(cmd.qp_handle, file->ucontext);
if (!qp)
return -EINVAL;

@@ -2404,7 +2417,7 @@ ssize_t ib_uverbs_attach_mcast(struct ib
kfree(mcast);

out_put:
- put_qp_read(qp);
+ put_qp_write(qp);

return ret ? ret : in_len;
}
@@ -2422,7 +2435,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;

- qp = idr_read_qp(cmd.qp_handle, file->ucontext);
+ qp = idr_write_qp(cmd.qp_handle, file->ucontext);
if (!qp)
return -EINVAL;

@@ -2441,7 +2454,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib
}

out_put:
- put_qp_read(qp);
+ put_qp_write(qp);

return ret ? ret : in_len;
}


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/