Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 2 Aug 2018 08:22:53 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r337085 - in stable/11/sys/ofed: drivers/infiniband/core include/rdma
Message-ID:  <201808020822.w728MrxP044604@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Thu Aug  2 08:22:53 2018
New Revision: 337085
URL: https://svnweb.freebsd.org/changeset/base/337085

Log:
  MFC r336380:
  Check AF family prior resolving address and introduce safer rdma_addr_size() variants in ibcore.
  
  Garbage supplied by user will cause to UCMA module provide zero
  memory size for memcpy(), because it wasn't checked, it will
  produce unpredictable results in rdma_resolve_addr().
  
  There are several places in the ucma ABI where userspace can pass in a
  sockaddr but set the address family to AF_IB.  When that happens,
  rdma_addr_size() will return a size bigger than sizeof struct sockaddr_in6,
  and the ucma kernel code might end up copying past the end of a buffer
  not sized for a struct sockaddr_ib.
  
  Fix this by introducing new variants
      int rdma_addr_size_in6(struct sockaddr_in6 *addr);
      int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr);
  
  that are type-safe for the types used in the ucma ABI and return 0 if the
  size computed is bigger than the size of the type passed in.  We can use
  these new variants to check what size userspace has passed in before
  copying any addresses.
  
  Linux commit:
  2975d5de6428ff6d9317e9948f0968f7d42e5d74
  09abfe7b5b2f442a85f4c4d59ecf582ad76088d7
  84652aefb347297aa08e91e283adf7b18f77c2d5
  
  Sponsored by:		Mellanox Technologies

Modified:
  stable/11/sys/ofed/drivers/infiniband/core/ib_addr.c
  stable/11/sys/ofed/drivers/infiniband/core/ib_ucma.c
  stable/11/sys/ofed/include/rdma/ib_addr.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/ofed/drivers/infiniband/core/ib_addr.c
==============================================================================
--- stable/11/sys/ofed/drivers/infiniband/core/ib_addr.c	Thu Aug  2 08:21:55 2018	(r337084)
+++ stable/11/sys/ofed/drivers/infiniband/core/ib_addr.c	Thu Aug  2 08:22:53 2018	(r337085)
@@ -89,6 +89,22 @@ int rdma_addr_size(struct sockaddr *addr)
 }
 EXPORT_SYMBOL(rdma_addr_size);
 
+int rdma_addr_size_in6(struct sockaddr_in6 *addr)
+{
+	int ret = rdma_addr_size((struct sockaddr *) addr);
+
+	return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_in6);
+
+int rdma_addr_size_kss(struct sockaddr_storage *addr)
+{
+	int ret = rdma_addr_size((struct sockaddr *) addr);
+
+	return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_kss);
+
 static struct rdma_addr_client self;
 
 void rdma_addr_register_client(struct rdma_addr_client *client)

Modified: stable/11/sys/ofed/drivers/infiniband/core/ib_ucma.c
==============================================================================
--- stable/11/sys/ofed/drivers/infiniband/core/ib_ucma.c	Thu Aug  2 08:21:55 2018	(r337084)
+++ stable/11/sys/ofed/drivers/infiniband/core/ib_ucma.c	Thu Aug  2 08:22:53 2018	(r337085)
@@ -636,6 +636,9 @@ static ssize_t ucma_bind_ip(struct ucma_file *file, co
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
+	if (!rdma_addr_size_in6(&cmd.addr))
+		return -EINVAL;
+
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
@@ -649,22 +652,21 @@ static ssize_t ucma_bind(struct ucma_file *file, const
 			 int in_len, int out_len)
 {
 	struct rdma_ucm_bind cmd;
-	struct sockaddr *addr;
 	struct ucma_context *ctx;
 	int ret;
 
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
-	addr = (struct sockaddr *) &cmd.addr;
-	if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
+	if (cmd.reserved || !cmd.addr_size ||
+	    cmd.addr_size != rdma_addr_size_kss(&cmd.addr))
 		return -EINVAL;
 
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ret = rdma_bind_addr(ctx->cm_id, addr);
+	ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -680,13 +682,16 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file,
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
+	if ((cmd.src_addr.sin6_family && !rdma_addr_size_in6(&cmd.src_addr)) ||
+	    !rdma_addr_size_in6(&cmd.dst_addr))
+		return -EINVAL;
+
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
 	ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
-				(struct sockaddr *) &cmd.dst_addr,
-				cmd.timeout_ms);
+				(struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -696,24 +701,23 @@ static ssize_t ucma_resolve_addr(struct ucma_file *fil
 				 int in_len, int out_len)
 {
 	struct rdma_ucm_resolve_addr cmd;
-	struct sockaddr *src, *dst;
 	struct ucma_context *ctx;
 	int ret;
 
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
-	src = (struct sockaddr *) &cmd.src_addr;
-	dst = (struct sockaddr *) &cmd.dst_addr;
-	if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
-	    !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
+	if (cmd.reserved ||
+	    (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) ||
+	    !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr)))
 		return -EINVAL;
 
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
+	ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
+				(struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1403,7 +1407,7 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file
 	join_cmd.response = cmd.response;
 	join_cmd.uid = cmd.uid;
 	join_cmd.id = cmd.id;
-	join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr);
+	join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr);
 	join_cmd.join_flags = RDMA_MC_JOIN_FLAG_FULLMEMBER;
 	memcpy(&join_cmd.addr, &cmd.addr, join_cmd.addr_size);
 
@@ -1418,6 +1422,9 @@ static ssize_t ucma_join_multicast(struct ucma_file *f
 
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
+
+	if (!rdma_addr_size_kss(&cmd.addr))
+		return -EINVAL;
 
 	return ucma_process_join(file, &cmd, out_len);
 }

Modified: stable/11/sys/ofed/include/rdma/ib_addr.h
==============================================================================
--- stable/11/sys/ofed/include/rdma/ib_addr.h	Thu Aug  2 08:21:55 2018	(r337084)
+++ stable/11/sys/ofed/include/rdma/ib_addr.h	Thu Aug  2 08:22:53 2018	(r337085)
@@ -131,6 +131,8 @@ int rdma_copy_addr(struct rdma_dev_addr *dev_addr, str
 	      const unsigned char *dst_dev_addr);
 
 int rdma_addr_size(struct sockaddr *addr);
+int rdma_addr_size_in6(struct sockaddr_in6 *addr);
+int rdma_addr_size_kss(struct sockaddr_storage *addr);
 
 int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
 				 const union ib_gid *dgid,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808020822.w728MrxP044604>