CVE-2014-2739: Improper Input Validation (CWE-20)
value: The cma_req_handler function in drivers/infiniband/core/cma.c in the Linux kernel 3.14.x through 3.14.1 attempts to resolve an RDMA over Converged Ethernet (aka RoCE) address that is properly resolved within a different module, which allows remote attackers to cause a denial of service (incorrect pointer dereference and system crash) via crafted network traffic.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
Published: 2014-04-14T23:55Z
Repository: https://github.com/torvalds/linux
Language: C
Files changed: drivers/infiniband/core/cm.c, drivers/infiniband/core/cma.c, include/rdma/ib_cm.h
Commit date: 2014-04-01 14:05:26 -0700
Commit message: IB/core: Don't resolve passive side RoCE L2 address in CMA REQ handler

The code that resolves the passive side source MAC within the rdma_cm
connection request handler was both redundant and buggy, so remove it.

It was redundant since later, when an RC QP is modified to RTR state,
the resolution will take place in the ib_core module.  It was buggy
because this callback also deals with UD SIDR exchange, for which we
incorrectly looked at the REQ member of the CM event and dereferenced
a random value.

Fixes: dd5f03beb4f7 ("IB/core: Ethernet L2 attributes in verbs/cm structures")
Signed-off-by: Moni Shoua <monis@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>

Diff: diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 0601b9daf8407a..c3239170d8b789 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -347,27 +347,10 @@ static void cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc,
 	av->pkey_index = wc->pkey_index;
 	ib_init_ah_from_wc(port->cm_dev->ib_device, port->port_num, wc,
 			   grh, &av->ah_attr);
 }
 
-int ib_update_cm_av(struct ib_cm_id *id, const u8 *smac, const u8 *alt_smac)
-{
-	struct cm_id_private *cm_id_priv;
-
-	cm_id_priv = container_of(id, struct cm_id_private, id);
-
-	if (smac != NULL)
-		memcpy(cm_id_priv->av.smac, smac, sizeof(cm_id_priv->av.smac));
-
-	if (alt_smac != NULL)
-		memcpy(cm_id_priv->alt_av.smac, alt_smac,
-		       sizeof(cm_id_priv->alt_av.smac));
-
-	return 0;
-}
-EXPORT_SYMBOL(ib_update_cm_av);
-
 static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
 {
 	struct cm_device *cm_dev;
 	struct cm_port *port = NULL;
 	unsigned long flags;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 199958d9ddc808..42c3058e6e9cdb 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -1282,19 +1282,10 @@ static int cma_check_req_qp_type(struct rdma_cm_id *id, struct ib_cm_event *ib_e
 static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
 {
 	struct rdma_id_private *listen_id, *conn_id;
 	struct rdma_cm_event event;
 	int offset, ret;
-	u8 smac[ETH_ALEN];
-	u8 alt_smac[ETH_ALEN];
-	u8 *psmac = smac;
-	u8 *palt_smac = alt_smac;
-	int is_iboe = ((rdma_node_get_transport(cm_id->device->node_type) ==
-			RDMA_TRANSPORT_IB) &&
-		       (rdma_port_get_link_layer(cm_id->device,
-			ib_event->param.req_rcvd.port) ==
-			IB_LINK_LAYER_ETHERNET));
 
 	listen_id = cm_id->context;
 	if (!cma_check_req_qp_type(&listen_id->id, ib_event))
 		return -EINVAL;
 
@@ -1334,32 +1325,15 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
 	 */
 	atomic_inc(&conn_id->refcount);
 	ret = conn_id->id.event_handler(&conn_id->id, &event);
 	if (ret)
 		goto err3;
-
-	if (is_iboe) {
-		if (ib_event->param.req_rcvd.primary_path != NULL)
-			rdma_addr_find_smac_by_sgid(
-				&ib_event->param.req_rcvd.primary_path->sgid,
-				psmac, NULL);
-		else
-			psmac = NULL;
-		if (ib_event->param.req_rcvd.alternate_path != NULL)
-			rdma_addr_find_smac_by_sgid(
-				&ib_event->param.req_rcvd.alternate_path->sgid,
-				palt_smac, NULL);
-		else
-			palt_smac = NULL;
-	}
 	/*
 	 * Acquire mutex to prevent user executing rdma_destroy_id()
 	 * while we're accessing the cm_id.
 	 */
 	mutex_lock(&lock);
-	if (is_iboe)
-		ib_update_cm_av(cm_id, psmac, palt_smac);
 	if (cma_comp(conn_id, RDMA_CM_CONNECT) &&
 	    (conn_id->id.qp_type != IB_QPT_UD))
 		ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
 	mutex_unlock(&lock);
 	mutex_unlock(&conn_id->handler_mutex);
diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h
index f29e3a27c2cccc..0e3ff30647d518 100644
--- a/include/rdma/ib_cm.h
+++ b/include/rdma/ib_cm.h
@@ -599,7 +599,6 @@ struct ib_cm_sidr_rep_param {
  * @param: Service ID resolution reply information.
  */
 int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id,
 			struct ib_cm_sidr_rep_param *param);
 
-int ib_update_cm_av(struct ib_cm_id *id, const u8 *smac, const u8 *alt_smac);
 #endif /* IB_CM_H */

Vulnerable code: int ib_update_cm_av(struct ib_cm_id *id, const u8 *smac, const u8 *alt_smac)
{
	struct cm_id_private *cm_id_priv;

	cm_id_priv = container_of(id, struct cm_id_private, id);

	if (smac != NULL)
		memcpy(cm_id_priv->av.smac, smac, sizeof(cm_id_priv->av.smac));

	if (alt_smac != NULL)
		memcpy(cm_id_priv->alt_av.smac, alt_smac,
		       sizeof(cm_id_priv->alt_av.smac));

	return 0;
}
EXPORT_SYMBOL(ib_update_cm_av);

	u8 smac[ETH_ALEN];
	u8 alt_smac[ETH_ALEN];
	u8 *psmac = smac;
	u8 *palt_smac = alt_smac;
	int is_iboe = ((rdma_node_get_transport(cm_id->device->node_type) ==
			RDMA_TRANSPORT_IB) &&
		       (rdma_port_get_link_layer(cm_id->device,
			ib_event->param.req_rcvd.port) ==
			IB_LINK_LAYER_ETHERNET));

	if (is_iboe) {
		if (ib_event->param.req_rcvd.primary_path != NULL)
			rdma_addr_find_smac_by_sgid(
				&ib_event->param.req_rcvd.primary_path->sgid,
				psmac, NULL);
		else
			psmac = NULL;
		if (ib_event->param.req_rcvd.alternate_path != NULL)
			rdma_addr_find_smac_by_sgid(
				&ib_event->param.req_rcvd.alternate_path->sgid,
				palt_smac, NULL);
		else
			palt_smac = NULL;
	}
	if (is_iboe)
		ib_update_cm_av(cm_id, psmac, palt_smac);
int ib_update_cm_av(struct ib_cm_id *id, const u8 *smac, const u8 *alt_smac);