aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFaisal Latif <faisal.latif@intel.com>2009-03-12 17:34:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-03-12 19:21:41 -0400
commitc12e56ef6951f4fce1afe9ef6aab9243ea9a9b04 (patch)
tree677319ae34074efbf98a87d9496a7d5cb47c0524
parent7ef0d7377cb287e08f3ae94cebc919448e1f5dff (diff)
RDMA/nes: Don't allow userspace QPs to use STag zero
STag zero is a special STag that allows consumers to access any bus address without registering memory. The nes driver unfortunately allows STag zero to be used even with QPs created by unprivileged userspace consumers, which means that any process with direct verbs access to the nes device can read and write any memory accessible to the underlying PCI device (usually any memory in the system). Such access is usually given for cluster software such as MPI to use, so this is a local privilege escalation bug on most systems running this driver. The driver was using STag zero to receive the last streaming mode data; to allow STag zero to be disabled for unprivileged QPs, the driver now registers a special MR for this data. Cc: <stable@kernel.org> Signed-off-by: Faisal Latif <faisal.latif@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c39
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.h1
3 files changed, 37 insertions, 5 deletions
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index a01b4488208b..4a65b96db2c8 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -2490,12 +2490,14 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt)
2490 int ret = 0; 2490 int ret = 0;
2491 struct nes_vnic *nesvnic; 2491 struct nes_vnic *nesvnic;
2492 struct nes_device *nesdev; 2492 struct nes_device *nesdev;
2493 struct nes_ib_device *nesibdev;
2493 2494
2494 nesvnic = to_nesvnic(nesqp->ibqp.device); 2495 nesvnic = to_nesvnic(nesqp->ibqp.device);
2495 if (!nesvnic) 2496 if (!nesvnic)
2496 return -EINVAL; 2497 return -EINVAL;
2497 2498
2498 nesdev = nesvnic->nesdev; 2499 nesdev = nesvnic->nesdev;
2500 nesibdev = nesvnic->nesibdev;
2499 2501
2500 nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n", 2502 nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
2501 atomic_read(&nesvnic->netdev->refcnt)); 2503 atomic_read(&nesvnic->netdev->refcnt));
@@ -2507,6 +2509,8 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt)
2507 } else { 2509 } else {
2508 /* Need to free the Last Streaming Mode Message */ 2510 /* Need to free the Last Streaming Mode Message */
2509 if (nesqp->ietf_frame) { 2511 if (nesqp->ietf_frame) {
2512 if (nesqp->lsmm_mr)
2513 nesibdev->ibdev.dereg_mr(nesqp->lsmm_mr);
2510 pci_free_consistent(nesdev->pcidev, 2514 pci_free_consistent(nesdev->pcidev,
2511 nesqp->private_data_len+sizeof(struct ietf_mpa_frame), 2515 nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
2512 nesqp->ietf_frame, nesqp->ietf_frame_pbase); 2516 nesqp->ietf_frame, nesqp->ietf_frame_pbase);
@@ -2543,6 +2547,12 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
2543 u32 crc_value; 2547 u32 crc_value;
2544 int ret; 2548 int ret;
2545 int passive_state; 2549 int passive_state;
2550 struct nes_ib_device *nesibdev;
2551 struct ib_mr *ibmr = NULL;
2552 struct ib_phys_buf ibphysbuf;
2553 struct nes_pd *nespd;
2554
2555
2546 2556
2547 ibqp = nes_get_qp(cm_id->device, conn_param->qpn); 2557 ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
2548 if (!ibqp) 2558 if (!ibqp)
@@ -2601,6 +2611,26 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
2601 if (cm_id->remote_addr.sin_addr.s_addr != 2611 if (cm_id->remote_addr.sin_addr.s_addr !=
2602 cm_id->local_addr.sin_addr.s_addr) { 2612 cm_id->local_addr.sin_addr.s_addr) {
2603 u64temp = (unsigned long)nesqp; 2613 u64temp = (unsigned long)nesqp;
2614 nesibdev = nesvnic->nesibdev;
2615 nespd = nesqp->nespd;
2616 ibphysbuf.addr = nesqp->ietf_frame_pbase;
2617 ibphysbuf.size = conn_param->private_data_len +
2618 sizeof(struct ietf_mpa_frame);
2619 ibmr = nesibdev->ibdev.reg_phys_mr((struct ib_pd *)nespd,
2620 &ibphysbuf, 1,
2621 IB_ACCESS_LOCAL_WRITE,
2622 (u64 *)&nesqp->ietf_frame);
2623 if (!ibmr) {
2624 nes_debug(NES_DBG_CM, "Unable to register memory region"
2625 "for lSMM for cm_node = %p \n",
2626 cm_node);
2627 return -ENOMEM;
2628 }
2629
2630 ibmr->pd = &nespd->ibpd;
2631 ibmr->device = nespd->ibpd.device;
2632 nesqp->lsmm_mr = ibmr;
2633
2604 u64temp |= NES_SW_CONTEXT_ALIGN>>1; 2634 u64temp |= NES_SW_CONTEXT_ALIGN>>1;
2605 set_wqe_64bit_value(wqe->wqe_words, 2635 set_wqe_64bit_value(wqe->wqe_words,
2606 NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, 2636 NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
@@ -2611,14 +2641,13 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
2611 wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 2641 wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
2612 cpu_to_le32(conn_param->private_data_len + 2642 cpu_to_le32(conn_param->private_data_len +
2613 sizeof(struct ietf_mpa_frame)); 2643 sizeof(struct ietf_mpa_frame));
2614 wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 2644 set_wqe_64bit_value(wqe->wqe_words,
2615 cpu_to_le32((u32)nesqp->ietf_frame_pbase); 2645 NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,
2616 wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 2646 (u64)nesqp->ietf_frame);
2617 cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32));
2618 wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 2647 wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
2619 cpu_to_le32(conn_param->private_data_len + 2648 cpu_to_le32(conn_param->private_data_len +
2620 sizeof(struct ietf_mpa_frame)); 2649 sizeof(struct ietf_mpa_frame));
2621 wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0; 2650 wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = ibmr->lkey;
2622 2651
2623 nesqp->nesqp_context->ird_ord_sizes |= 2652 nesqp->nesqp_context->ird_ord_sizes |=
2624 cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | 2653 cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 4fdb72454f94..d93a6562817c 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1360,8 +1360,10 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
1360 NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT); 1360 NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT);
1361 nesqp->nesqp_context->misc |= cpu_to_le32((u32)nesqp->hwqp.sq_encoded_size << 1361 nesqp->nesqp_context->misc |= cpu_to_le32((u32)nesqp->hwqp.sq_encoded_size <<
1362 NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT); 1362 NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT);
1363 if (!udata) {
1363 nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_PRIV_EN); 1364 nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_PRIV_EN);
1364 nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_FAST_REGISTER_EN); 1365 nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_FAST_REGISTER_EN);
1366 }
1365 nesqp->nesqp_context->cqs = cpu_to_le32(nesqp->nesscq->hw_cq.cq_number + 1367 nesqp->nesqp_context->cqs = cpu_to_le32(nesqp->nesscq->hw_cq.cq_number +
1366 ((u32)nesqp->nesrcq->hw_cq.cq_number << 16)); 1368 ((u32)nesqp->nesrcq->hw_cq.cq_number << 16));
1367 u64temp = (u64)nesqp->hwqp.sq_pbase; 1369 u64temp = (u64)nesqp->hwqp.sq_pbase;
diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h
index 6c6b4da5184f..ae0ca9bc83bd 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.h
+++ b/drivers/infiniband/hw/nes/nes_verbs.h
@@ -134,6 +134,7 @@ struct nes_qp {
134 struct ietf_mpa_frame *ietf_frame; 134 struct ietf_mpa_frame *ietf_frame;
135 dma_addr_t ietf_frame_pbase; 135 dma_addr_t ietf_frame_pbase;
136 wait_queue_head_t state_waitq; 136 wait_queue_head_t state_waitq;
137 struct ib_mr *lsmm_mr;
137 unsigned long socket; 138 unsigned long socket;
138 struct nes_hw_qp hwqp; 139 struct nes_hw_qp hwqp;
139 struct work_struct work; 140 struct work_struct work;