aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHefty, Sean <sean.hefty@intel.com>2011-10-06 12:32:33 -0400
committerRoland Dreier <roland@purestorage.com>2011-10-06 12:32:33 -0400
commit9595480c5dd1f01e477e8c993d6b24fa484eca3f (patch)
tree14c450423933c5e47a83f8e3c08210ab66ed86c5
parent976d167615b64e14bc1491ca51d424e2ba9a5e84 (diff)
RDMA/cma: Fix crash in cma_req_handler
The RDMA CM uses the local qp_type to determine how to process an incoming request. This can result in an incoming REQ being treated as a SIDR REQ and vice versa. Fix this by switching off the event type instead, and for good measure verify that the listener supports the incoming connection request. This problem showed up when a user space application mismatched the QP types between a client and server app. Signed-off-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r--drivers/infiniband/core/cma.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index ca4c5dcd7133..31d958e2c9ec 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -1179,6 +1179,15 @@ static void cma_set_req_event_data(struct rdma_cm_event *event,
1179 event->param.conn.qp_num = req_data->remote_qpn; 1179 event->param.conn.qp_num = req_data->remote_qpn;
1180} 1180}
1181 1181
1182static int cma_check_req_qp_type(struct rdma_cm_id *id, struct ib_cm_event *ib_event)
1183{
1184 return (((ib_event->event == IB_CM_REQ_RECEIVED) ||
1185 (ib_event->param.req_rcvd.qp_type == id->qp_type)) ||
1186 ((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) &&
1187 (id->qp_type == IB_QPT_UD)) ||
1188 (!id->qp_type));
1189}
1190
1182static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1191static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
1183{ 1192{
1184 struct rdma_id_private *listen_id, *conn_id; 1193 struct rdma_id_private *listen_id, *conn_id;
@@ -1186,13 +1195,16 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
1186 int offset, ret; 1195 int offset, ret;
1187 1196
1188 listen_id = cm_id->context; 1197 listen_id = cm_id->context;
1198 if (!cma_check_req_qp_type(&listen_id->id, ib_event))
1199 return -EINVAL;
1200
1189 if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 1201 if (cma_disable_callback(listen_id, RDMA_CM_LISTEN))
1190 return -ECONNABORTED; 1202 return -ECONNABORTED;
1191 1203
1192 memset(&event, 0, sizeof event); 1204 memset(&event, 0, sizeof event);
1193 offset = cma_user_data_offset(listen_id->id.ps); 1205 offset = cma_user_data_offset(listen_id->id.ps);
1194 event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1206 event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
1195 if (listen_id->id.qp_type == IB_QPT_UD) { 1207 if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) {
1196 conn_id = cma_new_udp_id(&listen_id->id, ib_event); 1208 conn_id = cma_new_udp_id(&listen_id->id, ib_event);
1197 event.param.ud.private_data = ib_event->private_data + offset; 1209 event.param.ud.private_data = ib_event->private_data + offset;
1198 event.param.ud.private_data_len = 1210 event.param.ud.private_data_len =