Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e214a0fe authored by Eli Cohen's avatar Eli Cohen Committed by Roland Dreier
Browse files

IB/uverbs: Protect QP multicast list



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@mellanox.com>
Signed-off-by: default avatarEli Cohen <eli@mellanox.com>
Cc: <stable@kernel.org>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent 5f0a6e2d
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -241,11 +241,24 @@ static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context)
	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_uverbs_file *file,
	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_uverbs_file *file,
		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_uverbs_file *file,
	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_uverbs_file *file,
		}

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

	return ret ? ret : in_len;
}