diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-07-13 15:42:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-07-13 15:42:14 -0400 |
commit | 4659fc8484b707c161b14324df0e3a2f5d03f050 (patch) | |
tree | 5f2e1dce44199e0ee19c7f1a7ed6c137b606798a | |
parent | 2a7e1211e130c51a2b5743ecf247645ac8e936ee (diff) | |
parent | d63c46734c545ad0488761059004a65c46efdde3 (diff) |
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma
Pull rdma fixes from Jason Gunthorpe:
"Things have been quite slow, only 6 RC patches have been sent to the
list. Regression, user visible bugs, and crashing fixes:
- cxgb4 could wrongly fail MR creation due to a typo
- various crashes if the wrong QP type is mixed in with APIs that
expect other types
- syzkaller oops
- using ERR_PTR and NULL together cases HFI1 to crash in some cases
- mlx5 memory leak in error unwind"
* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma:
RDMA/mlx5: Fix memory leak in mlx5_ib_create_srq() error path
RDMA/uverbs: Don't fail in creation of multiple flows
IB/hfi1: Fix incorrect mixing of ERR_PTR and NULL return values
RDMA/uverbs: Fix slab-out-of-bounds in ib_uverbs_ex_create_flow
RDMA/uverbs: Protect from attempts to create flows on unsupported QP
iw_cxgb4: correctly enforce the max reg_mr depth
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 28 | ||||
-rw-r--r-- | drivers/infiniband/hw/cxgb4/mem.c | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/rc.c | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/uc.c | 4 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/ud.c | 4 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/verbs_txreq.c | 4 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/verbs_txreq.h | 4 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx5/srq.c | 18 |
8 files changed, 39 insertions, 27 deletions
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 3e90b6a1d9d2..cc06e8404e9b 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -3488,8 +3488,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, | |||
3488 | struct ib_flow_attr *flow_attr; | 3488 | struct ib_flow_attr *flow_attr; |
3489 | struct ib_qp *qp; | 3489 | struct ib_qp *qp; |
3490 | struct ib_uflow_resources *uflow_res; | 3490 | struct ib_uflow_resources *uflow_res; |
3491 | struct ib_uverbs_flow_spec_hdr *kern_spec; | ||
3491 | int err = 0; | 3492 | int err = 0; |
3492 | void *kern_spec; | ||
3493 | void *ib_spec; | 3493 | void *ib_spec; |
3494 | int i; | 3494 | int i; |
3495 | 3495 | ||
@@ -3538,8 +3538,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, | |||
3538 | if (!kern_flow_attr) | 3538 | if (!kern_flow_attr) |
3539 | return -ENOMEM; | 3539 | return -ENOMEM; |
3540 | 3540 | ||
3541 | memcpy(kern_flow_attr, &cmd.flow_attr, sizeof(*kern_flow_attr)); | 3541 | *kern_flow_attr = cmd.flow_attr; |
3542 | err = ib_copy_from_udata(kern_flow_attr + 1, ucore, | 3542 | err = ib_copy_from_udata(&kern_flow_attr->flow_specs, ucore, |
3543 | cmd.flow_attr.size); | 3543 | cmd.flow_attr.size); |
3544 | if (err) | 3544 | if (err) |
3545 | goto err_free_attr; | 3545 | goto err_free_attr; |
@@ -3559,6 +3559,11 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, | |||
3559 | goto err_uobj; | 3559 | goto err_uobj; |
3560 | } | 3560 | } |
3561 | 3561 | ||
3562 | if (qp->qp_type != IB_QPT_UD && qp->qp_type != IB_QPT_RAW_PACKET) { | ||
3563 | err = -EINVAL; | ||
3564 | goto err_put; | ||
3565 | } | ||
3566 | |||
3562 | flow_attr = kzalloc(struct_size(flow_attr, flows, | 3567 | flow_attr = kzalloc(struct_size(flow_attr, flows, |
3563 | cmd.flow_attr.num_of_specs), GFP_KERNEL); | 3568 | cmd.flow_attr.num_of_specs), GFP_KERNEL); |
3564 | if (!flow_attr) { | 3569 | if (!flow_attr) { |
@@ -3578,21 +3583,22 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, | |||
3578 | flow_attr->flags = kern_flow_attr->flags; | 3583 | flow_attr->flags = kern_flow_attr->flags; |
3579 | flow_attr->size = sizeof(*flow_attr); | 3584 | flow_attr->size = sizeof(*flow_attr); |
3580 | 3585 | ||
3581 | kern_spec = kern_flow_attr + 1; | 3586 | kern_spec = kern_flow_attr->flow_specs; |
3582 | ib_spec = flow_attr + 1; | 3587 | ib_spec = flow_attr + 1; |
3583 | for (i = 0; i < flow_attr->num_of_specs && | 3588 | for (i = 0; i < flow_attr->num_of_specs && |
3584 | cmd.flow_attr.size > offsetof(struct ib_uverbs_flow_spec, reserved) && | 3589 | cmd.flow_attr.size >= sizeof(*kern_spec) && |
3585 | cmd.flow_attr.size >= | 3590 | cmd.flow_attr.size >= kern_spec->size; |
3586 | ((struct ib_uverbs_flow_spec *)kern_spec)->size; i++) { | 3591 | i++) { |
3587 | err = kern_spec_to_ib_spec(file->ucontext, kern_spec, ib_spec, | 3592 | err = kern_spec_to_ib_spec( |
3588 | uflow_res); | 3593 | file->ucontext, (struct ib_uverbs_flow_spec *)kern_spec, |
3594 | ib_spec, uflow_res); | ||
3589 | if (err) | 3595 | if (err) |
3590 | goto err_free; | 3596 | goto err_free; |
3591 | 3597 | ||
3592 | flow_attr->size += | 3598 | flow_attr->size += |
3593 | ((union ib_flow_spec *) ib_spec)->size; | 3599 | ((union ib_flow_spec *) ib_spec)->size; |
3594 | cmd.flow_attr.size -= ((struct ib_uverbs_flow_spec *)kern_spec)->size; | 3600 | cmd.flow_attr.size -= kern_spec->size; |
3595 | kern_spec += ((struct ib_uverbs_flow_spec *) kern_spec)->size; | 3601 | kern_spec = ((void *)kern_spec) + kern_spec->size; |
3596 | ib_spec += ((union ib_flow_spec *) ib_spec)->size; | 3602 | ib_spec += ((union ib_flow_spec *) ib_spec)->size; |
3597 | } | 3603 | } |
3598 | if (cmd.flow_attr.size || (i != flow_attr->num_of_specs)) { | 3604 | if (cmd.flow_attr.size || (i != flow_attr->num_of_specs)) { |
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index 1445918e3239..7b76e6f81aeb 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c | |||
@@ -774,7 +774,7 @@ static int c4iw_set_page(struct ib_mr *ibmr, u64 addr) | |||
774 | { | 774 | { |
775 | struct c4iw_mr *mhp = to_c4iw_mr(ibmr); | 775 | struct c4iw_mr *mhp = to_c4iw_mr(ibmr); |
776 | 776 | ||
777 | if (unlikely(mhp->mpl_len == mhp->max_mpl_len)) | 777 | if (unlikely(mhp->mpl_len == mhp->attr.pbl_size)) |
778 | return -ENOMEM; | 778 | return -ENOMEM; |
779 | 779 | ||
780 | mhp->mpl[mhp->mpl_len++] = addr; | 780 | mhp->mpl[mhp->mpl_len++] = addr; |
diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index 1a1a47ac53c6..f15c93102081 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c | |||
@@ -271,7 +271,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) | |||
271 | 271 | ||
272 | lockdep_assert_held(&qp->s_lock); | 272 | lockdep_assert_held(&qp->s_lock); |
273 | ps->s_txreq = get_txreq(ps->dev, qp); | 273 | ps->s_txreq = get_txreq(ps->dev, qp); |
274 | if (IS_ERR(ps->s_txreq)) | 274 | if (!ps->s_txreq) |
275 | goto bail_no_tx; | 275 | goto bail_no_tx; |
276 | 276 | ||
277 | if (priv->hdr_type == HFI1_PKT_TYPE_9B) { | 277 | if (priv->hdr_type == HFI1_PKT_TYPE_9B) { |
diff --git a/drivers/infiniband/hw/hfi1/uc.c b/drivers/infiniband/hw/hfi1/uc.c index b7b671017e59..e254dcec6f64 100644 --- a/drivers/infiniband/hw/hfi1/uc.c +++ b/drivers/infiniband/hw/hfi1/uc.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright(c) 2015, 2016 Intel Corporation. | 2 | * Copyright(c) 2015 - 2018 Intel Corporation. |
3 | * | 3 | * |
4 | * This file is provided under a dual BSD/GPLv2 license. When using or | 4 | * This file is provided under a dual BSD/GPLv2 license. When using or |
5 | * redistributing this file, you may do so under either license. | 5 | * redistributing this file, you may do so under either license. |
@@ -72,7 +72,7 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) | |||
72 | int middle = 0; | 72 | int middle = 0; |
73 | 73 | ||
74 | ps->s_txreq = get_txreq(ps->dev, qp); | 74 | ps->s_txreq = get_txreq(ps->dev, qp); |
75 | if (IS_ERR(ps->s_txreq)) | 75 | if (!ps->s_txreq) |
76 | goto bail_no_tx; | 76 | goto bail_no_tx; |
77 | 77 | ||
78 | if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_SEND_OK)) { | 78 | if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_SEND_OK)) { |
diff --git a/drivers/infiniband/hw/hfi1/ud.c b/drivers/infiniband/hw/hfi1/ud.c index 1ab332f1866e..70d39fc450a1 100644 --- a/drivers/infiniband/hw/hfi1/ud.c +++ b/drivers/infiniband/hw/hfi1/ud.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright(c) 2015, 2016 Intel Corporation. | 2 | * Copyright(c) 2015 - 2018 Intel Corporation. |
3 | * | 3 | * |
4 | * This file is provided under a dual BSD/GPLv2 license. When using or | 4 | * This file is provided under a dual BSD/GPLv2 license. When using or |
5 | * redistributing this file, you may do so under either license. | 5 | * redistributing this file, you may do so under either license. |
@@ -503,7 +503,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) | |||
503 | u32 lid; | 503 | u32 lid; |
504 | 504 | ||
505 | ps->s_txreq = get_txreq(ps->dev, qp); | 505 | ps->s_txreq = get_txreq(ps->dev, qp); |
506 | if (IS_ERR(ps->s_txreq)) | 506 | if (!ps->s_txreq) |
507 | goto bail_no_tx; | 507 | goto bail_no_tx; |
508 | 508 | ||
509 | if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_NEXT_SEND_OK)) { | 509 | if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_NEXT_SEND_OK)) { |
diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.c b/drivers/infiniband/hw/hfi1/verbs_txreq.c index 873e48ea923f..c4ab2d5b4502 100644 --- a/drivers/infiniband/hw/hfi1/verbs_txreq.c +++ b/drivers/infiniband/hw/hfi1/verbs_txreq.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright(c) 2016 - 2017 Intel Corporation. | 2 | * Copyright(c) 2016 - 2018 Intel Corporation. |
3 | * | 3 | * |
4 | * This file is provided under a dual BSD/GPLv2 license. When using or | 4 | * This file is provided under a dual BSD/GPLv2 license. When using or |
5 | * redistributing this file, you may do so under either license. | 5 | * redistributing this file, you may do so under either license. |
@@ -94,7 +94,7 @@ struct verbs_txreq *__get_txreq(struct hfi1_ibdev *dev, | |||
94 | struct rvt_qp *qp) | 94 | struct rvt_qp *qp) |
95 | __must_hold(&qp->s_lock) | 95 | __must_hold(&qp->s_lock) |
96 | { | 96 | { |
97 | struct verbs_txreq *tx = ERR_PTR(-EBUSY); | 97 | struct verbs_txreq *tx = NULL; |
98 | 98 | ||
99 | write_seqlock(&dev->txwait_lock); | 99 | write_seqlock(&dev->txwait_lock); |
100 | if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) { | 100 | if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) { |
diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.h b/drivers/infiniband/hw/hfi1/verbs_txreq.h index 729244c3086c..1c19bbc764b2 100644 --- a/drivers/infiniband/hw/hfi1/verbs_txreq.h +++ b/drivers/infiniband/hw/hfi1/verbs_txreq.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright(c) 2016 Intel Corporation. | 2 | * Copyright(c) 2016 - 2018 Intel Corporation. |
3 | * | 3 | * |
4 | * This file is provided under a dual BSD/GPLv2 license. When using or | 4 | * This file is provided under a dual BSD/GPLv2 license. When using or |
5 | * redistributing this file, you may do so under either license. | 5 | * redistributing this file, you may do so under either license. |
@@ -83,7 +83,7 @@ static inline struct verbs_txreq *get_txreq(struct hfi1_ibdev *dev, | |||
83 | if (unlikely(!tx)) { | 83 | if (unlikely(!tx)) { |
84 | /* call slow path to get the lock */ | 84 | /* call slow path to get the lock */ |
85 | tx = __get_txreq(dev, qp); | 85 | tx = __get_txreq(dev, qp); |
86 | if (IS_ERR(tx)) | 86 | if (!tx) |
87 | return tx; | 87 | return tx; |
88 | } | 88 | } |
89 | tx->qp = qp; | 89 | tx->qp = qp; |
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 0af7b7905550..f5de5adc9b1a 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c | |||
@@ -266,18 +266,24 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, | |||
266 | 266 | ||
267 | desc_size = sizeof(struct mlx5_wqe_srq_next_seg) + | 267 | desc_size = sizeof(struct mlx5_wqe_srq_next_seg) + |
268 | srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg); | 268 | srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg); |
269 | if (desc_size == 0 || srq->msrq.max_gs > desc_size) | 269 | if (desc_size == 0 || srq->msrq.max_gs > desc_size) { |
270 | return ERR_PTR(-EINVAL); | 270 | err = -EINVAL; |
271 | goto err_srq; | ||
272 | } | ||
271 | desc_size = roundup_pow_of_two(desc_size); | 273 | desc_size = roundup_pow_of_two(desc_size); |
272 | desc_size = max_t(size_t, 32, desc_size); | 274 | desc_size = max_t(size_t, 32, desc_size); |
273 | if (desc_size < sizeof(struct mlx5_wqe_srq_next_seg)) | 275 | if (desc_size < sizeof(struct mlx5_wqe_srq_next_seg)) { |
274 | return ERR_PTR(-EINVAL); | 276 | err = -EINVAL; |
277 | goto err_srq; | ||
278 | } | ||
275 | srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) / | 279 | srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) / |
276 | sizeof(struct mlx5_wqe_data_seg); | 280 | sizeof(struct mlx5_wqe_data_seg); |
277 | srq->msrq.wqe_shift = ilog2(desc_size); | 281 | srq->msrq.wqe_shift = ilog2(desc_size); |
278 | buf_size = srq->msrq.max * desc_size; | 282 | buf_size = srq->msrq.max * desc_size; |
279 | if (buf_size < desc_size) | 283 | if (buf_size < desc_size) { |
280 | return ERR_PTR(-EINVAL); | 284 | err = -EINVAL; |
285 | goto err_srq; | ||
286 | } | ||
281 | in.type = init_attr->srq_type; | 287 | in.type = init_attr->srq_type; |
282 | 288 | ||
283 | if (pd->uobject) | 289 | if (pd->uobject) |