Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

IB/mad: Validate MADs for spec compliance

Validate MADs sent by userspace clients for spec compliance with
C13-18.1.1 (prevent duplicate requests and responses sent on the
same port). Without this, RMPP transactions get aborted because
of duplicate packets.

This patch is similar to that provided by Jack Morgenstein.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: Jack Morgenstein <jackm@mellanox.co.il>
Signed-off-by: Roland Dreier <rolandd@cisco.com>

authored by

Sean Hefty and committed by
Roland Dreier
2527e681 16c59419

+95 -21
+12 -10
drivers/infiniband/core/mad.c
··· 167 167 return 0; 168 168 } 169 169 170 + int ib_response_mad(struct ib_mad *mad) 171 + { 172 + return ((mad->mad_hdr.method & IB_MGMT_METHOD_RESP) || 173 + (mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) || 174 + ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_BM) && 175 + (mad->mad_hdr.attr_mod & IB_BM_ATTR_MOD_RESP))); 176 + } 177 + EXPORT_SYMBOL(ib_response_mad); 178 + 170 179 /* 171 180 * ib_register_mad_agent - Register to send/receive MADs 172 181 */ ··· 579 570 } 580 571 EXPORT_SYMBOL(ib_unregister_mad_agent); 581 572 582 - static inline int response_mad(struct ib_mad *mad) 583 - { 584 - /* Trap represses are responses although response bit is reset */ 585 - return ((mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) || 586 - (mad->mad_hdr.method & IB_MGMT_METHOD_RESP)); 587 - } 588 - 589 573 static void dequeue_mad(struct ib_mad_list_head *mad_list) 590 574 { 591 575 struct ib_mad_queue *mad_queue; ··· 725 723 switch (ret) 726 724 { 727 725 case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY: 728 - if (response_mad(&mad_priv->mad.mad) && 726 + if (ib_response_mad(&mad_priv->mad.mad) && 729 727 mad_agent_priv->agent.recv_handler) { 730 728 local->mad_priv = mad_priv; 731 729 local->recv_mad_agent = mad_agent_priv; ··· 1553 1551 unsigned long flags; 1554 1552 1555 1553 spin_lock_irqsave(&port_priv->reg_lock, flags); 1556 - if (response_mad(mad)) { 1554 + if (ib_response_mad(mad)) { 1557 1555 u32 hi_tid; 1558 1556 struct ib_mad_agent_private *entry; 1559 1557 ··· 1801 1799 } 1802 1800 1803 1801 /* Complete corresponding request */ 1804 - if (response_mad(mad_recv_wc->recv_buf.mad)) { 1802 + if (ib_response_mad(mad_recv_wc->recv_buf.mad)) { 1805 1803 spin_lock_irqsave(&mad_agent_priv->lock, flags); 1806 1804 mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc); 1807 1805 if (!mad_send_wr) {
+76 -11
drivers/infiniband/core/user_mad.c
··· 112 112 struct ib_umad_file { 113 113 struct ib_umad_port *port; 114 114 struct list_head recv_list; 115 + struct list_head send_list; 115 116 struct list_head port_list; 116 117 spinlock_t recv_lock; 118 + spinlock_t send_lock; 117 119 wait_queue_head_t recv_wait; 118 120 struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; 119 121 int agents_dead; ··· 179 177 return ret; 180 178 } 181 179 180 + static void dequeue_send(struct ib_umad_file *file, 181 + struct ib_umad_packet *packet) 182 + { 183 + spin_lock_irq(&file->send_lock); 184 + list_del(&packet->list); 185 + spin_unlock_irq(&file->send_lock); 186 + } 187 + 182 188 static void send_handler(struct ib_mad_agent *agent, 183 189 struct ib_mad_send_wc *send_wc) 184 190 { 185 191 struct ib_umad_file *file = agent->context; 186 192 struct ib_umad_packet *packet = send_wc->send_buf->context[0]; 187 193 194 + dequeue_send(file, packet); 188 195 ib_destroy_ah(packet->msg->ah); 189 196 ib_free_send_mad(packet->msg); 190 197 ··· 381 370 return 0; 382 371 } 383 372 373 + static int same_destination(struct ib_user_mad_hdr *hdr1, 374 + struct ib_user_mad_hdr *hdr2) 375 + { 376 + if (!hdr1->grh_present && !hdr2->grh_present) 377 + return (hdr1->lid == hdr2->lid); 378 + 379 + if (hdr1->grh_present && hdr2->grh_present) 380 + return !memcmp(hdr1->gid, hdr2->gid, 16); 381 + 382 + return 0; 383 + } 384 + 385 + static int is_duplicate(struct ib_umad_file *file, 386 + struct ib_umad_packet *packet) 387 + { 388 + struct ib_umad_packet *sent_packet; 389 + struct ib_mad_hdr *sent_hdr, *hdr; 390 + 391 + hdr = (struct ib_mad_hdr *) packet->mad.data; 392 + list_for_each_entry(sent_packet, &file->send_list, list) { 393 + sent_hdr = (struct ib_mad_hdr *) sent_packet->mad.data; 394 + 395 + if ((hdr->tid != sent_hdr->tid) || 396 + (hdr->mgmt_class != sent_hdr->mgmt_class)) 397 + continue; 398 + 399 + /* 400 + * No need to be overly clever here. If two new operations have 401 + * the same TID, reject the second as a duplicate. This is more 402 + * restrictive than required by the spec. 403 + */ 404 + if (!ib_response_mad((struct ib_mad *) hdr)) { 405 + if (!ib_response_mad((struct ib_mad *) sent_hdr)) 406 + return 1; 407 + continue; 408 + } else if (!ib_response_mad((struct ib_mad *) sent_hdr)) 409 + continue; 410 + 411 + if (same_destination(&packet->mad.hdr, &sent_packet->mad.hdr)) 412 + return 1; 413 + } 414 + 415 + return 0; 416 + } 417 + 384 418 static ssize_t ib_umad_write(struct file *filp, const char __user *buf, 385 419 size_t count, loff_t *pos) 386 420 { ··· 435 379 struct ib_ah_attr ah_attr; 436 380 struct ib_ah *ah; 437 381 struct ib_rmpp_mad *rmpp_mad; 438 - u8 method; 439 382 __be64 *tid; 440 383 int ret, data_len, hdr_len, copy_offset, rmpp_active; 441 384 ··· 528 473 } 529 474 530 475 /* 531 - * If userspace is generating a request that will generate a 532 - * response, we need to make sure the high-order part of the 533 - * transaction ID matches the agent being used to send the 534 - * MAD. 476 + * Set the high-order part of the transaction ID to make MADs from 477 + * different agents unique, and allow routing responses back to the 478 + * original requestor. 535 479 */ 536 - method = ((struct ib_mad_hdr *) packet->msg->mad)->method; 537 - 538 - if (!(method & IB_MGMT_METHOD_RESP) && 539 - method != IB_MGMT_METHOD_TRAP_REPRESS && 540 - method != IB_MGMT_METHOD_SEND) { 480 + if (!ib_response_mad(packet->msg->mad)) { 541 481 tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid; 542 482 *tid = cpu_to_be64(((u64) agent->hi_tid) << 32 | 543 483 (be64_to_cpup(tid) & 0xffffffff)); 484 + rmpp_mad->mad_hdr.tid = *tid; 485 + } 486 + 487 + spin_lock_irq(&file->send_lock); 488 + ret = is_duplicate(file, packet); 489 + if (!ret) 490 + list_add_tail(&packet->list, &file->send_list); 491 + spin_unlock_irq(&file->send_lock); 492 + if (ret) { 493 + ret = -EINVAL; 494 + goto err_msg; 544 495 } 545 496 546 497 ret = ib_post_send_mad(packet->msg, NULL); 547 498 if (ret) 548 - goto err_msg; 499 + goto err_send; 549 500 550 501 up_read(&file->port->mutex); 551 502 return count; 552 503 504 + err_send: 505 + dequeue_send(file, packet); 553 506 err_msg: 554 507 ib_free_send_mad(packet->msg); 555 508 err_ah: ··· 720 657 } 721 658 722 659 spin_lock_init(&file->recv_lock); 660 + spin_lock_init(&file->send_lock); 723 661 INIT_LIST_HEAD(&file->recv_list); 662 + INIT_LIST_HEAD(&file->send_list); 724 663 init_waitqueue_head(&file->recv_wait); 725 664 726 665 file->port = port;
+7
include/rdma/ib_mad.h
··· 75 75 #define IB_MGMT_METHOD_TRAP_REPRESS 0x07 76 76 77 77 #define IB_MGMT_METHOD_RESP 0x80 78 + #define IB_BM_ATTR_MOD_RESP cpu_to_be32(1) 78 79 79 80 #define IB_MGMT_MAX_METHODS 128 80 81 ··· 246 245 int timeout_ms; 247 246 int retries; 248 247 }; 248 + 249 + /** 250 + * ib_response_mad - Returns if the specified MAD has been generated in 251 + * response to a sent request or trap. 252 + */ 253 + int ib_response_mad(struct ib_mad *mad); 249 254 250 255 /** 251 256 * ib_get_rmpp_resptime - Returns the RMPP response time.