Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Hefty, Sean and committed by
Roland Dreier
9595480c 976d1676

+13 -1
+13 -1
drivers/infiniband/core/cma.c
··· 1179 1179 event->param.conn.qp_num = req_data->remote_qpn; 1180 1180 } 1181 1181 1182 + static 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 + 1182 1191 static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1183 1192 { 1184 1193 struct rdma_id_private *listen_id, *conn_id; ··· 1195 1186 int offset, ret; 1196 1187 1197 1188 listen_id = cm_id->context; 1189 + if (!cma_check_req_qp_type(&listen_id->id, ib_event)) 1190 + return -EINVAL; 1191 + 1198 1192 if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 1199 1193 return -ECONNABORTED; 1200 1194 1201 1195 memset(&event, 0, sizeof event); 1202 1196 offset = cma_user_data_offset(listen_id->id.ps); 1203 1197 event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1204 - if (listen_id->id.qp_type == IB_QPT_UD) { 1198 + if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) { 1205 1199 conn_id = cma_new_udp_id(&listen_id->id, ib_event); 1206 1200 event.param.ud.private_data = ib_event->private_data + offset; 1207 1201 event.param.ud.private_data_len =