* [PATCH 1/4] IB/uverbs: check userspace input buffer size
[not found] ` <cover.1405884453.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
@ 2014-07-20 19:51 ` Yann Droneaud
2014-07-20 19:51 ` [PATCH 2/4] IB/uverbs: check userspace output " Yann Droneaud
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Yann Droneaud @ 2014-07-20 19:51 UTC (permalink / raw)
To: Roland Dreier, Sean Hefty, Hal Rosenstock
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
This patch makes uverbs functions check the length of the input
buffer before reading the command content.
This will detect truncated command and will prevent uverbs from
reading past userspace provided buffer.
Additionally, it will also prevent underflow while computing
remaining input space. Such underflow would set inlen field in
struct ib_udata in call to INIT_UDATA() to a meaningless value.
For example:
INIT_UDATA(&udata, buf + sizeof cmd,
(unsigned long) cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
If in_len is less than sizeof(cmd), the result of subtraction
is a negative value since in_len is an int per function prototype.
But inlen field in struct ib_udata is unsigned, so the result is
an overly large value in struct ib_udata. Such value will make
further size checking useless, allowing more out of bound read
in providers (eg. hw/) code.
Note that checking the input size and preventing the underflow
and/or overflow might break existing userspace program that
incorrectly set the buffer length in a uverbs request.
It's theoretically possible for a userspace driver to send
a request with a wrong size that can still be processed
correctly with the kernel:
Let's build a request through fake 'libibverbs' and
'libvendor-rdma' userspace driver.
It's a request which might be valid with current kernel
but will set inlen to (size_t) -1 while it will be possible
for vendor driver (eg. provider, under hw/) to read vendor
fields:
#include <infiniband/kern-abi.h>
/* aka. struct ib_uverbs_cmd_hdr */
struct ibv_cmd_hdr {
__u32 command;
__u16 in_words;
__u16 out_words;
};
struct vendor_create_cq {
struct ibv_create_cq ibv_cmd;
/* vendor defined fields */
};
struct vendor_create_cq_resp resp {
struct ibv_create_cq_resp ibv_resp;
/* vendor defined fields */
};
struct ibv_cq *vendor_create_cq_broken_inlen(...)
{
struct vendor_create_cq cmd;
struct vendor_create_cq_resp resp;
size_t cmd_size;
/* the command header size must be subtracted here
to ensure (inlen - sizeof(struct ib_uverbs_create_cq)
is equal to 0 in ib_uverbs_create_cq(), as the header
size is not subtracted in ib_uverbs_write() before
invoking ib_uverbs_create_cq() */
assert(sizeof(struct ibv_create_cq) >= sizeof(struct ibv_cmd_hdr));
cmd_size = sizeof(struct ibv_create_cq) -
sizeof(struct ibv_cmd_hdr);
/* instead of 0, make (inlen - sizeof(cmd)) underflow */
cmd_size--;
/* For the command to be valid in ib_uverbs_write(),
it size must be at least equal to sizeof(struct
ib_uverbs_cmd_hdr). */
assert(cmd_size >= sizeof(struct ibv_cmd_hdr));
...
IBV_INIT_CMD_RESP(&cmd,
cmd_size,
CREATE_CQ,
&resp,
sizeof(resp));
...
write(context->cmd_fd,
&cmd,
cmd_size);
...
}
This example shows how a request can be created to trigger
un-handled underflow while allowing provider (eg. hw/) to
process the request.
The provided patch will make it impossible to do it on
patched kernels, but might make unknown broken applications
fail.
Link: http://marc.info/?i=cover.1405884453.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org
Link: http://marc.info/?i=1387493822.11925.217.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_cmd.c | 102 +++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index ea6203ee7bcc..353cbd5229bb 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -292,6 +292,9 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
struct file *filp;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -387,6 +390,9 @@ ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
struct ib_device_attr attr;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -456,6 +462,9 @@ ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file,
struct ib_port_attr attr;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -508,6 +517,9 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
struct ib_pd *pd;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -579,6 +591,9 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
struct ib_uobject *uobj;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -705,6 +720,9 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
int ret = 0;
int new_xrcd = 0;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -840,6 +858,9 @@ ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file,
int live;
int ret = 0;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -917,6 +938,9 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
struct ib_mr *mr;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -1011,6 +1035,9 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
struct ib_uobject *uobj;
int ret = -EINVAL;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1051,6 +1078,9 @@ ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file,
struct ib_mw *mw;
int ret;
+ if (in_len < sizeof(cmd))
+ return -EINVAL;
+
if (out_len < sizeof(resp))
return -ENOSPC;
@@ -1131,6 +1161,9 @@ ssize_t ib_uverbs_dealloc_mw(struct ib_uverbs_file *file,
struct ib_uobject *uobj;
int ret = -EINVAL;
+ if (in_len < sizeof(cmd))
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof(cmd)))
return -EFAULT;
@@ -1169,6 +1202,9 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
struct file *filp;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -1209,6 +1245,9 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
struct ib_cq *cq;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -1308,6 +1347,9 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
struct ib_cq *cq;
int ret = -EINVAL;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1373,6 +1415,9 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
struct ib_wc wc;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1419,6 +1464,9 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
struct ib_uverbs_req_notify_cq cmd;
struct ib_cq *cq;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1446,6 +1494,9 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
struct ib_uverbs_event_file *ev_file;
int ret = -EINVAL;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1504,6 +1555,9 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
struct ib_qp_init_attr attr;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -1694,6 +1748,9 @@ ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
struct ib_qp_open_attr attr;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -1786,6 +1843,9 @@ ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
struct ib_qp_init_attr *init_attr;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1899,6 +1959,9 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
struct ib_qp_attr *attr;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1995,6 +2058,9 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
struct ib_uqp_object *obj;
int ret = -EINVAL;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2055,6 +2121,9 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
int is_ud;
ssize_t ret = -EINVAL;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2296,6 +2365,9 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
struct ib_qp *qp;
ssize_t ret = -EINVAL;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2345,6 +2417,9 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
struct ib_srq *srq;
ssize_t ret = -EINVAL;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2396,6 +2471,9 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
struct ib_ah_attr attr;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -2482,6 +2560,9 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
struct ib_uobject *uobj;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2520,6 +2601,9 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
struct ib_uverbs_mcast_entry *mcast;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2567,6 +2651,9 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
struct ib_uverbs_mcast_entry *mcast;
int ret = -EINVAL;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2982,6 +3069,9 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
struct ib_udata udata;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -3015,6 +3105,9 @@ ssize_t ib_uverbs_create_xsrq(struct ib_uverbs_file *file,
struct ib_udata udata;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -3042,6 +3135,9 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
struct ib_srq_attr attr;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -3072,6 +3168,9 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
struct ib_srq *srq;
int ret;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (out_len < sizeof resp)
return -ENOSPC;
@@ -3115,6 +3214,9 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
struct ib_usrq_object *us;
enum ib_srq_type srq_type;
+ if (in_len < sizeof cmd)
+ return -EINVAL;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
--
1.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/4] IB/uverbs: check userspace output buffer size
[not found] ` <cover.1405884453.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
2014-07-20 19:51 ` [PATCH 1/4] IB/uverbs: check userspace input buffer size Yann Droneaud
@ 2014-07-20 19:51 ` Yann Droneaud
2014-07-20 19:51 ` [PATCH 3/4] IB/uverbs: check userspace output buffer size in ib_uverbs_poll_cq() Yann Droneaud
2014-07-20 19:51 ` [PATCH 4/4] IB/uverbs: subtract command header from input size Yann Droneaud
3 siblings, 0 replies; 5+ messages in thread
From: Yann Droneaud @ 2014-07-20 19:51 UTC (permalink / raw)
To: Roland Dreier, Sean Hefty, Hal Rosenstock
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
This patch makes uverbs functions check the length of the
output buffer.
This will prevent uverbs from writing past userspace provided
buffer.
Additionally, it will prevent an underflow while computing
remaining output space. Such underflow would set outlen field in
struct ib_udata in call to INIT_UDATA() to a meaningless value.
For example:
INIT_UDATA(&udata, buf + sizeof cmd,
(unsigned long) cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
If out_len is less than sizeof(resp), the result of subtraction
is a negative value since out_len is an int per function prototype.
But outlen field in struct ib_udata is unsigned, so the result is
an overly large value in struct ib_udata. Such value will make
further size checking useless, allowing more out of bound write
in providers (eg. hw/) code.
Note that checking the output size and preventing the underflow
and/or overflow might break existing userspace program that
incorrectly set the buffer length in a uverbs request.
It's theoretically possible for a userspace driver to send
a request with a wrong size that can still be processed
correctly with the kernel:
Let's build a request through fake 'libibverbs' and
'libvendor-rdma' userspace driver.
It's a request which might be valid with current kernel
but will set outlen to (size_t) -1 while it will be possible
for vendor driver (eg. provider, under hw/) to write vendor
fields:
#include <infiniband/kern-abi.h>
/* aka. struct ib_uverbs_cmd_hdr */
struct ibv_cmd_hdr {
__u32 command;
__u16 in_words;
__u16 out_words;
};
struct vendor_resize_cq {
struct ibv_resize_cq ibv_cmd;
/* vendor defined fields */
};
struct vendor_resize_cq_resp resp {
struct ibv_resize_cq_resp ibv_resp;
/* vendor defined fields */
};
struct ibv_cq *vendor_resize_cq_broken_outlen(...)
{
struct vendor_resize_cq cmd;
struct vendor_resize_cq_resp resp;
size_t resp_size;
...
/* slightly less than struct ib_uverbs_resize_cq_resp */
resp_size = sizeof(struct ibv_create_cq_resp);
resp_size--;
...
IBV_INIT_CMD_RESP(&cmd,
sizeof(cmd),
RESIZE_CQ,
&resp,
resp_size);
...
write(context->cmd_fd,
&cmd,
sizeof(cmd));
...
}
This example shows how a request can be created to trigger
un-handled underflow while allowing provider (eg. hw/) to
process the request.
The provided patch will make it impossible to do it on
patched kernels, but might make unknown broken applications
fail.
Link: http://marc.info/?i=cover.1405884453.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org
Link: http://marc.info/?i=1387493822.11925.217.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_cmd.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 353cbd5229bb..9b971514db88 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -1350,6 +1350,9 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
if (in_len < sizeof cmd)
return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1418,6 +1421,9 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
if (in_len < sizeof cmd)
return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1497,6 +1503,9 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
if (in_len < sizeof cmd)
return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1846,6 +1855,9 @@ ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
if (in_len < sizeof cmd)
return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2061,6 +2073,9 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
if (in_len < sizeof cmd)
return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2124,6 +2139,9 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
if (in_len < sizeof cmd)
return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2368,6 +2386,9 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
if (in_len < sizeof cmd)
return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2420,6 +2441,9 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
if (in_len < sizeof cmd)
return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -3217,6 +3241,9 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
if (in_len < sizeof cmd)
return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
--
1.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 4/4] IB/uverbs: subtract command header from input size
[not found] ` <cover.1405884453.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
` (2 preceding siblings ...)
2014-07-20 19:51 ` [PATCH 3/4] IB/uverbs: check userspace output buffer size in ib_uverbs_poll_cq() Yann Droneaud
@ 2014-07-20 19:51 ` Yann Droneaud
3 siblings, 0 replies; 5+ messages in thread
From: Yann Droneaud @ 2014-07-20 19:51 UTC (permalink / raw)
To: Roland Dreier, Sean Hefty, Hal Rosenstock
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud, Eli Cohen,
Or Gerlitz, Sagi Grimberg
The uverbs handler functions are given a pointer
to the command buffer, which point right after the
command header.
But the size given to the function is the total size,
including the command header size.
The size of the command header must be subtracted
from the input length before calling the uverbs handler
function so that the parameters are in par.
This patch makes ib_uverbs_write() subtract the header
size from the total size when calling uverbs function.
As the return value from the uverbs function will
be the size without the header (or a negative value),
it must not be used as-is. Instead the function use
the total size as return value when no error occurred.
Additionally, drivers (mthca, mlx5) taking the size
of command header in account in their size checks are
modified accordingly.
Note: once the input size is correct, input size check
in uverbs functions might become effective.
Cc: Eli Cohen <eli-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Cc: Or Gerlitz <ogerlitz-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Cc: Sagi Grimberg <sagig-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Link: http://marc.info/?i=cover.1405884453.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_main.c | 18 +++++++++++++-----
drivers/infiniband/hw/mlx5/cq.c | 6 ++----
drivers/infiniband/hw/mlx5/main.c | 2 +-
drivers/infiniband/hw/mlx5/srq.c | 6 ++----
drivers/infiniband/hw/mthca/mthca_provider.c | 2 +-
5 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 08219fb3338b..577f236d47e9 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -592,6 +592,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
{
struct ib_uverbs_file *file = filp->private_data;
struct ib_uverbs_cmd_hdr hdr;
+ const size_t written_count = count;
__u32 flags;
if (count < sizeof hdr)
@@ -605,6 +606,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
if (!flags) {
__u32 command;
+ ssize_t err;
if (hdr.command & ~(__u32)(IB_USER_VERBS_CMD_FLAGS_MASK |
IB_USER_VERBS_CMD_COMMAND_MASK))
@@ -626,10 +628,17 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
if (hdr.in_words * 4 != count)
return -EINVAL;
- return uverbs_cmd_table[command](file,
- buf + sizeof(hdr),
- hdr.in_words * 4,
- hdr.out_words * 4);
+ count -= sizeof(hdr);
+ buf += sizeof(hdr);
+
+ err = uverbs_cmd_table[command](file,
+ buf,
+ count,
+ hdr.out_words * 4);
+ if (err < 0)
+ return err;
+
+ return written_count;
} else if (flags == IB_USER_VERBS_CMD_FLAG_EXTENDED) {
__u32 command;
@@ -638,7 +647,6 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
struct ib_udata ucore;
struct ib_udata uhw;
int err;
- size_t written_count = count;
if (hdr.command & ~(__u32)(IB_USER_VERBS_CMD_FLAGS_MASK |
IB_USER_VERBS_CMD_COMMAND_MASK))
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index 8ae4f896cb41..898877a4f04d 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -609,10 +609,8 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata,
int ncont;
int err;
- ucmdlen =
- (udata->inlen - sizeof(struct ib_uverbs_cmd_hdr) <
- sizeof(ucmd)) ? (sizeof(ucmd) -
- sizeof(ucmd.reserved)) : sizeof(ucmd);
+ ucmdlen = (udata->inlen < sizeof(ucmd)) ?
+ (sizeof(ucmd) - sizeof(ucmd.reserved)) : sizeof(ucmd);
if (ib_copy_from_udata(&ucmd, udata, ucmdlen))
return -EFAULT;
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 364d4b6937f5..59b6ee53df96 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -563,7 +563,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
return ERR_PTR(-EAGAIN);
memset(&req, 0, sizeof(req));
- reqlen = udata->inlen - sizeof(struct ib_uverbs_cmd_hdr);
+ reqlen = udata->inlen;
if (reqlen == sizeof(struct mlx5_ib_alloc_ucontext_req))
ver = 0;
else if (reqlen == sizeof(struct mlx5_ib_alloc_ucontext_req_v2))
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c
index 384af6dec5eb..37ab42d1d30b 100644
--- a/drivers/infiniband/hw/mlx5/srq.c
+++ b/drivers/infiniband/hw/mlx5/srq.c
@@ -86,10 +86,8 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
int ncont;
u32 offset;
- ucmdlen =
- (udata->inlen - sizeof(struct ib_uverbs_cmd_hdr) <
- sizeof(ucmd)) ? (sizeof(ucmd) -
- sizeof(ucmd.reserved)) : sizeof(ucmd);
+ ucmdlen = (udata->inlen < sizeof(ucmd)) ?
+ (sizeof(ucmd) - sizeof(ucmd.reserved)) : sizeof(ucmd);
if (ib_copy_from_udata(&ucmd, udata, ucmdlen)) {
mlx5_ib_dbg(dev, "failed copy udata\n");
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 415f8e1a54db..e5933b032fc3 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -986,7 +986,7 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
int err = 0;
int write_mtt_size;
- if (udata->inlen - sizeof (struct ib_uverbs_cmd_hdr) < sizeof ucmd) {
+ if (udata->inlen < sizeof ucmd) {
if (!to_mucontext(pd->uobject->context)->reg_mr_warned) {
mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n",
current->comm);
--
1.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 5+ messages in thread