summaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/nes/nes_cm.c
diff options
context:
space:
mode:
authorFaisal Latif2009-03-12 22:34:59 +0100
committerLinus Torvalds2009-03-13 00:21:41 +0100
commitc12e56ef6951f4fce1afe9ef6aab9243ea9a9b04 (patch)
tree677319ae34074efbf98a87d9496a7d5cb47c0524 /drivers/infiniband/hw/nes/nes_cm.c
parentfs: new inode i_state corruption fix (diff)
downloadkernel-qcow2-linux-c12e56ef6951f4fce1afe9ef6aab9243ea9a9b04.tar.gz
kernel-qcow2-linux-c12e56ef6951f4fce1afe9ef6aab9243ea9a9b04.tar.xz
kernel-qcow2-linux-c12e56ef6951f4fce1afe9ef6aab9243ea9a9b04.zip
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>
Diffstat (limited to 'drivers/infiniband/hw/nes/nes_cm.c')
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c39
1 files changed, 34 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)
int ret = 0;
struct nes_vnic *nesvnic;
struct nes_device *nesdev;
+ struct nes_ib_device *nesibdev;
nesvnic = to_nesvnic(nesqp->ibqp.device);
if (!nesvnic)
return -EINVAL;
nesdev = nesvnic->nesdev;
+ nesibdev = nesvnic->nesibdev;
nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
atomic_read(&nesvnic->netdev->refcnt));
@@ -2507,6 +2509,8 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt)
} else {
/* Need to free the Last Streaming Mode Message */
if (nesqp->ietf_frame) {
+ if (nesqp->lsmm_mr)
+ nesibdev->ibdev.dereg_mr(nesqp->lsmm_mr);
pci_free_consistent(nesdev->pcidev,
nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
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)
u32 crc_value;
int ret;
int passive_state;
+ struct nes_ib_device *nesibdev;
+ struct ib_mr *ibmr = NULL;
+ struct ib_phys_buf ibphysbuf;
+ struct nes_pd *nespd;
+
+
ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
if (!ibqp)
@@ -2601,6 +2611,26 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (cm_id->remote_addr.sin_addr.s_addr !=
cm_id->local_addr.sin_addr.s_addr) {
u64temp = (unsigned long)nesqp;
+ nesibdev = nesvnic->nesibdev;
+ nespd = nesqp->nespd;
+ ibphysbuf.addr = nesqp->ietf_frame_pbase;
+ ibphysbuf.size = conn_param->private_data_len +
+ sizeof(struct ietf_mpa_frame);
+ ibmr = nesibdev->ibdev.reg_phys_mr((struct ib_pd *)nespd,
+ &ibphysbuf, 1,
+ IB_ACCESS_LOCAL_WRITE,
+ (u64 *)&nesqp->ietf_frame);
+ if (!ibmr) {
+ nes_debug(NES_DBG_CM, "Unable to register memory region"
+ "for lSMM for cm_node = %p \n",
+ cm_node);
+ return -ENOMEM;
+ }
+
+ ibmr->pd = &nespd->ibpd;
+ ibmr->device = nespd->ibpd.device;
+ nesqp->lsmm_mr = ibmr;
+
u64temp |= NES_SW_CONTEXT_ALIGN>>1;
set_wqe_64bit_value(wqe->wqe_words,
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)
wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
cpu_to_le32(conn_param->private_data_len +
sizeof(struct ietf_mpa_frame));
- wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] =
- cpu_to_le32((u32)nesqp->ietf_frame_pbase);
- wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] =
- cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32));
+ set_wqe_64bit_value(wqe->wqe_words,
+ NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,
+ (u64)nesqp->ietf_frame);
wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
cpu_to_le32(conn_param->private_data_len +
sizeof(struct ietf_mpa_frame));
- wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = ibmr->lkey;
nesqp->nesqp_context->ird_ord_sizes |=
cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |