mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 12:10:38 -04:00
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma
Pull rdma fixes from Jason Gunthorpe:
"More bug fixes, many found by tools:
- Protect from a possible DOS with certain RMPP traffic patterns
- Correct mac address comparison so CMA works properly on IB
- Some crashes in irdma around memory registration
- Uninitialized value in erdma and mana
- Wrong order setting up a QP in SIW allowed a network packet to
reach an unready QP struct
- Catch math overflows in hns and irdma"
* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma:
RDMA/irdma: Prevent overflows in memory contiguity checks
RDMA/siw: publish QP after initialization
RDMA/hns: Fix potential integer overflow in mhop hem cleanup
RDMA/core: Fix memory leak in __ib_create_cq() on invalid cqe
RDMA/mana_ib: initialize err for empty send WR lists
RDMA/erdma: initialize ret for empty receive WR lists
RDMA/irdma: Prevent user-triggered null deref on QP create
RDMA/irdma: Prevent rereg_mr for non-mem regions
RDMA/cma: Fix hardware address comparison length in netevent callback
RDMa/mlx5: Avoid frame overflow warning
IB/mad: Drop unmatched RMPP responses before reassembly
This commit is contained in:
@@ -5270,7 +5270,7 @@ static int cma_netevent_callback(struct notifier_block *self,
|
||||
|
||||
list_for_each_entry(current_id, &ips_node->id_list, id_list_entry) {
|
||||
if (!memcmp(current_id->id.route.addr.dev_addr.dst_dev_addr,
|
||||
neigh->ha, ETH_ALEN))
|
||||
neigh->ha, neigh->dev->addr_len))
|
||||
continue;
|
||||
cma_id_get(current_id);
|
||||
if (!queue_work(cma_wq, ¤t_id->id.net_work))
|
||||
|
||||
@@ -2031,6 +2031,24 @@ void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr)
|
||||
change_mad_state(mad_send_wr, IB_MAD_STATE_EARLY_RESP);
|
||||
}
|
||||
|
||||
static bool is_kernel_rmpp_data_response(struct ib_mad_agent_private *agent,
|
||||
struct ib_mad_recv_wc *mad_recv_wc)
|
||||
{
|
||||
const struct ib_mad_hdr *mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;
|
||||
struct ib_rmpp_mad *rmpp_mad;
|
||||
|
||||
if (!ib_mad_kernel_rmpp_agent(&agent->agent) ||
|
||||
!ib_response_mad(mad_hdr) ||
|
||||
!ib_is_mad_class_rmpp(mad_hdr->mgmt_class))
|
||||
return false;
|
||||
|
||||
rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
|
||||
|
||||
return (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
|
||||
IB_MGMT_RMPP_FLAG_ACTIVE) &&
|
||||
rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA;
|
||||
}
|
||||
|
||||
static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
|
||||
struct ib_mad_recv_wc *mad_recv_wc)
|
||||
{
|
||||
@@ -2050,6 +2068,18 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
|
||||
}
|
||||
|
||||
list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
|
||||
if (is_kernel_rmpp_data_response(mad_agent_priv, mad_recv_wc)) {
|
||||
spin_lock_irqsave(&mad_agent_priv->lock, flags);
|
||||
mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc);
|
||||
spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
|
||||
|
||||
if (!mad_send_wr) {
|
||||
ib_free_recv_mad(mad_recv_wc);
|
||||
deref_mad_agent(mad_agent_priv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ib_mad_kernel_rmpp_agent(&mad_agent_priv->agent)) {
|
||||
mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv,
|
||||
mad_recv_wc);
|
||||
|
||||
@@ -2196,13 +2196,13 @@ struct ib_cq *__ib_create_cq(struct ib_device *device,
|
||||
struct ib_cq *cq;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON_ONCE(!cq_attr->cqe))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
cq = rdma_zalloc_drv_obj(device, ib_cq);
|
||||
if (!cq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (WARN_ON_ONCE(!cq_attr->cqe))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
cq->device = device;
|
||||
cq->comp_handler = comp_handler;
|
||||
cq->event_handler = event_handler;
|
||||
|
||||
@@ -734,7 +734,7 @@ int erdma_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *recv_wr,
|
||||
const struct ib_recv_wr *wr = recv_wr;
|
||||
struct erdma_qp *qp = to_eqp(ibqp);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&qp->lock, flags);
|
||||
|
||||
|
||||
@@ -836,7 +836,7 @@ static void hns_roce_cleanup_mhop_hem_table(struct hns_roce_dev *hr_dev,
|
||||
mhop.bt_chunk_size;
|
||||
|
||||
for (i = 0; i < table->num_hem; ++i) {
|
||||
obj = i * buf_chunk_size / table->obj_size;
|
||||
obj = (u64)i * buf_chunk_size / table->obj_size;
|
||||
if (table->hem[i])
|
||||
hns_roce_table_mhop_put(hr_dev, table, obj, 0);
|
||||
}
|
||||
|
||||
@@ -633,17 +633,16 @@ static int irdma_setup_umode_qp(struct ib_udata *udata,
|
||||
|
||||
iwqp->ctx_info.qp_compl_ctx = req.user_compl_ctx;
|
||||
iwqp->user_mode = 1;
|
||||
if (req.user_wqe_bufs) {
|
||||
spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
|
||||
iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs,
|
||||
&ucontext->qp_reg_mem_list);
|
||||
spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
|
||||
|
||||
if (!iwqp->iwpbl) {
|
||||
ret = -ENODATA;
|
||||
ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n");
|
||||
return ret;
|
||||
}
|
||||
spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
|
||||
iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs,
|
||||
&ucontext->qp_reg_mem_list);
|
||||
spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
|
||||
|
||||
if (!iwqp->iwpbl) {
|
||||
ret = -ENODATA;
|
||||
ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ucontext->use_raw_attrs) {
|
||||
@@ -2802,7 +2801,7 @@ static bool irdma_check_mem_contiguous(u64 *arr, u32 npages, u32 pg_size)
|
||||
u32 pg_idx;
|
||||
|
||||
for (pg_idx = 0; pg_idx < npages; pg_idx++) {
|
||||
if ((*arr + (pg_size * pg_idx)) != arr[pg_idx])
|
||||
if ((*arr + ((u64)pg_size * pg_idx)) != arr[pg_idx])
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2835,7 +2834,7 @@ static bool irdma_check_mr_contiguous(struct irdma_pble_alloc *palloc,
|
||||
|
||||
for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) {
|
||||
arr = leaf->addr;
|
||||
if ((*start_addr + (i * pg_size * PBLE_PER_PAGE)) != *arr)
|
||||
if ((*start_addr + ((u64)i * pg_size * PBLE_PER_PAGE)) != *arr)
|
||||
return false;
|
||||
ret = irdma_check_mem_contiguous(arr, leaf->cnt, pg_size);
|
||||
if (!ret)
|
||||
@@ -3791,6 +3790,9 @@ static struct ib_mr *irdma_rereg_user_mr(struct ib_mr *ib_mr, int flags,
|
||||
if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS))
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
if (iwmr->type != IRDMA_MEMREG_TYPE_MEM)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
ret = ib_umem_check_rereg(iwmr->region, flags, new_access);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
@@ -144,7 +144,7 @@ static int mana_ib_post_send_ud(struct mana_ib_qp *qp, const struct ib_ud_wr *wr
|
||||
int mana_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
|
||||
const struct ib_send_wr **bad_wr)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
struct mana_ib_qp *qp = container_of(ibqp, struct mana_ib_qp, ibqp);
|
||||
|
||||
for (; wr; wr = wr->next) {
|
||||
|
||||
@@ -840,13 +840,15 @@ static int handle_psv(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int handle_reg_mr_integrity(struct mlx5_ib_dev *dev,
|
||||
struct mlx5_ib_qp *qp,
|
||||
const struct ib_send_wr *wr,
|
||||
struct mlx5_wqe_ctrl_seg **ctrl, void **seg,
|
||||
int *size, void **cur_edge,
|
||||
unsigned int *idx, int nreq, u8 fence,
|
||||
u8 next_fence)
|
||||
static noinline_for_stack int handle_reg_mr_integrity(struct mlx5_ib_dev *dev,
|
||||
struct mlx5_ib_qp *qp,
|
||||
const struct ib_send_wr *wr,
|
||||
struct mlx5_wqe_ctrl_seg **ctrl,
|
||||
void **seg,
|
||||
int *size, void **cur_edge,
|
||||
unsigned int *idx, int nreq,
|
||||
u8 fence,
|
||||
u8 next_fence)
|
||||
{
|
||||
struct mlx5_ib_mr *mr;
|
||||
struct mlx5_ib_mr *pi_mr;
|
||||
|
||||
@@ -318,6 +318,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
|
||||
struct siw_ucontext *uctx =
|
||||
rdma_udata_to_drv_context(udata, struct siw_ucontext,
|
||||
base_ucontext);
|
||||
struct siw_uresp_create_qp uresp = {};
|
||||
unsigned long flags;
|
||||
int num_sqe, num_rqe, rv = 0;
|
||||
size_t length;
|
||||
@@ -371,11 +372,6 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
|
||||
spin_lock_init(&qp->rq_lock);
|
||||
spin_lock_init(&qp->orq_lock);
|
||||
|
||||
rv = siw_qp_add(sdev, qp);
|
||||
if (rv)
|
||||
goto err_atomic;
|
||||
|
||||
|
||||
/* All queue indices are derived from modulo operations
|
||||
* on a free running 'get' (consumer) and 'put' (producer)
|
||||
* unsigned counter. Having queue sizes at power of two
|
||||
@@ -393,14 +389,14 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
|
||||
|
||||
if (qp->sendq == NULL) {
|
||||
rv = -ENOMEM;
|
||||
goto err_out_xa;
|
||||
goto err_out;
|
||||
}
|
||||
if (attrs->sq_sig_type != IB_SIGNAL_REQ_WR) {
|
||||
if (attrs->sq_sig_type == IB_SIGNAL_ALL_WR)
|
||||
qp->attrs.flags |= SIW_SIGNAL_ALL_WR;
|
||||
else {
|
||||
rv = -EINVAL;
|
||||
goto err_out_xa;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
qp->pd = pd;
|
||||
@@ -426,7 +422,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
|
||||
|
||||
if (qp->recvq == NULL) {
|
||||
rv = -ENOMEM;
|
||||
goto err_out_xa;
|
||||
goto err_out;
|
||||
}
|
||||
qp->attrs.rq_size = num_rqe;
|
||||
}
|
||||
@@ -441,11 +437,8 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
|
||||
qp->attrs.state = SIW_QP_STATE_IDLE;
|
||||
|
||||
if (udata) {
|
||||
struct siw_uresp_create_qp uresp = {};
|
||||
|
||||
uresp.num_sqe = num_sqe;
|
||||
uresp.num_rqe = num_rqe;
|
||||
uresp.qp_id = qp_id(qp);
|
||||
|
||||
if (qp->sendq) {
|
||||
length = num_sqe * sizeof(struct siw_sqe);
|
||||
@@ -454,7 +447,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
|
||||
length, &uresp.sq_key);
|
||||
if (!qp->sq_entry) {
|
||||
rv = -ENOMEM;
|
||||
goto err_out_xa;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,9 +459,23 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
|
||||
if (!qp->rq_entry) {
|
||||
uresp.sq_key = SIW_INVAL_UOBJ_KEY;
|
||||
rv = -ENOMEM;
|
||||
goto err_out_xa;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
qp->tx_cpu = siw_get_tx_cpu(sdev);
|
||||
if (qp->tx_cpu < 0) {
|
||||
rv = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
init_completion(&qp->qp_free);
|
||||
|
||||
rv = siw_qp_add(sdev, qp);
|
||||
if (rv)
|
||||
goto err_out_tx;
|
||||
|
||||
if (udata) {
|
||||
uresp.qp_id = qp_id(qp);
|
||||
|
||||
if (udata->outlen < sizeof(uresp)) {
|
||||
rv = -EINVAL;
|
||||
@@ -478,22 +485,19 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
|
||||
if (rv)
|
||||
goto err_out_xa;
|
||||
}
|
||||
qp->tx_cpu = siw_get_tx_cpu(sdev);
|
||||
if (qp->tx_cpu < 0) {
|
||||
rv = -EINVAL;
|
||||
goto err_out_xa;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&qp->devq);
|
||||
spin_lock_irqsave(&sdev->lock, flags);
|
||||
list_add_tail(&qp->devq, &sdev->qp_list);
|
||||
spin_unlock_irqrestore(&sdev->lock, flags);
|
||||
|
||||
init_completion(&qp->qp_free);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_xa:
|
||||
xa_erase(&sdev->qp_xa, qp_id(qp));
|
||||
err_out_tx:
|
||||
siw_put_tx_cpu(qp->tx_cpu);
|
||||
err_out:
|
||||
if (uctx) {
|
||||
rdma_user_mmap_entry_remove(qp->sq_entry);
|
||||
rdma_user_mmap_entry_remove(qp->rq_entry);
|
||||
|
||||
Reference in New Issue
Block a user