[PATCH rdma-next] RDMA: Check the gid_index provided by users space for the namespace

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Parav Pandit <parav@xxxxxxxxxxxx>

Restrict user space users from passing a gid_index that refers to a net
device outside their net namespace. This covers sysfs GID attribute
access and uverbs users.

Signed-off-by: Parav Pandit <parav@xxxxxxxxxxxx>
Signed-off-by: Jason Gunthorpe <jgg@xxxxxxxxxxxx>
Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxxxx>
---
 drivers/infiniband/core/cache.c | 34 +++++++++++++++++++++++++++++-----
 drivers/infiniband/core/sysfs.c |  7 ++++---
 drivers/infiniband/core/verbs.c | 23 +++++++++++++++--------
 include/rdma/ib_cache.h         | 19 +++++++++++++++++--
 4 files changed, 65 insertions(+), 18 deletions(-)

diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 0bee1f4b914e..ff3148ac47a6 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -1172,13 +1172,17 @@ int ib_get_cached_port_state(struct ib_device   *device,
 EXPORT_SYMBOL(ib_get_cached_port_state);
 
 /**
- * rdma_get_gid_attr - Returns GID attributes for a port of a device
+ * _rdma_get_gid_attr - Returns GID attributes for a port of a device
  * at a requested gid_index, if a valid GID entry exists.
  * @device:		The device to query.
  * @port_num:		The port number on the device where the GID value
  *			is to be queried.
  * @index:		Index of the GID table entry whose attributes are to
  *                      be queried.
+ * @net:		If not NULL, check that the net of gid attritube and
+ *			provided net are same. This is optional parameter
+ *			applicable and meaningful only when a GID attribute
+ *			has valid netdevice.
  *
  * rdma_get_gid_attr() acquires reference count of gid attributes from the
  * cached GID table. Caller must invoke rdma_put_gid_attr() to release
@@ -1187,8 +1191,9 @@ EXPORT_SYMBOL(ib_get_cached_port_state);
  * Returns pointer to valid gid attribute or ERR_PTR for the appropriate error
  * code.
  */
-const struct ib_gid_attr *
-rdma_get_gid_attr(struct ib_device *device, u8 port_num, int index)
+const struct ib_gid_attr *_rdma_get_gid_attr(struct ib_device *device,
+					     u8 port_num, int index,
+					     struct net *net)
 {
 	const struct ib_gid_attr *attr = ERR_PTR(-EINVAL);
 	struct ib_gid_table *table;
@@ -1205,13 +1210,32 @@ rdma_get_gid_attr(struct ib_device *device, u8 port_num, int index)
 	if (!is_gid_entry_valid(table->data_vec[index]))
 		goto done;
 
-	get_gid_entry(table->data_vec[index]);
 	attr = &table->data_vec[index]->attr;
+
+	/*
+	 * If this is user space requesting access, the caller must be in a
+	 * process context and must have the same net namespace.
+	 */
+	if (net && attr->ndev) {
+		bool matches;
+
+		rcu_read_lock();
+		matches = net_eq(dev_net(attr->ndev), net);
+		rcu_read_unlock();
+
+		if (!matches) {
+			attr = ERR_PTR(-EINVAL);
+			goto done;
+		}
+	}
+
+	get_gid_entry(table->data_vec[index]);
+
 done:
 	read_unlock_irqrestore(&table->rwlock, flags);
 	return attr;
 }
-EXPORT_SYMBOL(rdma_get_gid_attr);
+EXPORT_SYMBOL(_rdma_get_gid_attr);
 
 /**
  * rdma_put_gid_attr - Release reference to the GID attribute
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 7fd14ead7b37..edb8ff1a2c32 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -369,10 +369,10 @@ static ssize_t _show_port_gid_attr(
 	const struct ib_gid_attr *gid_attr;
 	ssize_t ret;
 
-	gid_attr = rdma_get_gid_attr(p->ibdev, p->port_num, tab_attr->index);
+	gid_attr =
+		rdma_get_user_gid_attr(p->ibdev, p->port_num, tab_attr->index);
 	if (IS_ERR(gid_attr))
 		return PTR_ERR(gid_attr);
-
 	ret = print(gid_attr, buf);
 	rdma_put_gid_attr(gid_attr);
 	return ret;
@@ -386,7 +386,8 @@ static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr,
 	const struct ib_gid_attr *gid_attr;
 	ssize_t ret;
 
-	gid_attr = rdma_get_gid_attr(p->ibdev, p->port_num, tab_attr->index);
+	gid_attr =
+		rdma_get_user_gid_attr(p->ibdev, p->port_num, tab_attr->index);
 	if (IS_ERR(gid_attr)) {
 		const union ib_gid zgid = {};
 
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index b6ceb6fd6a67..cd093d81de4d 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -413,7 +413,8 @@ static int rdma_check_ah_attr(struct ib_device *device,
  */
 static int rdma_fill_sgid_attr(struct ib_device *device,
 			       struct rdma_ah_attr *ah_attr,
-			       const struct ib_gid_attr **old_sgid_attr)
+			       const struct ib_gid_attr **old_sgid_attr,
+			       bool is_user)
 {
 	const struct ib_gid_attr *sgid_attr;
 	struct ib_global_route *grh;
@@ -432,8 +433,13 @@ static int rdma_fill_sgid_attr(struct ib_device *device,
 	if (grh->sgid_attr)
 		return 0;
 
-	sgid_attr =
-		rdma_get_gid_attr(device, ah_attr->port_num, grh->sgid_index);
+	if (is_user)
+		sgid_attr = rdma_get_user_gid_attr(device, ah_attr->port_num,
+						   grh->sgid_index);
+	else
+		sgid_attr = rdma_get_gid_attr(device, ah_attr->port_num,
+					      grh->sgid_index);
+
 	if (IS_ERR(sgid_attr))
 		return PTR_ERR(sgid_attr);
 
@@ -510,7 +516,7 @@ struct ib_ah *rdma_create_ah(struct ib_pd *pd, struct rdma_ah_attr *ah_attr)
 	struct ib_ah *ah;
 	int ret;
 
-	ret = rdma_fill_sgid_attr(pd->device, ah_attr, &old_sgid_attr);
+	ret = rdma_fill_sgid_attr(pd->device, ah_attr, &old_sgid_attr, false);
 	if (ret)
 		return ERR_PTR(ret);
 
@@ -542,7 +548,8 @@ struct ib_ah *rdma_create_user_ah(struct ib_pd *pd,
 	struct ib_ah *ah;
 	int err;
 
-	err = rdma_fill_sgid_attr(pd->device, ah_attr, &old_sgid_attr);
+	err = rdma_fill_sgid_attr(pd->device, ah_attr, &old_sgid_attr,
+				  true);
 	if (err)
 		return ERR_PTR(err);
 
@@ -881,7 +888,7 @@ int rdma_modify_ah(struct ib_ah *ah, struct rdma_ah_attr *ah_attr)
 	if (ah->type != ah_attr->type)
 		return -EINVAL;
 
-	ret = rdma_fill_sgid_attr(ah->device, ah_attr, &old_sgid_attr);
+	ret = rdma_fill_sgid_attr(ah->device, ah_attr, &old_sgid_attr, false);
 	if (ret)
 		return ret;
 
@@ -1583,7 +1590,7 @@ static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
 
 	if (attr_mask & IB_QP_AV) {
 		ret = rdma_fill_sgid_attr(qp->device, &attr->ah_attr,
-					  &old_sgid_attr_av);
+					  &old_sgid_attr_av, udata != NULL);
 		if (ret)
 			return ret;
 	}
@@ -1596,7 +1603,7 @@ static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
 		 * counting does not serve any functional purpose.
 		 */
 		ret = rdma_fill_sgid_attr(qp->device, &attr->alt_ah_attr,
-					  &old_sgid_attr_alt_av);
+					  &old_sgid_attr_alt_av, udata != NULL);
 		if (ret)
 			goto out_av;
 
diff --git a/include/rdma/ib_cache.h b/include/rdma/ib_cache.h
index 1108d4220276..511ff6be503a 100644
--- a/include/rdma/ib_cache.h
+++ b/include/rdma/ib_cache.h
@@ -128,8 +128,23 @@ int ib_get_cached_port_state(struct ib_device *device,
 			      enum ib_port_state *port_active);
 
 bool rdma_is_zero_gid(const union ib_gid *gid);
-const struct ib_gid_attr *rdma_get_gid_attr(struct ib_device *device,
-					    u8 port_num, int index);
+
+const struct ib_gid_attr *_rdma_get_gid_attr(struct ib_device *device,
+					     u8 port_num, int index,
+					     struct net *net);
+static inline const struct ib_gid_attr *
+rdma_get_gid_attr(struct ib_device *device, u8 port_num, int index)
+{
+	return _rdma_get_gid_attr(device, port_num, index, NULL);
+}
+
+static inline const struct ib_gid_attr *
+rdma_get_user_gid_attr(struct ib_device *device, u8 port_num, int index)
+{
+	return _rdma_get_gid_attr(device, port_num,
+				  index, current->nsproxy->net_ns);
+}
+
 void rdma_put_gid_attr(const struct ib_gid_attr *attr);
 void rdma_hold_gid_attr(const struct ib_gid_attr *attr);
 #endif /* _IB_CACHE_H */
-- 
2.14.4

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



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux