Skip to contentSkip to conversation

Doorbell drop Avoidance Bug fix for iw_cxgb4

PATCH In review Hariprasad Shenai 9 participants 25 messages Mar 14, 2014 – May 5, 2014 8 messages not in the archive

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

cover Doorbell drop Avoidance Bug fix for iw_cxgb4

Hi All,

This patch series provides fixes for Chelsio T4/T5 adapters related to DB Drop avoidance and other small fix related to keepalive on iw-cxgb4.

The patches series is created against David Miller's 'net-next' tree. And includes patches on cxgb4 and iw_cxgb4 driver.

We would like to request this patch series to get merged via David Miller's 'net-next' tree.

We have included all the maintainers of respective drivers. Kindly review the change and let us know in case of any review comments.

Thanks

Steve Wise (2):
cxgb4/iw_cxgb4: Treat CPL_ERR_KEEPALV_NEG_ADVICE as negative advice cxgb4/iw_cxgb4: Doorbell Drop Avoidance Bug Fixes

 drivers/infiniband/hw/cxgb4/cm.c                |  24 ++--
 drivers/infiniband/hw/cxgb4/device.c            | 177 ++++++++++++++----------
 drivers/infiniband/hw/cxgb4/iw_cxgb4.h          |   9 +-
 drivers/infiniband/hw/cxgb4/provider.c          |  43 +++++-
 drivers/infiniband/hw/cxgb4/qp.c                | 140 +++++++++----------
 drivers/infiniband/hw/cxgb4/t4.h                |   6 +
 drivers/infiniband/hw/cxgb4/user.h              |   5 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h      |   1 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |  87 +++++++-----
 drivers/net/ethernet/chelsio/cxgb4/sge.c        |   8 +-
 drivers/net/ethernet/chelsio/cxgb4/t4_msg.h     |   1 +
 11 files changed, 299 insertions(+), 202 deletions(-)
Signature · 6 lines
1.8.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 1394814128-8815-1-git-send-email-hariprasad-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org

#2 lore raw

PATCH 1/2 cxgb4/iw_cxgb4: Treat CPL_ERR_KEEPALV_NEG_ADVICE as negative advice

From: Steve Wise <[email protected]>

Based on original work by Anand Priyadarshee <[email protected]>.

---
 drivers/infiniband/hw/cxgb4/cm.c            | 24 ++++++++++++------------
 drivers/net/ethernet/chelsio/cxgb4/t4_msg.h |  1 +
 2 files changed, 13 insertions(+), 12 deletions(-)
drivers/infiniband/hw/cxgb4/cm.c +12 -12
index d286bde..7e98a58 100644
@@ -1647,6 +1647,15 @@ static inline int act_open_has_tid(int status)
 	       status != CPL_ERR_ARP_MISS;
 }
 
+/* Returns whether a CPL status conveys negative advice.
+ */
+static int is_neg_adv(unsigned int status)
+{
+	return status == CPL_ERR_RTX_NEG_ADVICE ||
+	       status == CPL_ERR_PERSIST_NEG_ADVICE ||
+	       status == CPL_ERR_KEEPALV_NEG_ADVICE;
+}
+
 #define ACT_OPEN_RETRY_COUNT 2
 
 static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
@@ -1835,7 +1844,7 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
 	PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid,
 	     status, status2errno(status));
 
-	if (status == CPL_ERR_RTX_NEG_ADVICE) {
+	if (is_neg_adv(status)) {
 		printk(KERN_WARNING MOD "Connection problems for atid %u\n",
 			atid);
 		return 0;
@@ -2265,15 +2274,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
 	return 0;
 }
 
-/*
- * Returns whether an ABORT_REQ_RSS message is a negative advice.
- */
-static int is_neg_adv_abort(unsigned int status)
-{
-	return status == CPL_ERR_RTX_NEG_ADVICE ||
-	       status == CPL_ERR_PERSIST_NEG_ADVICE;
-}
-
 static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
 {
 	struct cpl_abort_req_rss *req = cplhdr(skb);
@@ -2287,7 +2287,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
 	unsigned int tid = GET_TID(req);
 
 	ep = lookup_tid(t, tid);
-	if (is_neg_adv_abort(req->status)) {
+	if (is_neg_adv(req->status)) {
 		PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
 		     ep->hwtid);
 		return 0;
@@ -3570,7 +3570,7 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
 		kfree_skb(skb);
 		return 0;
 	}
-	if (is_neg_adv_abort(req->status)) {
+	if (is_neg_adv(req->status)) {
 		PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
 		     ep->hwtid);
 		kfree_skb(skb);
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +1 -0
index cd6874b..f2738c7 100644
@@ -116,6 +116,7 @@ enum CPL_error {
 	CPL_ERR_KEEPALIVE_TIMEDOUT = 34,
 	CPL_ERR_RTX_NEG_ADVICE     = 35,
 	CPL_ERR_PERSIST_NEG_ADVICE = 36,
+	CPL_ERR_KEEPALV_NEG_ADVICE = 37,
 	CPL_ERR_ABORT_FAILED       = 42,
 	CPL_ERR_IWARP_FLM          = 50,
 };
Signature · 6 lines
1.8.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#3 lore raw
In reply to a message not in the archive

From: Hariprasad Shenai <[email protected]>
Date: Fri, 14 Mar 2014 21:52:06 +0530

Quoted 4 lines

This patch series provides fixes for Chelsio T4/T5 adapters related to DB Drop avoidance and other small fix related to keepalive on iw-cxgb4.

Quoted 8 lines

The patches series is created against David Miller's 'net-next' tree. And includes patches on cxgb4 and iw_cxgb4 driver.

We would like to request this patch series to get merged via David Miller's 'net-next' tree.

We have included all the maintainers of respective drivers. Kindly review the change and let us know in case of any review comments.

Series applied, thanks.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#4 lore raw

PATCH 2/2 cxgb4/iw_cxgb4: Doorbell Drop Avoidance Bug Fixes

In reply to Hariprasad Shenai

From: Steve Wise <[email protected]>

The current logic suffers from a slow response time to disable user DB usage, and also fails to avoid DB FIFO drops under heavy load. This commit fixes these deficiencies and makes the avoidance logic more optimal. This is done by more efficiently notifying the ULDs of potential DB problems, and implements a smoother flow control algorithm in iw_cxgb4, which is the ULD that puts the most load on the DB fifo.

Design:

cxgb4:

Direct ULD callback from the DB FULL/DROP interrupt handler. This allows the ULD to stop doing user DB writes as quickly as possible.

While user DB usage is disabled, the LLD will accumulate DB write events for its queues. Then once DB usage is reenabled, a single DB write is done for each queue with its accumulated write count. This reduces the load put on the DB fifo when reenabling.

iw_cxgb4:

Instead of marking each qp to indicate DB writes are disabled, we create a device-global status page that each user process maps. This allows iw_cxgb4 to only set this single bit to disable all DB writes for all user QPs vs traversing the idr of all the active QPs. If the libcxgb4 doesn't support this, then we fall back to the old approach of marking each QP. Thus we allow the new driver to work with an older libcxgb4.

When the LLD upcalls iw_cxgb4 indicating DB FULL, we disable all DB writes via the status page and transition the DB state to STOPPED. As user processes see that DB writes are disabled, they call into iw_cxgb4 to submit their DB write events. Since the DB state is in STOPPED, the QP trying to write gets enqueued on a new DB "flow control" list. As subsequent DB writes are submitted for this flow controlled QP, the amount of writes are accumulated for each QP on the flow control list. So all the user QPs that are actively ringing the DB get put on this list and the number of writes they request are accumulated.

When the LLD upcalls iw_cxgb4 indicating DB EMPTY, which is in a workq context, we change the DB state to FLOW_CONTROL, and begin resuming all the QPs that are on the flow control list. This logic runs on until the flow control list is empty or we exit FLOW_CONTROL mode (due to a DB DROP upcall, for example). QPs are removed from this list, and their accumulated DB write counts written to the DB FIFO. Sets of QPs, called chunks in the code, are removed at one time. The chunk size is 64. So 64 QPs are resumed at a time, and before the next chunk is resumed, the logic waits (blocks) for the DB FIFO to drain. This prevents resuming to quickly and overflowing the FIFO. Once the flow control list is empty, the db state transitions back to NORMAL and user QPs are again allowed to write directly to the user DB register.

The algorithm is designed such that if the DB write load is high enough, then all the DB writes get submitted by the kernel using this flow controlled approach to avoid DB drops. As the load lightens though, we resume to normal DB writes directly by user applications.

---
 drivers/infiniband/hw/cxgb4/device.c            | 177 ++++++++++++++----------
 drivers/infiniband/hw/cxgb4/iw_cxgb4.h          |   9 +-
 drivers/infiniband/hw/cxgb4/provider.c          |  43 +++++-
 drivers/infiniband/hw/cxgb4/qp.c                | 140 +++++++++----------
 drivers/infiniband/hw/cxgb4/t4.h                |   6 +
 drivers/infiniband/hw/cxgb4/user.h              |   5 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h      |   1 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |  87 +++++++-----
 drivers/net/ethernet/chelsio/cxgb4/sge.c        |   8 +-
 9 files changed, 286 insertions(+), 190 deletions(-)
drivers/infiniband/hw/cxgb4/device.c +107 -70
index 4a03385..ba7335f 100644
@@ -64,6 +64,10 @@ struct uld_ctx {
 static LIST_HEAD(uld_ctx_list);
 static DEFINE_MUTEX(dev_mutex);
 
+#define DB_FC_RESUME_SIZE 64
+#define DB_FC_RESUME_DELAY 1
+#define DB_FC_DRAIN_THRESH 0
+
 static struct dentry *c4iw_debugfs_root;
 
 struct c4iw_debugfs_data {
@@ -282,7 +286,7 @@ static const struct file_operations stag_debugfs_fops = {
 	.llseek  = default_llseek,
 };
 
-static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY"};
+static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY", "STOPPED"};
 
 static int stats_show(struct seq_file *seq, void *v)
 {
@@ -311,9 +315,10 @@ static int stats_show(struct seq_file *seq, void *v)
 	seq_printf(seq, "  DB FULL: %10llu\n", dev->rdev.stats.db_full);
 	seq_printf(seq, " DB EMPTY: %10llu\n", dev->rdev.stats.db_empty);
 	seq_printf(seq, "  DB DROP: %10llu\n", dev->rdev.stats.db_drop);
-	seq_printf(seq, " DB State: %s Transitions %llu\n",
+	seq_printf(seq, " DB State: %s Transitions %llu FC Interruptions %llu\n",
 		   db_state_str[dev->db_state],
-		   dev->rdev.stats.db_state_transitions);
+		   dev->rdev.stats.db_state_transitions,
+		   dev->rdev.stats.db_fc_interruptions);
 	seq_printf(seq, "TCAM_FULL: %10llu\n", dev->rdev.stats.tcam_full);
 	seq_printf(seq, "ACT_OFLD_CONN_FAILS: %10llu\n",
 		   dev->rdev.stats.act_ofld_conn_fails);
@@ -643,6 +648,12 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
 		printk(KERN_ERR MOD "error %d initializing ocqp pool\n", err);
 		goto err4;
 	}
+	rdev->status_page = (struct t4_dev_status_page *)
+			    __get_free_page(GFP_KERNEL);
+	if (!rdev->status_page) {
+		pr_err(MOD "error allocating status page\n");
+		goto err4;
+	}
 	return 0;
 err4:
 	c4iw_rqtpool_destroy(rdev);
@@ -656,6 +667,7 @@ err1:
 
 static void c4iw_rdev_close(struct c4iw_rdev *rdev)
 {
+	free_page((unsigned long)rdev->status_page);
 	c4iw_pblpool_destroy(rdev);
 	c4iw_rqtpool_destroy(rdev);
 	c4iw_destroy_resource(&rdev->resource);
@@ -703,18 +715,6 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
 		pr_info("%s: On-Chip Queues not supported on this device.\n",
 			pci_name(infop->pdev));
 
-	if (!is_t4(infop->adapter_type)) {
-		if (!allow_db_fc_on_t5) {
-			db_fc_threshold = 100000;
-			pr_info("DB Flow Control Disabled.\n");
-		}
-
-		if (!allow_db_coalescing_on_t5) {
-			db_coalescing_threshold = -1;
-			pr_info("DB Coalescing Disabled.\n");
-		}
-	}
-
 	devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp));
 	if (!devp) {
 		printk(KERN_ERR MOD "Cannot allocate ib device\n");
@@ -749,6 +749,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
 	spin_lock_init(&devp->lock);
 	mutex_init(&devp->rdev.stats.lock);
 	mutex_init(&devp->db_mutex);
+	INIT_LIST_HEAD(&devp->db_fc_list);
 
 	if (c4iw_debugfs_root) {
 		devp->debugfs_root = debugfs_create_dir(
@@ -977,13 +978,16 @@ static int disable_qp_db(int id, void *p, void *data)
 
 static void stop_queues(struct uld_ctx *ctx)
 {
-	spin_lock_irq(&ctx->dev->lock);
-	if (ctx->dev->db_state == NORMAL) {
-		ctx->dev->rdev.stats.db_state_transitions++;
-		ctx->dev->db_state = FLOW_CONTROL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->dev->lock, flags);
+	ctx->dev->rdev.stats.db_state_transitions++;
+	ctx->dev->db_state = STOPPED;
+	if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED)
 		idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
-	}
-	spin_unlock_irq(&ctx->dev->lock);
+	else
+		ctx->dev->rdev.status_page->db_off = 1;
+	spin_unlock_irqrestore(&ctx->dev->lock, flags);
 }
 
 static int enable_qp_db(int id, void *p, void *data)
@@ -994,15 +998,70 @@ static int enable_qp_db(int id, void *p, void *data)
 	return 0;
 }
 
+static void resume_rc_qp(struct c4iw_qp *qp)
+{
+	spin_lock(&qp->lock);
+	t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc);
+	qp->wq.sq.wq_pidx_inc = 0;
+	t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc);
+	qp->wq.rq.wq_pidx_inc = 0;
+	spin_unlock(&qp->lock);
+}
+
+static void resume_a_chunk(struct uld_ctx *ctx)
+{
+	int i;
+	struct c4iw_qp *qp;
+
+	for (i = 0; i < DB_FC_RESUME_SIZE; i++) {
+		qp = list_first_entry(&ctx->dev->db_fc_list, struct c4iw_qp,
+				      db_fc_entry);
+		list_del_init(&qp->db_fc_entry);
+		resume_rc_qp(qp);
+		if (list_empty(&ctx->dev->db_fc_list))
+			break;
+	}
+}
+
 static void resume_queues(struct uld_ctx *ctx)
 {
 	spin_lock_irq(&ctx->dev->lock);
-	if (ctx->dev->qpcnt <= db_fc_threshold &&
-	    ctx->dev->db_state == FLOW_CONTROL) {
-		ctx->dev->db_state = NORMAL;
-		ctx->dev->rdev.stats.db_state_transitions++;
-		idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
+	if (ctx->dev->db_state != STOPPED)
+		goto out;
+	ctx->dev->db_state = FLOW_CONTROL;
+	while (1) {
+		if (list_empty(&ctx->dev->db_fc_list)) {
+			WARN_ON(ctx->dev->db_state != FLOW_CONTROL);
+			ctx->dev->db_state = NORMAL;
+			ctx->dev->rdev.stats.db_state_transitions++;
+			if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED) {
+				idr_for_each(&ctx->dev->qpidr, enable_qp_db,
+					     NULL);
+			} else {
+				ctx->dev->rdev.status_page->db_off = 0;
+			}
+			break;
+		} else {
+			if (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1)
+			    < (ctx->dev->rdev.lldi.dbfifo_int_thresh <<
+			       DB_FC_DRAIN_THRESH)) {
+				resume_a_chunk(ctx);
+			}
+			if (!list_empty(&ctx->dev->db_fc_list)) {
+				spin_unlock_irq(&ctx->dev->lock);
+				if (DB_FC_RESUME_DELAY) {
+					set_current_state(TASK_UNINTERRUPTIBLE);
+					schedule_timeout(DB_FC_RESUME_DELAY);
+				}
+				spin_lock_irq(&ctx->dev->lock);
+				if (ctx->dev->db_state != FLOW_CONTROL)
+					break;
+			}
+		}
 	}
+out:
+	if (ctx->dev->db_state != NORMAL)
+		ctx->dev->rdev.stats.db_fc_interruptions++;
 	spin_unlock_irq(&ctx->dev->lock);
 }
 
@@ -1028,12 +1087,12 @@ static int count_qps(int id, void *p, void *data)
 	return 0;
 }
 
-static void deref_qps(struct qp_list qp_list)
+static void deref_qps(struct qp_list *qp_list)
 {
 	int idx;
 
-	for (idx = 0; idx < qp_list.idx; idx++)
-		c4iw_qp_rem_ref(&qp_list.qps[idx]->ibqp);
+	for (idx = 0; idx < qp_list->idx; idx++)
+		c4iw_qp_rem_ref(&qp_list->qps[idx]->ibqp);
 }
 
 static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
@@ -1044,17 +1103,22 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
 	for (idx = 0; idx < qp_list->idx; idx++) {
 		struct c4iw_qp *qp = qp_list->qps[idx];
 
+		spin_lock_irq(&qp->rhp->lock);
+		spin_lock(&qp->lock);
 		ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
 					  qp->wq.sq.qid,
 					  t4_sq_host_wq_pidx(&qp->wq),
 					  t4_sq_wq_size(&qp->wq));
 		if (ret) {
-			printk(KERN_ERR MOD "%s: Fatal error - "
+			pr_err(KERN_ERR MOD "%s: Fatal error - "
 			       "DB overflow recovery failed - "
 			       "error syncing SQ qid %u\n",
 			       pci_name(ctx->lldi.pdev), qp->wq.sq.qid);
+			spin_unlock(&qp->lock);
+			spin_unlock_irq(&qp->rhp->lock);
 			return;
 		}
+		qp->wq.sq.wq_pidx_inc = 0;
 
 		ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
 					  qp->wq.rq.qid,
@@ -1062,12 +1126,17 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
 					  t4_rq_wq_size(&qp->wq));
 
 		if (ret) {
-			printk(KERN_ERR MOD "%s: Fatal error - "
+			pr_err(KERN_ERR MOD "%s: Fatal error - "
 			       "DB overflow recovery failed - "
 			       "error syncing RQ qid %u\n",
 			       pci_name(ctx->lldi.pdev), qp->wq.rq.qid);
+			spin_unlock(&qp->lock);
+			spin_unlock_irq(&qp->rhp->lock);
 			return;
 		}
+		qp->wq.rq.wq_pidx_inc = 0;
+		spin_unlock(&qp->lock);
+		spin_unlock_irq(&qp->rhp->lock);
 
 		/* Wait for the dbfifo to drain */
 		while (cxgb4_dbfifo_count(qp->rhp->rdev.lldi.ports[0], 1) > 0) {
@@ -1083,36 +1152,22 @@ static void recover_queues(struct uld_ctx *ctx)
 	struct qp_list qp_list;
 	int ret;
 
-	/* lock out kernel db ringers */
-	mutex_lock(&ctx->dev->db_mutex);
-
-	/* put all queues in to recovery mode */
-	spin_lock_irq(&ctx->dev->lock);
-	ctx->dev->db_state = RECOVERY;
-	ctx->dev->rdev.stats.db_state_transitions++;
-	idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
-	spin_unlock_irq(&ctx->dev->lock);
-
 	/* slow everybody down */
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(usecs_to_jiffies(1000));
 
-	/* Wait for the dbfifo to completely drain. */
-	while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(usecs_to_jiffies(10));
-	}
-
 	/* flush the SGE contexts */
 	ret = cxgb4_flush_eq_cache(ctx->dev->rdev.lldi.ports[0]);
 	if (ret) {
 		printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
 		       pci_name(ctx->lldi.pdev));
-		goto out;
+		return;
 	}
 
 	/* Count active queues so we can build a list of queues to recover */
 	spin_lock_irq(&ctx->dev->lock);
+	WARN_ON(ctx->dev->db_state != STOPPED);
+	ctx->dev->db_state = RECOVERY;
 	idr_for_each(&ctx->dev->qpidr, count_qps, &count);
 
 	qp_list.qps = kzalloc(count * sizeof *qp_list.qps, GFP_ATOMIC);
@@ -1120,7 +1175,7 @@ static void recover_queues(struct uld_ctx *ctx)
 		printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
 		       pci_name(ctx->lldi.pdev));
 		spin_unlock_irq(&ctx->dev->lock);
-		goto out;
+		return;
 	}
 	qp_list.idx = 0;
 
@@ -1133,29 +1188,13 @@ static void recover_queues(struct uld_ctx *ctx)
 	recover_lost_dbs(ctx, &qp_list);
 
 	/* we're almost done!  deref the qps and clean up */
-	deref_qps(qp_list);
+	deref_qps(&qp_list);
 	kfree(qp_list.qps);
 
-	/* Wait for the dbfifo to completely drain again */
-	while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(usecs_to_jiffies(10));
-	}
-
-	/* resume the queues */
 	spin_lock_irq(&ctx->dev->lock);
-	if (ctx->dev->qpcnt > db_fc_threshold)
-		ctx->dev->db_state = FLOW_CONTROL;
-	else {
-		ctx->dev->db_state = NORMAL;
-		idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
-	}
-	ctx->dev->rdev.stats.db_state_transitions++;
+	WARN_ON(ctx->dev->db_state != RECOVERY);
+	ctx->dev->db_state = STOPPED;
 	spin_unlock_irq(&ctx->dev->lock);
-
-out:
-	/* start up kernel db ringers again */
-	mutex_unlock(&ctx->dev->db_mutex);
 }
 
 static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
@@ -1165,9 +1204,7 @@ static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
 	switch (control) {
 	case CXGB4_CONTROL_DB_FULL:
 		stop_queues(ctx);
-		mutex_lock(&ctx->dev->rdev.stats.lock);
 		ctx->dev->rdev.stats.db_full++;
-		mutex_unlock(&ctx->dev->rdev.stats.lock);
 		break;
 	case CXGB4_CONTROL_DB_EMPTY:
 		resume_queues(ctx);
drivers/infiniband/hw/cxgb4/iw_cxgb4.h +7 -2
index 23eaeab..eb18f9b 100644
@@ -109,6 +109,7 @@ struct c4iw_dev_ucontext {
 
 enum c4iw_rdev_flags {
 	T4_FATAL_ERROR = (1<<0),
+	T4_STATUS_PAGE_DISABLED = (1<<1),
 };
 
 struct c4iw_stat {
@@ -130,6 +131,7 @@ struct c4iw_stats {
 	u64  db_empty;
 	u64  db_drop;
 	u64  db_state_transitions;
+	u64  db_fc_interruptions;
 	u64  tcam_full;
 	u64  act_ofld_conn_fails;
 	u64  pas_ofld_conn_fails;
@@ -150,6 +152,7 @@ struct c4iw_rdev {
 	unsigned long oc_mw_pa;
 	void __iomem *oc_mw_kva;
 	struct c4iw_stats stats;
+	struct t4_dev_status_page *status_page;
 };
 
 static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
@@ -211,7 +214,8 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
 enum db_state {
 	NORMAL = 0,
 	FLOW_CONTROL = 1,
-	RECOVERY = 2
+	RECOVERY = 2,
+	STOPPED = 3
 };
 
 struct c4iw_dev {
@@ -225,10 +229,10 @@ struct c4iw_dev {
 	struct mutex db_mutex;
 	struct dentry *debugfs_root;
 	enum db_state db_state;
-	int qpcnt;
 	struct idr hwtid_idr;
 	struct idr atid_idr;
 	struct idr stid_idr;
+	struct list_head db_fc_list;
 };
 
 static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
@@ -432,6 +436,7 @@ struct c4iw_qp_attributes {
 
 struct c4iw_qp {
 	struct ib_qp ibqp;
+	struct list_head db_fc_entry;
 	struct c4iw_dev *rhp;
 	struct c4iw_ep *ep;
 	struct c4iw_qp_attributes attr;
drivers/infiniband/hw/cxgb4/provider.c +41 -2

56 lines not on this page · raw message

drivers/infiniband/hw/cxgb4/qp.c +62 -78

208 lines not on this page · raw message

drivers/infiniband/hw/cxgb4/t4.h +6 -0
index e73ace7..eeca8b1 100644
@@ -300,6 +300,7 @@ struct t4_sq {
 	u16 cidx;
 	u16 pidx;
 	u16 wq_pidx;
+	u16 wq_pidx_inc;
 	u16 flags;
 	short flush_cidx;
 };
@@ -324,6 +325,7 @@ struct t4_rq {
 	u16 cidx;
 	u16 pidx;
 	u16 wq_pidx;
+	u16 wq_pidx_inc;
 };
 
 struct t4_wq {
@@ -609,3 +611,7 @@ static inline void t4_set_cq_in_error(struct t4_cq *cq)
 	((struct t4_status_page *)&cq->queue[cq->size])->qp_err = 1;
 }
 #endif
+
+struct t4_dev_status_page {
+	u8 db_off;
+};
drivers/infiniband/hw/cxgb4/user.h +5 -0
index 32b754c..11ccd27 100644
@@ -70,4 +70,9 @@ struct c4iw_create_qp_resp {
 	__u32 qid_mask;
 	__u32 flags;
 };
+
+struct c4iw_alloc_ucontext_resp {
+	__u64 status_page_key;
+	__u32 status_page_size;
+};
 #endif
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +1 -0
index 50abe1d..32db377 100644
@@ -500,6 +500,7 @@ struct sge_txq {
 	spinlock_t db_lock;
 	int db_disabled;
 	unsigned short db_pidx;
+	unsigned short db_pidx_inc;
 	u64 udb;
 };
 
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +52 -35

145 lines not on this page · raw message

drivers/net/ethernet/chelsio/cxgb4/sge.c +5 -3
index 46429f9..d4db382 100644
@@ -860,9 +860,10 @@ static void cxgb_pio_copy(u64 __iomem *dst, u64 *src)
 static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
 {
 	unsigned int *wr, index;
+	unsigned long flags;
 
 	wmb();            /* write descriptors before telling HW */
-	spin_lock(&q->db_lock);
+	spin_lock_irqsave(&q->db_lock, flags);
 	if (!q->db_disabled) {
 		if (is_t4(adap->params.chip)) {
 			t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
@@ -878,9 +879,10 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
 				writel(n,  adap->bar2 + q->udb + 8);
 			wmb();
 		}
-	}
+	} else
+		q->db_pidx_inc += n;
 	q->db_pidx = q->pidx;
-	spin_unlock(&q->db_lock);
+	spin_unlock_irqrestore(&q->db_lock, flags);
 }
 
 /**
Signature · 1 line
1.8.4

A message that is not in the archive (sent off-list or not yet received): 1394814128-8815-3-git-send-email-hariprasad-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org

#6 lore raw

Re: [PATCH net-next 2/2] cxgb4/iw_cxgb4: Doorbell Drop Avoidance Bug Fixes

Quoted 1 line · Hariprasad Shenai

From: Steve Wise <[email protected]>

[...]

Quoted 13 lines
---
 drivers/infiniband/hw/cxgb4/device.c            | 177 ++++++++++++++----------
 drivers/infiniband/hw/cxgb4/iw_cxgb4.h          |   9 +-
 drivers/infiniband/hw/cxgb4/provider.c          |  43 +++++-
 drivers/infiniband/hw/cxgb4/qp.c                | 140 +++++++++----------
 drivers/infiniband/hw/cxgb4/t4.h                |   6 +
 drivers/infiniband/hw/cxgb4/user.h              |   5 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h      |   1 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |  87 +++++++-----
 drivers/net/ethernet/chelsio/cxgb4/sge.c        |   8 +-
 9 files changed, 286 insertions(+), 190 deletions(-)

[...]

Quoted 25 lines
drivers/infiniband/hw/cxgb4/provider.c +9 -2
index 7e94c9a..e36d2a2 100644
@@ -106,15 +106,54 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
 {
 	struct c4iw_ucontext *context;
 	struct c4iw_dev *rhp = to_c4iw_dev(ibdev);
+	static int warned;
+	struct c4iw_alloc_ucontext_resp uresp;
+	int ret = 0;
+	struct c4iw_mm_entry *mm = NULL;
 
 	PDBG("%s ibdev %p\n", __func__, ibdev);
 	context = kzalloc(sizeof(*context), GFP_KERNEL);
-	if (!context)
-		return ERR_PTR(-ENOMEM);
+	if (!context) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
 	c4iw_init_dev_ucontext(&rhp->rdev, &context->uctx);
 	INIT_LIST_HEAD(&context->mmaps);
 	spin_lock_init(&context->mmap_lock);

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev, · line 133

Quoted 10 lines
drivers/infiniband/hw/cxgb4/provider.c +10 -0
+
+	if (udata->outlen < sizeof(uresp)) {
+		if (!warned++)
+			pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device status page disabled.");
+		rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED;
+	} else {
+		mm = kmalloc(sizeof(*mm), GFP_KERNEL);
+		if (!mm)
+			goto err_free;
+

OK, that's the origin of the missing error I've noticed in my latest review on linux-next.

See
<http://marc.info/[email protected]>
<http://marc.info/?i=005b01cf4907$9adfa320$d09ee960
[email protected]>

Sorry, I've missed the opportunity to report it.

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev, · line 140

Quoted 7 lines
drivers/infiniband/hw/cxgb4/provider.c +7 -0
+		uresp.status_page_size = PAGE_SIZE;
+
+		spin_lock(&context->mmap_lock);
+		uresp.status_page_key = context->key;
+		context->key += PAGE_SIZE;
+		spin_unlock(&context->mmap_lock);
+

Is it really necessary to spinlock here since context is local to the function ?

Quoted 18 lines
drivers/infiniband/hw/cxgb4/provider.c +15 -0
+		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+		if (ret)
+			goto err_mm;
+
+		mm->key = uresp.status_page_key;
+		mm->addr = virt_to_phys(rhp->rdev.status_page);
+		mm->len = PAGE_SIZE;
+		insert_mmap(context, mm);
+	}
 	return &context->ibucontext;
+err_mm:
+	kfree(mm);
+err_free:
+	kfree(context);
+err:
+	return ERR_PTR(ret);
 }
 

[...]

drivers/infiniband/hw/cxgb4/user.h struct c4iw_create_qp_resp { · line 77

Quoted 13 lines
drivers/infiniband/hw/cxgb4/user.h +5 -0
index 32b754c..11ccd27 100644
@@ -70,4 +70,9 @@ struct c4iw_create_qp_resp {
 	__u32 qid_mask;
 	__u32 flags;
 };
+
+struct c4iw_alloc_ucontext_resp {
+	__u64 status_page_key;
+	__u32 status_page_size;
+};

If this is going to be part of the ABI, mind add an explicit padding to align the structure on 64bits.

Regards

Signature · 8 lines
Yann Droneaud
OPTEYA


--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 1395848977.3297.15.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#8 lore raw

RE: [PATCH net-next 2/2] cxgb4/iw_cxgb4: Doorbell Drop Avoidance Bug Fixes

Quoted 13 lines

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev, · line 140

Quoted 9 lines
drivers/infiniband/hw/cxgb4/provider.c +7 -0
+		uresp.status_page_size = PAGE_SIZE;
+
+		spin_lock(&context->mmap_lock);
+		uresp.status_page_key = context->key;
+		context->key += PAGE_SIZE;
+		spin_unlock(&context->mmap_lock);
+

Is it really necessary to spinlock here since context is local to the function ?

You're correct.

Quoted 20 lines

[...]

drivers/infiniband/hw/cxgb4/user.h struct c4iw_create_qp_resp { · line 77

Quoted 13 lines
drivers/infiniband/hw/cxgb4/user.h +5 -0
index 32b754c..11ccd27 100644
@@ -70,4 +70,9 @@ struct c4iw_create_qp_resp {
 	__u32 qid_mask;
 	__u32 flags;
 };
+
+struct c4iw_alloc_ucontext_resp {
+	__u64 status_page_key;
+	__u32 status_page_size;
+};

If this is going to be part of the ABI, mind add an explicit padding to align the structure on 64bits.

Sounds good. Can you provide patches for these?

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#9 lore raw

PATCH 1/1 RDMA/cxgb4: info leak in c4iw_alloc_ucontext()

The c4iw_alloc_ucontext_resp struct has a 4 byte hole after the last member and we should clear it before passing it to the user.

Fixes 05eb23893c2c ('cxgb4/iw_cxgb4: Doorbell Drop Avoidance Bug Fixes')
drivers/infiniband/hw/cxgb4/provider.c +1 -1
index e36d2a2..a72aaa7 100644
@@ -107,7 +107,7 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
 	struct c4iw_ucontext *context;
 	struct c4iw_dev *rhp = to_c4iw_dev(ibdev);
 	static int warned;
-	struct c4iw_alloc_ucontext_resp uresp;
+	struct c4iw_alloc_ucontext_resp uresp = {};
 	int ret = 0;
 	struct c4iw_mm_entry *mm = NULL;
 
#10 lore raw

Re: [patch] RDMA/cxgb4: info leak in c4iw_alloc_ucontext()

Hi,

Quoted 6 lines · Dan Carpenter

The c4iw_alloc_ucontext_resp struct has a 4 byte hole after the last member and we should clear it before passing it to the user.

Fixes 05eb23893c2c ('cxgb4/iw_cxgb4: Doorbell Drop Avoidance Bug Fixes')

It's not the proper fix for this issue: an explicit padding has to be added (and initialized), see "Re: [PATCH net-next 2/2] cxgb4/iw_cxgb4:
Doorbell Drop Avoidance Bug Fixes"
http://marc.info/?i[email protected]

In its current form, the c4iw_alloc_ucontext_resp structure does not require padding on i386, so a 32bits userspace program using this structure against a x86_64 kernel will make the kernel do a buffer overflow in userspace, likely on stack, as answer of a GET_CONTEXT request:

#include <infiniband/verbs.h>
#include <infiniband/kern-abi.h>

#define IBV_INIT_CMD_RESP(cmd, size, opcode, out, outsize) \

do {                                                       \
    (cmd)->command = IB_USER_VERBS_CMD_##opcode;           \
    (cmd)->in_words  = (size) / 4;                         \
    (cmd)->out_words = (outsize) / 4;                      \
    (cmd)->response  = (out);                              \

} while (0)

struct c4iw_alloc_ucontext_resp {
        struct ibv_get_context_resp ibv_resp;
        __u64 status_page_key;
        __u32 status_page_size;
};

struct ibv_context *alloc_context(struct ibv_device *ibdev,
int cmd_fd)

{
    struct ibv_get_context cmd;
    struct c4iw_alloc_ucontext_resp resp;
    ssize_t sret;
    ...

    IBV_INIT_CMD_RESP(&cmd, sizeof(cmd),
                      GET_CONTEXT,
                      &resp, sizeof(resp));
    ...
    sret = write(context->cmd_fd,
                 &cmd,
                 sizeof(cmd));

    if (sret != sizeof(cmd)) {
        int err = errno;
        fprintf(stderr, "GET_CONTEXT failed: %d (%s)\n",
                err, strerror(err));
        ...
    }
    ...
}

Unfortunately, it's not the only structure which has this problem. I'm currently preparing a report on this issue for this driver (cxgb4) and another.

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev, · line 113

Quoted 13 lines
drivers/infiniband/hw/cxgb4/provider.c +1 -1
index e36d2a2..a72aaa7 100644
@@ -107,7 +107,7 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
 	struct c4iw_ucontext *context;
 	struct c4iw_dev *rhp = to_c4iw_dev(ibdev);
 	static int warned;
-	struct c4iw_alloc_ucontext_resp uresp;
+	struct c4iw_alloc_ucontext_resp uresp = {};
 	int ret = 0;
 	struct c4iw_mm_entry *mm = NULL;
 

Regards.

Signature · 2 lines
Yann Droneaud
OPTEYA

A message that is not in the archive (sent off-list or not yet received): 1396002468.3297.63.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#12 lore raw

RE: [patch] RDMA/cxgb4: info leak in c4iw_alloc_ucontext()

RnJvbTogWWFubiBEcm9uZWF1ZA0KPiBIaSwNCj4gDQo+IExlIHZlbmRyZWRpIDI4IG1hcnMgMjAx NCAgMTE6MjQgKzAzMDAsIERhbiBDYXJwZW50ZXIgYSBjcml0IDoNCj4gPiBUaGUgYzRpd19hbGxv Y191Y29udGV4dF9yZXNwIHN0cnVjdCBoYXMgYSA0IGJ5dGUgaG9sZSBhZnRlciB0aGUgbGFzdA0K PiA+IG1lbWJlciBhbmQgd2Ugc2hvdWxkIGNsZWFyIGl0IGJlZm9yZSBwYXNzaW5nIGl0IHRvIHRo ZSB1c2VyLg0KPiA+DQo+ID4gRml4ZXM6IDA1ZWIyMzg5M2MyYyAoJ2N4Z2I0L2l3X2N4Z2I0OiBE b29yYmVsbCBEcm9wIEF2b2lkYW5jZSBCdWcgRml4ZXMnKQ0KPiA+IFNpZ25lZC1vZmYtYnk6IERh biBDYXJwZW50ZXIgPGRhbi5jYXJwZW50ZXJAb3JhY2xlLmNvbT4NCj4gPg0KPiANCj4gSXQncyBu b3QgdGhlIHByb3BlciBmaXggZm9yIHRoaXMgaXNzdWU6IGFuIGV4cGxpY2l0IHBhZGRpbmcgaGFz IHRvIGJlDQo+IGFkZGVkIChhbmQgaW5pdGlhbGl6ZWQpLCBzZWUgIlJlOiBbUEFUQ0ggbmV0LW5l eHQgMi8yXSBjeGdiNC9pd19jeGdiNDoNCj4gRG9vcmJlbGwgRHJvcCBBdm9pZGFuY2UgQnVnIEZp eGVzIg0KPiBodHRwOi8vbWFyYy5pbmZvLz9pPTEzOTU4NDg5NzcuMzI5Ny4xNS5jYW1lbEBsb2Nh bGhvc3QubG9jYWxkb21haW4NCj4gDQo+IEluIGl0cyBjdXJyZW50IGZvcm0sIHRoZSBjNGl3X2Fs bG9jX3Vjb250ZXh0X3Jlc3Agc3RydWN0dXJlIGRvZXMgbm90DQo+IHJlcXVpcmUgcGFkZGluZyBv biBpMzg2LCBzbyBhIDMyYml0cyB1c2Vyc3BhY2UgcHJvZ3JhbSB1c2luZyB0aGlzDQo+IHN0cnVj dHVyZSBhZ2FpbnN0IGEgeDg2XzY0IGtlcm5lbCB3aWxsIG1ha2UgdGhlIGtlcm5lbCBkbyBhIGJ1 ZmZlcg0KPiBvdmVyZmxvdyBpbiB1c2Vyc3BhY2UsIGxpa2VseSBvbiBzdGFjaywgYXMgYW5zd2Vy IG9mIGEgR0VUX0NPTlRFWFQNCj4gcmVxdWVzdDoNCi4uLg0KPiBzdHJ1Y3QgYzRpd19hbGxvY191 Y29udGV4dF9yZXNwIHsNCj4gICAgICAgICBzdHJ1Y3QgaWJ2X2dldF9jb250ZXh0X3Jlc3AgaWJ2 X3Jlc3A7DQo+ICAgICAgICAgX191NjQgc3RhdHVzX3BhZ2Vfa2V5Ow0KPiAgICAgICAgIF9fdTMy IHN0YXR1c19wYWdlX3NpemU7DQo+IH07DQoNCk9yIGFkZCBfX2F0dHJpYnV0ZV9fKChhbGlnbmVk KDQpKSkgdG8gdGhlIDY0Yml0IGZpZWxkcy4NCkFuZCBtYXliZSBhIGNvbXBpbGUgdGltZSBhc3Nl cnQgb24gdGhlIGxlbmd0aCBvZiB0aGUgc3RydWN0dXJlLg0KU2luY2UgaXQgaXMgcGFydCBvZiBh biBBQkkgaXQgbXVzdCBub3QgY2hhbmdlDQoNCglEYXZpZA0KDQo

#13 lore raw

Re: [patch] RDMA/cxgb4: info leak in c4iw_alloc_ucontext()

In reply to a message not in the archive
Quoted 4 lines · Yann Droneaud

Unfortunately, it's not the only structure which has this problem. I'm currently preparing a report on this issue for this driver (cxgb4) and another.

This information leak is still present in linux-next. These days we count those things as security vulnerabilities with CVEs and everything.

When is it likely to get fixed?

regards,
dan carpenter

#14 lore raw

cover uverbs ABI fixes

Hi,

Please find 4 patches which fix some issues regarding missing explicit padding at end of structure exchanged between kernel and userspace.

These makes i386 userspace libraries and x86_64 kernel disagree about the size of the structures.

Additionally, as reported by Dan Carpenter, in one case, stack information can be leaked by the kernel to userspace due to implicit padding being not initialized.

Unfortunately, the data structure cannot be fixed alone as it would break existing applications. So in order to remain compatible with i386 libraries, providers (hw) functions are modified to use the input length to guess the expected format of the command in order to check the content of the reserved field for future usage. Other are modified to not write the padding field in response to make the kernel able to handle gracefully i386 userspace on x86_64.

For full coherency, patches against the userspace libraries (libcxgb4 and libmlx5) will be submitted as a followup to update the data structure on userspace side.

Yann Droneaud (4):
RDMA/mlx5: add missing padding at end of struct mlx5_ib_create_cq RDMA/mlx5: add missing padding at end of struct mlx5_ib_create_srq RDMA/cxgb4: add missing padding at end of struct c4iw_create_cq_resp RDMA/cxgb4: add missing padding at end of struct
c4iw_alloc_ucontext_resp

 drivers/infiniband/hw/cxgb4/cq.c       |  8 ++++++--
 drivers/infiniband/hw/cxgb4/provider.c |  8 ++++++--
 drivers/infiniband/hw/cxgb4/user.h     |  2 ++
 drivers/infiniband/hw/mlx5/cq.c        | 13 +++++++++++--
 drivers/infiniband/hw/mlx5/srq.c       | 18 +++++++++++++++---
 drivers/infiniband/hw/mlx5/user.h      |  2 ++
 6 files changed, 42 insertions(+), 9 deletions(-)
Signature · 6 lines
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): cover.1399216475.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org

#16 lore raw

PATCH 1/4 RDMA/mlx5: add missing padding at end of struct mlx5_ib_create_cq

i386 ABI disagree with most other ABIs regarding alignment of data type larger than 4 bytes: on most ABIs a padding must be added at end of the structures, while it is not required on i386.

So for most ABI struct mlx5_ib_create_cq get padded to be aligned on a 8 bytes multiple, while for i386, such padding is not added.

Tool pahole could be used to find such implicit padding:

  $ pahole --anon_include \
  	 --nested_anon_include \
  	 --recursive \
  	 --class_name mlx5_ib_create_cq \
  	 drivers/infiniband/hw/mlx5/mlx5_ib.o

Then, structure layout can be compared between i386 and x86_64:

  +++ obj-i386/drivers/infiniband/hw/mlx5/mlx5_ib.o.pahole.txt    2014-03-28 11:43:07.386413682 +0100
  --- obj-x86_64/drivers/infiniband/hw/mlx5/mlx5_ib.o.pahole.txt  2014-03-27 13:06:17.788472721 +0100
  @@ -34,9 +34,8 @@ struct mlx5_ib_create_cq {
          __u64                      db_addr;              /*     8     8 */
          __u32                      cqe_size;             /*    16     4 */
  -       /* size: 20, cachelines: 1, members: 3 */
  -       /* last cacheline: 20 bytes */
  +       /* size: 24, cachelines: 1, members: 3 */
  +       /* padding: 4 */
  +       /* last cacheline: 24 bytes */

};

This ABI disagreement will make an x86_64 kernel try to read past the buffer provided by an i386 binary.

When boundary check will be implemented, a x86_64 kernel will refuse to read past the i386 userspace provided buffer and the uverb will fail.

Anyway, if the structure lay in memory on a page boundary and next page is not mapped, ib_copy_from_udata() will fail when trying to read the 4 bytes of padding and the uverb will fail.

This patch makes create_cq_user() takes care of the input data size to handle the case where no padding is provided.

This way, x86_64 kernel will be able to handle struct mlx5_ib_create_cq as sent by unpatched and patched i386 libmlx5.

---
 drivers/infiniband/hw/mlx5/cq.c   | 13 +++++++++++--
 drivers/infiniband/hw/mlx5/user.h |  1 +
 2 files changed, 12 insertions(+), 2 deletions(-)
drivers/infiniband/hw/mlx5/cq.c +11 -2
index 62bb6b49dc1d..5996132e799d 100644
@@ -32,6 +32,7 @@
 
 #include <linux/kref.h>
 #include <rdma/ib_umem.h>
+#include <rdma/ib_user_verbs.h>
 #include "mlx5_ib.h"
 #include "user.h"
 
@@ -607,8 +608,16 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata,
 	int ncont;
 	int err;
 
-	if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
-		return -EFAULT;
+	if (udata->inlen - sizeof(struct ib_uverbs_cmd_hdr) < sizeof(ucmd)) {
+		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd) - sizeof(ucmd.reserved)))
+			return -EFAULT;
+	} else {
+		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
+			return -EFAULT;
+
+		if (ucmd.reserved != 0)
+			return -EINVAL;
+	}
 
 	if (ucmd.cqe_size != 64 && ucmd.cqe_size != 128)
 		return -EINVAL;
drivers/infiniband/hw/mlx5/user.h +1 -0
index 0f4f8e42a17f..d44ecd2c2faf 100644
@@ -91,6 +91,7 @@ struct mlx5_ib_create_cq {
 	__u64	buf_addr;
 	__u64	db_addr;
 	__u32	cqe_size;
+	__u32	reserved; /* explicit padding (optional on i386) */
 };
 
 struct mlx5_ib_create_cq_resp {
Signature · 6 lines
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#17 lore raw

PATCH 3/4 RDMA/cxgb4: add missing padding at end of struct c4iw_create_cq_resp

In reply to a message not in the archive

i386 ABI disagree with most other ABIs regarding alignment of data type larger than 4 bytes: on most ABIs a padding must be added at end of the structures, while it is not required on i386.

So for most ABI struct c4iw_create_cq_resp get implicitly padded to be aligned on a 8 bytes multiple, while for i386, such padding is not added.

Tool pahole could be used to find such implicit padding:

  $ pahole --anon_include \
           --nested_anon_include \
           --recursive \
           --class_name c4iw_create_cq_resp \
           drivers/infiniband/hw/cxgb4/iw_cxgb4.o

Then, structure layout can be compared between i386 and x86_64:

  +++ obj-i386/drivers/infiniband/hw/cxgb4/iw_cxgb4.o.pahole.txt   2014-03-28 11:43:05.547432195 +0100
  --- obj-x86_64/drivers/infiniband/hw/cxgb4/iw_cxgb4.o.pahole.txt 2014-03-28 10:55:10.990133017 +0100
  @@ -14,9 +13,8 @@ struct c4iw_create_cq_resp {
          __u32                      size;                 /*    28     4 */
          __u32                      qid_mask;             /*    32     4 */
  -       /* size: 36, cachelines: 1, members: 6 */
  -       /* last cacheline: 36 bytes */
  +       /* size: 40, cachelines: 1, members: 6 */
  +       /* padding: 4 */
  +       /* last cacheline: 40 bytes */

};

This ABI disagreement will make an x86_64 kernel try to write past the buffer provided by an i386 binary.

When boundary check will be implemented, the x86_64 kernel will refuse to write past the i386 userspace provided buffer and the uverbs will fail.

If the structure lay in memory on a page boundary and next page is not mapped, ib_copy_to_udata() will fail and the uverbs will fail.

This patch adds an explicit padding at end of structure c4iw_create_cq_resp, and, like 92b0ca7cb149 ('IB/mlx5: Fix stack info leak in mlx5_ib_alloc_ucontext()'), makes function c4iw_create_cq() not writting this padding field to userspace. This way, x86_64 kernel will be able to write struct c4iw_create_cq_resp as expected by unpatched and patched i386 libcxgb4.

Fixes cfdda9d764362 ('RDMA/cxgb4: Add driver for Chelsio T4 RNIC')
Fixes e24a72a3302a6 ('RDMA/cxgb4: Fix four byte info leak in c4iw_create_cq()')
Cc Dan Carpenter <[email protected]>
---
 drivers/infiniband/hw/cxgb4/cq.c   | 8 ++++++--
 drivers/infiniband/hw/cxgb4/user.h | 1 +
 2 files changed, 7 insertions(+), 2 deletions(-)
drivers/infiniband/hw/cxgb4/cq.c +1 -2
index cfaa56ada189..5cb3cb4b4c25 100644
@@ -940,7 +940,6 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
 		if (!mm2)
 			goto err4;
 
-		memset(&uresp, 0, sizeof(uresp));
 		uresp.qid_mask = rhp->rdev.cqmask;
 		uresp.cqid = chp->cq.cqid;
 		uresp.size = chp->cq.size;
@@ -951,7 +950,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
 		uresp.gts_key = ucontext->key;
 		ucontext->key += PAGE_SIZE;
 		spin_unlock(&ucontext->mmap_lock);
-		ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
+		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp) - sizeof(uresp.reserved));
 		if (ret)
 			goto err5;
 
drivers/infiniband/hw/cxgb4/user.h +1 -0
index 11ccd276e5d9..9b7534b5f07d 100644
@@ -48,6 +48,7 @@ struct c4iw_create_cq_resp {
 	__u32 cqid;
 	__u32 size;
 	__u32 qid_mask;
+	__u32 reserved; /* explicit padding (optional for i386) */
 };
 
 
Signature · 6 lines
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#18 lore raw

PATCH 4/4 RDMA/cxgb4: add missing padding at end of struct c4iw_alloc_ucontext_resp

In reply to a message not in the archive

i386 ABI disagree with most other ABIs regarding alignment of data type larger than 4 bytes: on most ABIs a padding must be added at end of the structures, while it is not required on i386.

So for most ABI struct c4iw_alloc_ucontext_resp get implicitly padded to be aligned on a 8 bytes multiple, while for i386, such padding is not added.

Tool pahole could be used to find such implicit padding:

  $ pahole --anon_include \
           --nested_anon_include \
           --recursive \
           --class_name c4iw_alloc_ucontext_resp \
           drivers/infiniband/hw/cxgb4/iw_cxgb4.o

Then, structure layout can be compared between i386 and x86_64:

  +++ obj-i386/drivers/infiniband/hw/cxgb4/iw_cxgb4.o.pahole.txt   2014-03-28 11:43:05.547432195 +0100
  --- obj-x86_64/drivers/infiniband/hw/cxgb4/iw_cxgb4.o.pahole.txt 2014-03-28 10:55:10.990133017 +0100
  @@ -2,9 +2,8 @@ struct c4iw_alloc_ucontext_resp {
          __u64                      status_page_key;      /*     0     8 */
          __u32                      status_page_size;     /*     8     4 */
  -       /* size: 12, cachelines: 1, members: 2 */
  -       /* last cacheline: 12 bytes */
  +       /* size: 16, cachelines: 1, members: 2 */
  +       /* padding: 4 */
  +       /* last cacheline: 16 bytes */

};

This ABI disagreement will make an x86_64 kernel try to write past the buffer provided by an i386 binary.

When boundary check will be implemented, the x86_64 kernel will refuse to write past the i386 userspace provided buffer and the uverbs will fail.

If the structure lay in memory on a page boundary and next page is not mapped, ib_copy_to_udata() will fail and the uverb will fail.

Additionally, as reported by Dan Carpenter, without the implicit padding being properly cleared, an information leak would take place in most architectures.

This patch adds an explicit padding to struct c4iw_alloc_ucontext_resp, and, like 92b0ca7cb149 ('IB/mlx5: Fix stack info leak in mlx5_ib_alloc_ucontext()'), makes function c4iw_alloc_ucontext() not writting this padding field to userspace. This way, x86_64 kernel will be able to write struct c4iw_alloc_ucontext_resp as expected by unpatched and patched i386 libcxgb4.

---
 drivers/infiniband/hw/cxgb4/provider.c | 8 ++++++--
 drivers/infiniband/hw/cxgb4/user.h     | 1 +
 2 files changed, 7 insertions(+), 2 deletions(-)
drivers/infiniband/hw/cxgb4/provider.c +2 -2
index a94a3e12c349..9ba01d524f51 100644
@@ -122,7 +122,7 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
 	INIT_LIST_HEAD(&context->mmaps);
 	spin_lock_init(&context->mmap_lock);
 
-	if (udata->outlen < sizeof(uresp)) {
+	if (udata->outlen < sizeof(uresp) - sizeof(uresp.reserved)) {
 		if (!warned++)
 			pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device status page disabled.");
 		rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED;
@@ -134,13 +134,13 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
 		}
 
 		uresp.status_page_size = PAGE_SIZE;
 
 		spin_lock(&context->mmap_lock);
 		uresp.status_page_key = context->key;
 		context->key += PAGE_SIZE;
 		spin_unlock(&context->mmap_lock);
 
-		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp) - sizeof(uresp.reserved));
 		if (ret)
 			goto err_mm;
 
drivers/infiniband/hw/cxgb4/user.h +1 -0
index 9b7534b5f07d..cbd0ce170728 100644
@@ -75,5 +75,6 @@ struct c4iw_create_qp_resp {
 struct c4iw_alloc_ucontext_resp {
 	__u64 status_page_key;
 	__u32 status_page_size;
+	__u32 reserved; /* explicit padding (optional for i386) */
 };
 #endif
Signature · 6 lines
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 2236129ab4aa1ad1562858f363fb6fef0d6bc93b.1399216475.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org

#20 lore raw

RE: [PATCH 4/4] RDMA/cxgb4: add missing padding at end of struct c4iw_alloc_ucontext_resp

<snip>

Review

Quoted 1 line
(quoted diff) +0 -0

b/drivers/infiniband/hw/cxgb4/provider.c

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device

Quoted 4 lines

index a94a3e12c349..9ba01d524f51 100644

drivers/infiniband/hw/cxgb4/provider.c +0 -0
@@ -122,7 +122,7 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device

*ibdev,

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,

Quoted 7 lines
drivers/infiniband/hw/cxgb4/provider.c +1 -1
 	INIT_LIST_HEAD(&context->mmaps);
 	spin_lock_init(&context->mmap_lock);
 
-	if (udata->outlen < sizeof(uresp)) {
+	if (udata->outlen < sizeof(uresp) - sizeof(uresp.reserved)) {
 		if (!warned++)
 			pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device

status

Quoted 5 lines
drivers/infiniband/hw/cxgb4/provider.c +0 -0
 page disabled.");
drivers/infiniband/hw/cxgb4/provider.c +0 -0
 		rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED;
@@ -134,13 +134,13 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device
 *ibdev,
 		}

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device · line 144

Quoted 10 lines
drivers/infiniband/hw/cxgb4/provider.c +1 -1
 
 		uresp.status_page_size = PAGE_SIZE;
 
 		spin_lock(&context->mmap_lock);
 		uresp.status_page_key = context->key;
 		context->key += PAGE_SIZE;
 		spin_unlock(&context->mmap_lock);
 
-		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp) -

sizeof(uresp.reserved));

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev, · line 145

Quoted 3 lines
drivers/infiniband/hw/cxgb4/provider.c +0 -0
 		if (ret)
 			goto err_mm;

This chunk doesn't apply. Not sure why. I can use -F 6 with patch, but it should apply cleanly. Can you please respin this against 89ca3b8 Linux 3.15-rc4?

I'll test the cxgb4 stuff today.

Thanks,

Steve.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#21 lore raw

Re: [PATCH 4/4] RDMA/cxgb4: add missing padding at end of struct c4iw_alloc_ucontext_resp

Hi,

Quoted 33 lines · Steve Wise

<snip>

Review

Quoted 1 line
(quoted diff) +0 -0

b/drivers/infiniband/hw/cxgb4/provider.c

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device

Quoted 4 lines

index a94a3e12c349..9ba01d524f51 100644

drivers/infiniband/hw/cxgb4/provider.c +0 -0
@@ -122,7 +122,7 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device

*ibdev,

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,

Quoted 7 lines
drivers/infiniband/hw/cxgb4/provider.c +1 -1
 	INIT_LIST_HEAD(&context->mmaps);
 	spin_lock_init(&context->mmap_lock);
 
-	if (udata->outlen < sizeof(uresp)) {
+	if (udata->outlen < sizeof(uresp) - sizeof(uresp.reserved)) {
 		if (!warned++)
 			pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device

status

Quoted 5 lines
drivers/infiniband/hw/cxgb4/provider.c +0 -0
 page disabled.");
drivers/infiniband/hw/cxgb4/provider.c +0 -0
 		rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED;
@@ -134,13 +134,13 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device
 *ibdev,
 		}

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device · line 144

Quoted 10 lines
drivers/infiniband/hw/cxgb4/provider.c +1 -1
 
 		uresp.status_page_size = PAGE_SIZE;
 
 		spin_lock(&context->mmap_lock);
 		uresp.status_page_key = context->key;
 		context->key += PAGE_SIZE;
 		spin_unlock(&context->mmap_lock);
 
-		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp) -

sizeof(uresp.reserved));

Quoted 7 lines

drivers/infiniband/hw/cxgb4/provider.c static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev, · line 145

Quoted 3 lines
drivers/infiniband/hw/cxgb4/provider.c +0 -0
 		if (ret)
 			goto err_mm;

This chunk doesn't apply. Not sure why. I can use -F 6 with patch, but it should apply cleanly. Can you please respin this against 89ca3b8 Linux 3.15-rc4?

I've hand-edited it before sending, but I've tested it with git am against linux-next (as of today).

Anyway, I'm rolling an updated patchset. Sorry for the inconvenience.

Quoted 2 lines

I'll test the cxgb4 stuff today.

Thanks.

Signature · 8 lines
Yann Droneaud
OPTEYA


--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 1399309159.2957.19.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#23 lore raw

RE: [PATCH 4/4] RDMA/cxgb4: add missing padding at end of struct c4iw_alloc_ucontext_resp

Quoted 9 lines
Quoted 3 lines

This chunk doesn't apply. Not sure why. I can use -F 6 with patch, but it should apply cleanly. Can you please respin this against 89ca3b8 Linux 3.15-rc4?

I've hand-edited it before sending, but I've tested it with git am against linux-next (as of today).

Anyway, I'm rolling an updated patchset. Sorry for the inconvenience.

No problem. I hand applied it and tested these 2 + the libcxgb4 changes and they seem to work fine.

Steve.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#24 lore raw

cover uverbs ABI fixes

In reply to a message not in the archive

Hi,

Please find two patches for libcxgb4 to keep the library in sync regarding the kernel changes I've submitted: explicit padding must be added at end of the structure so that i386 userspace library has the same structure layout than x86_64 kernel.

See http://marc.info/?i=cover.1399216475.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org

Yann Droneaud (2):
kernel abi: adds explicit padding in struct c4iw_create_cq_resp kernel abi: adds explicit padding in struct c4iw_alloc_ucontext_resp

 src/cxgb4-abi.h | 2 ++
 src/dev.c       | 5 +++++
 src/verbs.c     | 5 +++++
 3 files changed, 12 insertions(+)
Signature · 6 lines
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): cover.1399235229.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org

#26 lore raw

PATCH 1/2 kernel abi: adds explicit padding in struct c4iw_create_cq_resp

i386 ABI disagree with most other ABIs regarding alignment of data type larger than 4 bytes: on most ABIs a padding must be added at end of the structures, while it is not required on i386.

Such ABI disagreement will make an x86_64 kernel try to write past the struct c4iw_create_cq_resp buffer provided by an i386 userspace binary. As struct c4iw_create_cq_resp is likely on stack, see function c4iw_create_cq(), side effects are expected.

On kernel side, this structure was added for kernel v2.6.35-rc1 by following commit.

Commit cfdda9d764362ab77b11a410bb928400e6520d57
Author: Steve Wise <[email protected]>
Date: Wed Apr 21 15:30:06 2010 -0700

RDMA/cxgb4: Add driver for Chelsio T4 RNIC

If boundary check is implemented on kernel side, the x86_64 kernel will refuse to write past the i386 userspace provided buffer and the uverbs will fail.

To fix these issues, this patch adds an explicit padding at end of structure so that i386 and others ABI share the same structure layout. This patch makes c4iw_create_cq() check for a value in the padding field to detect newer kernel using the field for a future purpose (only activated in debug).

With this patch, libcxgb4 will work against older kernel and newer patched kernel.

---
 src/cxgb4-abi.h | 1 +
 src/verbs.c     | 5 +++++
 2 files changed, 6 insertions(+)
src/cxgb4-abi.h +1 -0
index d70b0f132a7f..23870f66dc0d 100644
@@ -53,6 +53,7 @@ struct c4iw_create_cq_resp {
 	__u32 cqid;
 	__u32 size;
 	__u32 qid_mask;
+	__u32 reserved;
 };
 
 enum {
src/verbs.c +5 -0
index ab4a45d7cdbc..4a6c1b47bc9e 100644
@@ -181,12 +181,17 @@ struct ibv_cq *c4iw_create_cq(struct ibv_context *context, int cqe,
 		return NULL;
 	}
 
+	resp.reserved = 0;
 	ret = ibv_cmd_create_cq(context, cqe, channel, comp_vector,
 				&chp->ibv_cq, &cmd, sizeof cmd,
 				&resp.ibv_resp, sizeof resp);
 	if (ret)
 		goto err1;
 
+	if (resp.reserved)
+		PDBG("%s c4iw_create_cq_resp reserved field modified by kernel\n",
+		     __FUNCTION__);
+
 	pthread_spin_init(&chp->lock, PTHREAD_PROCESS_PRIVATE);
 #ifdef STALL_DETECTION
 	gettimeofday(&chp->time, NULL);
Signature · 6 lines
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#27 lore raw

PATCH 2/2 kernel abi: adds explicit padding in struct c4iw_alloc_ucontext_resp

In reply to a message not in the archive

i386 ABI disagree with most other ABIs regarding alignment of data type larger than 4 bytes: on most ABIs a padding must be added at end of the structures, while it is not required on i386.

Such ABI disagreement will make an x86_64 kernel try to write past the struct c4iw_alloc_ucontext_resp buffer provided by an i386 userspace binary. As struct c4iw_alloc_ucontext_resp is likely on stack, see function c4iw_alloc_context(), side effects are expected.

On kernel side, this structure was modified for kernel v3.15-rc1 by following commit:

Commit 05eb23893c2cf9502a9cec0c32e7f1d1ed2895c8
Author: Steve Wise <[email protected]>
Date: Fri Mar 14 21:52:08 2014 +0530

cxgb4/iw_cxgb4: Doorbell Drop Avoidance Bug Fixes

If boundary check is implemented on kernel side, the x86_64 kernel will instead refuse to write past the i386 userspace provided buffer and the uverbs will fail.

To fix these issues, this patch adds an explicit padding at end of structure so that i386 and others ABI share the same structure layout. This patch makes c4iw_alloc_context() check for a value in the padding field to detect newer kernel using the field for a future purpose (only activated in debug).

With this patch, libcxgb4 will work against older kernel and newer patched kernel.

---
 src/cxgb4-abi.h | 1 +
 src/dev.c       | 5 +++++
 2 files changed, 6 insertions(+)
src/cxgb4-abi.h +1 -0
index 23870f66dc0d..0b9f4d99d0e7 100644
@@ -38,6 +38,7 @@ struct c4iw_alloc_ucontext_resp {
 	struct ibv_get_context_resp ibv_resp;
 	__u64 status_page_key;
 	__u32 status_page_size;
+	__u32 reserved;
 };
 
 struct c4iw_alloc_pd_resp {
src/dev.c +5 -0
index 3236e6b2db6d..f66df71105e5 100644
@@ -125,10 +125,15 @@ static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
 	context->ibv_ctx.cmd_fd = cmd_fd;
 
 	resp.status_page_size = 0;
+	resp.reserved = 0;
 	if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd,
 				&resp.ibv_resp, sizeof resp))
 		goto err_free;
 
+	if (resp.reserved)
+		PDBG("%s c4iw_alloc_ucontext_resp reserved field modified by kernel\n",
+		     __FUNCTION__);
+
 	context->status_page_size = resp.status_page_size;
 	if (resp.status_page_size) {
 		context->status_page = mmap(NULL, resp.status_page_size,
Signature · 6 lines
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#29 lore raw

PATCH 1/1 abi: adds explicit padding on mlx5_create_cq and mlx5_create_srq

In reply to a message not in the archive

i386 ABI disagree with most other ABIs regarding alignment of data type larger than 4 bytes: on most ABIs a padding must be added at end of the structures, while it is not required on i386.

Such ABI disagreement will make an x86_64 kernel try to read past a buffer provided by an i386 binary, as the latter will not have the expected padding for struct mlx5_create_cq and mlx5_create_srq.

On kernel side, these structures were added for kernel v3.11-rc1 by following commit:

Commit e126ba97dba9edeb6fafa3665b5f8497fc9cdf8c
Author: Eli Cohen <eli-VPRAkNaXOzVWk0Htik3J/[email protected]>
Date: Sun Jul 7 17:25:49 2013 +0300

mlx5: Add driver for Mellanox Connect-IB adapters

If future kernel is to use the padding for extension, on a x86_64 unpatched kernel, it might read garbage as it would read past the i386 provided buffer.

In this other hand, if boundary check is implemented on kernel side, the x86_64 kernel will refuse to read past the i386 userspace provided buffer for struct mlx5_create_cq and mlx5_create_srq, making the uverbs fail.

To address all these issues, this patch add an explicit padding at end of structures and initialize it so that i386 and others ABI share the same structure layout.

With this patch, libmlx5 will run on older kernel and newer patched kernel.

---
 src/mlx5-abi.h | 2 ++
 src/verbs.c    | 6 ++++--
 2 files changed, 6 insertions(+), 2 deletions(-)
src/mlx5-abi.h +2 -0
index 6f98e62c59d5..980b24910403 100644
@@ -83,6 +83,7 @@ struct mlx5_create_cq {
 	__u64				buf_addr;
 	__u64				db_addr;
 	__u32				cqe_size;
+	__u32				reserved;
 };
 
 struct mlx5_create_cq_resp {
@@ -95,6 +96,7 @@ struct mlx5_create_srq {
 	__u64				buf_addr;
 	__u64				db_addr;
 	__u32				flags;
+	__u32				reserved;
 };
 
 struct mlx5_create_srq_resp {
src/verbs.c +4 -2
index 7201e94925c5..1de8692e5264 100644
@@ -261,7 +261,6 @@ struct ibv_cq *mlx5_create_cq(struct ibv_context *context, int cqe,
 		return NULL;
 	}
 
-	memset(&cmd, 0, sizeof cmd);
 	cq->cons_index = 0;
 
 	if (mlx5_spinlock_init(&cq->lock))
@@ -307,6 +306,7 @@ struct ibv_cq *mlx5_create_cq(struct ibv_context *context, int cqe,
 	cmd.buf_addr = (uintptr_t) cq->buf_a.buf;
 	cmd.db_addr  = (uintptr_t) cq->dbrec;
 	cmd.cqe_size = cqe_sz;
+	cmd.reserved = 0;
 
 	ret = ibv_cmd_create_cq(context, ncqe - 1, channel, comp_vector,
 				&cq->ibv_cq, &cmd.ibv_cmd, sizeof cmd,
@@ -442,7 +442,6 @@ struct ibv_srq *mlx5_create_srq(struct ibv_pd *pd,
 	}
 	ibsrq = &srq->srq;
 
-	memset(&cmd, 0, sizeof cmd);
 	if (mlx5_spinlock_init(&srq->lock)) {
 		fprintf(stderr, "%s-%d:\n", __func__, __LINE__);
 		goto err;
@@ -490,6 +489,9 @@ struct ibv_srq *mlx5_create_srq(struct ibv_pd *pd,
 	srq->wq_sig = srq_sig_enabled();
 	if (srq->wq_sig)
 		cmd.flags = MLX5_SRQ_FLAG_SIGNATURE;
+	else
+		cmd.flags = 0;
+	cmd.reserved = 0;
 
 	attr->attr.max_sge = srq->max_gs;
 	pthread_mutex_lock(&ctx->srq_table_mutex);
Signature · 6 lines
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#30 lore raw

Re: [PATCH for v3.15 0/4] uverbs ABI fixes

In reply to a message not in the archive

Hi,

Quoted 3 lines · Yann Droneaud

Please find 4 patches which fix some issues regarding missing explicit padding at end of structure exchanged between kernel and userspace.

I've made a review of all others drivers. I've identified the following structures as part of ABI:

cxgb3/iw_cxgb3.o     struct iwch_create_cq_req
cxgb3/iw_cxgb3.o     struct iwch_create_cq_resp
cxgb3/iw_cxgb3.o     struct iwch_create_qp_resp
cxgb3/iw_cxgb3.o     struct iwch_reg_user_mr_resp
cxgb4/iw_cxgb4.o     struct c4iw_alloc_ucontext_resp
cxgb4/iw_cxgb4.o     struct c4iw_create_cq_resp
cxgb4/iw_cxgb4.o     struct c4iw_create_qp_resp
ehca/ib_ehca.o       struct ehca_create_cq_resp
ehca/ib_ehca.o       struct ehca_create_qp_resp
ehca/ib_ehca.o       struct ipzu_queue_resp
mlx4/mlx4_ib.o       struct mlx4_ib_alloc_ucontext_resp
mlx4/mlx4_ib.o       struct mlx4_ib_alloc_ucontext_resp_v3
mlx4/mlx4_ib.o       struct mlx4_ib_create_cq
mlx4/mlx4_ib.o       struct mlx4_ib_create_qp
mlx4/mlx4_ib.o       struct mlx4_ib_create_srq
mlx4/mlx4_ib.o       struct mlx4_ib_resize_cq
mlx5/mlx5_ib.o       struct mlx5_ib_alloc_pd_resp
mlx5/mlx5_ib.o       struct mlx5_ib_alloc_ucontext_req_v2
mlx5/mlx5_ib.o       struct mlx5_ib_alloc_ucontext_resp
mlx5/mlx5_ib.o       struct mlx5_ib_create_cq
mlx5/mlx5_ib.o       struct mlx5_ib_create_qp
mlx5/mlx5_ib.o       struct mlx5_ib_create_qp_resp
mlx5/mlx5_ib.o       struct mlx5_ib_create_srq
mlx5/mlx5_ib.o       struct mlx5_ib_resize_cq
mthca/ib_mthca.o     struct mthca_alloc_ucontext_resp
mthca/ib_mthca.o     struct mthca_create_cq
mthca/ib_mthca.o     struct mthca_create_qp
mthca/ib_mthca.o     struct mthca_create_srq
mthca/ib_mthca.o     struct mthca_reg_mr
mthca/ib_mthca.o     struct mthca_resize_cq
nes/iw_nes.o         struct nes_alloc_pd_resp
nes/iw_nes.o         struct nes_alloc_ucontext_req
nes/iw_nes.o         struct nes_alloc_ucontext_resp
nes/iw_nes.o         struct nes_create_cq_req
nes/iw_nes.o         struct nes_create_cq_resp
nes/iw_nes.o         struct nes_create_qp_req
nes/iw_nes.o         struct nes_create_qp_resp
nes/iw_nes.o         struct nes_mem_reg_req
ocrdma/ocrdma.o      struct ocrdma_alloc_pd_uresp
ocrdma/ocrdma.o      struct ocrdma_alloc_ucontext_resp
ocrdma/ocrdma.o      struct ocrdma_create_cq_ureq
ocrdma/ocrdma.o      struct ocrdma_create_cq_uresp
ocrdma/ocrdma.o      struct ocrdma_create_qp_ureq
ocrdma/ocrdma.o      struct ocrdma_create_qp_uresp
ocrdma/ocrdma.o      struct ocrdma_create_srq_uresp
usnic/usnic_verbs.o  struct usnic_ib_create_qp_cmd
usnic/usnic_verbs.o  struct usnic_ib_create_qp_resp
usnic/usnic_verbs.o  struct usnic_transport_spec

It seems that amso1100/iw_c2.o, ipath/ib_ipath.o and qib/ib_qib.o don't make use of structure to exchange data with userspace: they use single values, either u32 or u64.

So using pahole I've found issues in mlx5 and cxgb4 only.

Quoted 14 lines

These makes i386 userspace libraries and x86_64 kernel disagree about the size of the structures.

Additionally, as reported by Dan Carpenter, in one case, stack information can be leaked by the kernel to userspace due to implicit padding being not initialized.

Unfortunately, the data structure cannot be fixed alone as it would break existing applications. So in order to remain compatible with i386 libraries, providers (hw) functions are modified to use the input length to guess the expected format of the command in order to check the content of the reserved field for future usage. Other are modified to not write the padding field in response to make the kernel able to handle gracefully i386 userspace on x86_64.

Quoted 4 lines

For full coherency, patches against the userspace libraries (libcxgb4 and libmlx5) will be submitted as a followup to update the data structure on userspace side.

BTW, as I don't have the hardware / I don't have access to the hardware, the patches are not tested against real world. (I only have HCAs handled by mlx4 and qib drivers).

Regards.

Signature · 8 lines
Yann Droneaud
OPTEYA


--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#31 lore raw

PATCH 2/4 RDMA/mlx5: add missing padding at end of struct mlx5_ib_create_srq

In reply to Yann Droneaud

i386 ABI disagree with most other ABIs regarding alignment of data type larger than 4 bytes: on most ABIs a padding must be added at end of the structures, while it is not required on i386.

So for most ABI struct mlx5_ib_create_srq get implicitly padded to be aligned on a 8 bytes multiple, while for i386, such padding is not added.

Tool pahole could be used to find such implicit padding:

  $ pahole --anon_include \
           --nested_anon_include \
           --recursive \
           --class_name mlx5_ib_create_srq \
           drivers/infiniband/hw/mlx5/mlx5_ib.o

Then, structure layout can be compared between i386 and x86_64:

  +++ obj-i386/drivers/infiniband/hw/mlx5/mlx5_ib.o.pahole.txt    2014-03-28 11:43:07.386413682 +0100
  --- obj-x86_64/drivers/infiniband/hw/mlx5/mlx5_ib.o.pahole.txt  2014-03-27 13:06:17.788472721 +0100
  @@ -69,7 +68,6 @@ struct mlx5_ib_create_srq {
          __u64                      db_addr;              /*     8     8 */
          __u32                      flags;                /*    16     4 */
  -       /* size: 20, cachelines: 1, members: 3 */
  -       /* last cacheline: 20 bytes */
  +       /* size: 24, cachelines: 1, members: 3 */
  +       /* padding: 4 */
  +       /* last cacheline: 24 bytes */

};

ABI disagreement will make an x86_64 kernel try to read past the buffer provided by an i386 binary.

When boundary check will be implemented, the x86_64 kernel will refuse to read past the i386 userspace provided buffer and the uverb will fail.

Anyway, if the structure lay in memory on a page boundary and next page is not mapped, ib_copy_from_udata() will fail and the uverb will fail.

This patch makes create_srq_user() takes care of the input data size to handle the case where no padding was provided.

This way, x86_64 kernel will be able to handle struct mlx5_ib_create_srq as sent by unpatched and patched i386 libmlx5.

Fixes e126ba97dba9e ('mlx5: Add driver for Mellanox Connect-IB adapter')
---
 drivers/infiniband/hw/mlx5/srq.c  | 18 +++++++++++++++---
 drivers/infiniband/hw/mlx5/user.h |  1 +
 2 files changed, 16 insertions(+), 3 deletions(-)
drivers/infiniband/hw/mlx5/srq.c +15 -3
index 210b3eaf188a..38ca52181eb6 100644
@@ -35,6 +35,7 @@
 #include <linux/mlx5/srq.h>
 #include <linux/slab.h>
 #include <rdma/ib_umem.h>
+#include <rdma/ib_user_verbs.h>
 
 #include "mlx5_ib.h"
 #include "user.h"
@@ -84,10 +85,21 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
 	int ncont;
 	u32 offset;
 
-	if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
-		mlx5_ib_dbg(dev, "failed copy udata\n");
-		return -EFAULT;
+	if (udata->inlen - sizeof(struct ib_uverbs_cmd_hdr) < sizeof(ucmd)) {
+		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd) - sizeof(ucmd.reserved))) {
+			mlx5_ib_dbg(dev, "failed copy udata\n");
+			return -EFAULT;
+		}
+	} else {
+		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
+			mlx5_ib_dbg(dev, "failed copy udata\n");
+			return -EFAULT;
+		}
+
+		if (ucmd.reserved != 0)
+			return -EINVAL;
 	}
+
 	srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE);
 
 	srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, buf_size,
drivers/infiniband/hw/mlx5/user.h +1 -0
index d44ecd2c2faf..d0ba264ac1ed 100644
@@ -110,6 +110,7 @@ struct mlx5_ib_create_srq {
 	__u64	buf_addr;
 	__u64	db_addr;
 	__u32	flags;
+	__u32	reserved; /* explicit padding (optional on i386) */
 };
 
 struct mlx5_ib_create_srq_resp {
Signature · 1 line
1.9.0
#32 lore raw

Re: [patch] RDMA/cxgb4: info leak in c4iw_alloc_ucontext()

In reply to Dan Carpenter

Hi,

Quoted 11 lines · Dan Carpenter
Quoted 4 lines · Yann Droneaud

Unfortunately, it's not the only structure which has this problem. I'm currently preparing a report on this issue for this driver (cxgb4) and another.

This information leak is still present in linux-next. These days we count those things as security vulnerabilities with CVEs and everything.

When is it likely to get fixed?

Thanks for the reminder.

The patches were waiting for some times in my patch queue, I failed to provide them earlier. BTW, I've taken time during the week end to complete them. They should be available on [email protected]. See http://marc.info/[email protected]

Regards.

Signature · 2 lines
Yann Droneaud
OPTEYA