IB/core: Avoid accessing non-allocated memory when inferring port type

Commit 44c58487d51a ("IB/core: Define 'ib' and 'roce' rdma_ah_attr types")
introduced the concept of type in ah_attr:
* During ib_register_device, each port is checked for its type which
is stored in ib_device's port_immutable array.
* During uverbs' modify_qp, the type is inferred using the port number
in ib_uverbs_qp_dest struct (address vector) by accessing the
relevant port_immutable array and the type is passed on to
providers.

IB spec (version 1.3) enforces a valid port value only in Reset to
Init. During Init to RTR, the address vector must be valid but port
number is not mentioned as a field in the address vector, so its
value is not validated, which leads to accesses to a non-allocated
memory when inferring the port type.

Save the real port number in ib_qp during modify to Init (when the
comp_mask indicates that the port number is valid) and use this value
to infer the port type.

Avoid copying the address vector fields if the matching bit is not set
in the attr_mask. Address vector can't be modified before the port, so
no valid flow is affected.

Fixes: 44c58487d51a ('IB/core: Define 'ib' and 'roce' rdma_ah_attr types')
Signed-off-by: Noa Osherovich <noaos@mellanox.com>
Reviewed-by: Yishai Hadas <yishaih@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>

authored by

Noa Osherovich and committed by
Doug Ledford
498ca3c8 65159c05

+14 -5
+7 -4
drivers/infiniband/core/uverbs_cmd.c
··· 1522 1522 qp->qp_type = attr.qp_type; 1523 1523 atomic_set(&qp->usecnt, 0); 1524 1524 atomic_inc(&pd->usecnt); 1525 + qp->port = 0; 1525 1526 if (attr.send_cq) 1526 1527 atomic_inc(&attr.send_cq->usecnt); 1527 1528 if (attr.recv_cq) ··· 1963 1962 attr->alt_timeout = cmd->base.alt_timeout; 1964 1963 attr->rate_limit = cmd->rate_limit; 1965 1964 1966 - attr->ah_attr.type = rdma_ah_find_type(qp->device, 1967 - cmd->base.dest.port_num); 1965 + if (cmd->base.attr_mask & IB_QP_AV) 1966 + attr->ah_attr.type = rdma_ah_find_type(qp->device, 1967 + cmd->base.dest.port_num); 1968 1968 if (cmd->base.dest.is_global) { 1969 1969 rdma_ah_set_grh(&attr->ah_attr, NULL, 1970 1970 cmd->base.dest.flow_label, ··· 1983 1981 rdma_ah_set_port_num(&attr->ah_attr, 1984 1982 cmd->base.dest.port_num); 1985 1983 1986 - attr->alt_ah_attr.type = rdma_ah_find_type(qp->device, 1987 - cmd->base.dest.port_num); 1984 + if (cmd->base.attr_mask & IB_QP_ALT_PATH) 1985 + attr->alt_ah_attr.type = 1986 + rdma_ah_find_type(qp->device, cmd->base.dest.port_num); 1988 1987 if (cmd->base.alt_dest.is_global) { 1989 1988 rdma_ah_set_grh(&attr->alt_ah_attr, NULL, 1990 1989 cmd->base.alt_dest.flow_label,
+6 -1
drivers/infiniband/core/verbs.c
··· 838 838 spin_lock_init(&qp->mr_lock); 839 839 INIT_LIST_HEAD(&qp->rdma_mrs); 840 840 INIT_LIST_HEAD(&qp->sig_mrs); 841 + qp->port = 0; 841 842 842 843 if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) 843 844 return ib_create_xrc_qp(qp, qp_init_attr); ··· 1298 1297 if (ret) 1299 1298 return ret; 1300 1299 } 1301 - return ib_security_modify_qp(qp, attr, attr_mask, udata); 1300 + ret = ib_security_modify_qp(qp, attr, attr_mask, udata); 1301 + if (!ret && (attr_mask & IB_QP_PORT)) 1302 + qp->port = attr->port_num; 1303 + 1304 + return ret; 1302 1305 } 1303 1306 EXPORT_SYMBOL(ib_modify_qp_with_udata); 1304 1307
+1
include/rdma/ib_verbs.h
··· 1683 1683 enum ib_qp_type qp_type; 1684 1684 struct ib_rwq_ind_table *rwq_ind_tbl; 1685 1685 struct ib_qp_security *qp_sec; 1686 + u8 port; 1686 1687 }; 1687 1688 1688 1689 struct ib_mr {