diff mbox series

[rdma-rc] RDMA/uverbs: Mark ioctl responses with UVERBS_ATTR_F_VALID_OUTPUT

Message ID 20190111062144.3589-1-leon@kernel.org (mailing list archive)
State Mainlined
Commit d6f4a21f309dfe10a5693ad236358dd6fcc46f7a
Delegated to: Jason Gunthorpe
Headers show
Series [rdma-rc] RDMA/uverbs: Mark ioctl responses with UVERBS_ATTR_F_VALID_OUTPUT | expand

Commit Message

Leon Romanovsky Jan. 11, 2019, 6:21 a.m. UTC
From: Jason Gunthorpe <jgg@mellanox.com>

When the ioctl interface for the write commands was introduced it did
not mark the core response with UVERBS_ATTR_F_VALID_OUTPUT. This causes
rdma-core in userspace to not mark the buffers as written for valgrind.

Along the same lines it turns out we have always missed marking the driver
data. Fixing both of these makes valgrind work properly with rdma-core and
ioctl.

Fixes: 4785860e04bc ("RDMA/uverbs: Implement an ioctl that can call write and write_ex handlers")
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Reviewed-by: Artemy Kovalyov <artemyko@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
---
 drivers/infiniband/core/rdma_core.h    |  2 +
 drivers/infiniband/core/uverbs_cmd.c   |  7 +++
 drivers/infiniband/core/uverbs_ioctl.c | 62 ++++++++++++++++++++------
 drivers/infiniband/core/uverbs_main.c  |  1 +
 4 files changed, 59 insertions(+), 13 deletions(-)

Comments

Jason Gunthorpe Jan. 14, 2019, 9:03 p.m. UTC | #1
On Fri, Jan 11, 2019 at 08:21:44AM +0200, Leon Romanovsky wrote:
> From: Jason Gunthorpe <jgg@mellanox.com>
> 
> When the ioctl interface for the write commands was introduced it did
> not mark the core response with UVERBS_ATTR_F_VALID_OUTPUT. This causes
> rdma-core in userspace to not mark the buffers as written for valgrind.
> 
> Along the same lines it turns out we have always missed marking the driver
> data. Fixing both of these makes valgrind work properly with rdma-core and
> ioctl.
> 
> Fixes: 4785860e04bc ("RDMA/uverbs: Implement an ioctl that can call write and write_ex handlers")
> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
> Reviewed-by: Artemy Kovalyov <artemyko@mellanox.com>
> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
> ---
>  drivers/infiniband/core/rdma_core.h    |  2 +
>  drivers/infiniband/core/uverbs_cmd.c   |  7 +++
>  drivers/infiniband/core/uverbs_ioctl.c | 62 ++++++++++++++++++++------
>  drivers/infiniband/core/uverbs_main.c  |  1 +
>  4 files changed, 59 insertions(+), 13 deletions(-)

Applied to for-next

Thanks,
Jason
Jason Gunthorpe Jan. 14, 2019, 9:04 p.m. UTC | #2
On Mon, Jan 14, 2019 at 02:03:12PM -0700, Jason Gunthorpe wrote:
> On Fri, Jan 11, 2019 at 08:21:44AM +0200, Leon Romanovsky wrote:
> > From: Jason Gunthorpe <jgg@mellanox.com>
> > 
> > When the ioctl interface for the write commands was introduced it did
> > not mark the core response with UVERBS_ATTR_F_VALID_OUTPUT. This causes
> > rdma-core in userspace to not mark the buffers as written for valgrind.
> > 
> > Along the same lines it turns out we have always missed marking the driver
> > data. Fixing both of these makes valgrind work properly with rdma-core and
> > ioctl.
> > 
> > Fixes: 4785860e04bc ("RDMA/uverbs: Implement an ioctl that can call write and write_ex handlers")
> > Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
> > Reviewed-by: Artemy Kovalyov <artemyko@mellanox.com>
> > Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
> >  drivers/infiniband/core/rdma_core.h    |  2 +
> >  drivers/infiniband/core/uverbs_cmd.c   |  7 +++
> >  drivers/infiniband/core/uverbs_ioctl.c | 62 ++++++++++++++++++++------
> >  drivers/infiniband/core/uverbs_main.c  |  1 +
> >  4 files changed, 59 insertions(+), 13 deletions(-)
> 
> Applied to for-next

woops, I mean for-rc

Jason
Bart Van Assche Feb. 14, 2019, 2:29 a.m. UTC | #3
On 1/10/19 10:21 PM, Leon Romanovsky wrote:
> --- a/drivers/infiniband/core/uverbs_cmd.c
> +++ b/drivers/infiniband/core/uverbs_cmd.c
> @@ -60,6 +60,10 @@ static int uverbs_response(struct uverbs_attr_bundle *attrs, const void *resp,
>   {
>   	int ret;
>   
> +	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
> +		return uverbs_copy_to_struct_or_zero(
> +			attrs, UVERBS_ATTR_CORE_OUT, resp, resp_len);
> +
>   	if (copy_to_user(attrs->ucore.outbuf, resp,
>   			 min(attrs->ucore.outlen, resp_len)))
>   		return -EFAULT;
> @@ -1181,6 +1185,9 @@ static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs)
>   		goto out_put;
>   	}
>   
> +	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
> +		ret = uverbs_output_written(attrs, UVERBS_ATTR_CORE_OUT);
> +
>   	ret = 0;
>   

Hi Leon,

Coverity reports about this code that the value returned by 
uverbs_output_written() is overwritten before it is used.

Bart.
Jason Gunthorpe Feb. 14, 2019, 5:52 a.m. UTC | #4
On Wed, Feb 13, 2019 at 06:29:22PM -0800, Bart Van Assche wrote:
> On 1/10/19 10:21 PM, Leon Romanovsky wrote:
> > +++ b/drivers/infiniband/core/uverbs_cmd.c
> > @@ -60,6 +60,10 @@ static int uverbs_response(struct uverbs_attr_bundle *attrs, const void *resp,
> >   {
> >   	int ret;
> > +	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
> > +		return uverbs_copy_to_struct_or_zero(
> > +			attrs, UVERBS_ATTR_CORE_OUT, resp, resp_len);
> > +
> >   	if (copy_to_user(attrs->ucore.outbuf, resp,
> >   			 min(attrs->ucore.outlen, resp_len)))
> >   		return -EFAULT;
> > @@ -1181,6 +1185,9 @@ static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs)
> >   		goto out_put;
> >   	}
> > +	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
> > +		ret = uverbs_output_written(attrs, UVERBS_ATTR_CORE_OUT);
> > +
> >   	ret = 0;
> 
> Hi Leon,
> 
> Coverity reports about this code that the value returned by
> uverbs_output_written() is overwritten before it is used.

Indeed, the ret = 0 should be done before the if.

Jason
diff mbox series

Patch

diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index be6b8e1257d0..69f8db66925e 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -106,6 +106,8 @@  int uverbs_finalize_object(struct ib_uobject *uobj,
 			   enum uverbs_obj_access access,
 			   bool commit);
 
+int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx);
+
 void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile);
 void release_ufile_idr_uobject(struct ib_uverbs_file *ufile);
 
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 1b82cb74276c..3317300ab036 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -60,6 +60,10 @@  static int uverbs_response(struct uverbs_attr_bundle *attrs, const void *resp,
 {
 	int ret;
 
+	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
+		return uverbs_copy_to_struct_or_zero(
+			attrs, UVERBS_ATTR_CORE_OUT, resp, resp_len);
+
 	if (copy_to_user(attrs->ucore.outbuf, resp,
 			 min(attrs->ucore.outlen, resp_len)))
 		return -EFAULT;
@@ -1181,6 +1185,9 @@  static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs)
 		goto out_put;
 	}
 
+	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
+		ret = uverbs_output_written(attrs, UVERBS_ATTR_CORE_OUT);
+
 	ret = 0;
 
 out_put:
diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index 8c81ff698052..0ca04d224015 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -144,6 +144,21 @@  static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
 			   0, uattr->len - len);
 }
 
+static int uverbs_set_output(const struct uverbs_attr_bundle *bundle,
+			     const struct uverbs_attr *attr)
+{
+	struct bundle_priv *pbundle =
+		container_of(bundle, struct bundle_priv, bundle);
+	u16 flags;
+
+	flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
+		UVERBS_ATTR_F_VALID_OUTPUT;
+	if (put_user(flags,
+		     &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
+		return -EFAULT;
+	return 0;
+}
+
 static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
 				     const struct uverbs_api_attr *attr_uapi,
 				     struct uverbs_objs_arr_attr *attr,
@@ -455,6 +470,19 @@  static int ib_uverbs_run_method(struct bundle_priv *pbundle,
 		ret = handler(&pbundle->bundle);
 	}
 
+	/*
+	 * Until the drivers are revised to use the bundle directly we have to
+	 * assume that the driver wrote to its UHW_OUT and flag userspace
+	 * appropriately.
+	 */
+	if (!ret && pbundle->method_elm->has_udata) {
+		const struct uverbs_attr *attr =
+			uverbs_attr_get(&pbundle->bundle, UVERBS_ATTR_UHW_OUT);
+
+		if (!IS_ERR(attr))
+			ret = uverbs_set_output(&pbundle->bundle, attr);
+	}
+
 	/*
 	 * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can
 	 * not invoke the method because the request is not supported.  No
@@ -706,10 +734,7 @@  void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
 int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
 		   const void *from, size_t size)
 {
-	struct bundle_priv *pbundle =
-		container_of(bundle, struct bundle_priv, bundle);
 	const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
-	u16 flags;
 	size_t min_size;
 
 	if (IS_ERR(attr))
@@ -719,16 +744,25 @@  int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
 	if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
 		return -EFAULT;
 
-	flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
-		UVERBS_ATTR_F_VALID_OUTPUT;
-	if (put_user(flags,
-		     &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
-		return -EFAULT;
-
-	return 0;
+	return uverbs_set_output(bundle, attr);
 }
 EXPORT_SYMBOL(uverbs_copy_to);
 
+
+/*
+ * This is only used if the caller has directly used copy_to_use to write the
+ * data.  It signals to user space that the buffer is filled in.
+ */
+int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx)
+{
+	const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
+
+	if (IS_ERR(attr))
+		return PTR_ERR(attr);
+
+	return uverbs_set_output(bundle, attr);
+}
+
 int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle,
 		      size_t idx, s64 lower_bound, u64 upper_bound,
 		      s64  *def_val)
@@ -757,8 +791,10 @@  int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle,
 {
 	const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
 
-	if (clear_user(u64_to_user_ptr(attr->ptr_attr.data),
-		       attr->ptr_attr.len))
-		return -EFAULT;
+	if (size < attr->ptr_attr.len) {
+		if (clear_user(u64_to_user_ptr(attr->ptr_attr.data) + size,
+			       attr->ptr_attr.len - size))
+			return -EFAULT;
+	}
 	return uverbs_copy_to(bundle, idx, from, size);
 }
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index fb0007aa0c27..2890a77339e1 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -690,6 +690,7 @@  static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
 
 	buf += sizeof(hdr);
 
+	memset(bundle.attr_present, 0, sizeof(bundle.attr_present));
 	bundle.ufile = file;
 	if (!method_elm->is_ex) {
 		size_t in_len = hdr.in_words * 4 - sizeof(hdr);