* [PATCHv3 for-3.13 0/9] create_flow/destroy_flow fixes for v3.13
@ 2013-12-11 22:01 Yann Droneaud
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
Hi Roland,
Please find the third revision of a patchset against create_flow/destroy_flow
and associated extended command scheme.
These are fixes that *must* be applied before making the new uverbs
widely available in v3.13:
- patches 1 and 2 address a warning reported by sparse.
- patch 3 handle an uncommon type of extended command.
- patch 4, 5 and 6 ensure that commands will be extensible:
- one patch add a missing check of comp_mask;
- the other patches add checks on reserved fields.
- patch 7 fix an error path which was not setting the error code.
- patch 8 ensure the response buffer of an extended command
is a valid memory region for userspace. Doing the check earlier,
on the *full* response buffer, might be safer.
- patch 9 prevent out of bound access and underflow.
Please review and apply for v3.13.
Changes from patchset v2 [1]:
- add a patch to check the input length in extended uverbs,
create_flow and destroy_flow.
Changes from patchset v1 [2]:
- add patch to verify early response buffer using access_ok(),
just like vfs_read().
Regards.
[1] [PATCH v2 for v3.13 0/8] create_flow/destroy_flow fixes for v3.13
http://marc.info/?i=cover.1385981934.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org
[2] [PATCH for v3.13 0/7] create_flow/destroy_flow fixes for v3.13
http://marc.info/?i=cover.1385501822.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org
Yann Droneaud (9):
IB/core: const'ify inbuf in struct ib_udata
IB/uverbs: remove implicit cast in INIT_UDATA()
IB/uverbs: set outbuf to NULL when no core response space is provided
IB/uverbs: check reserved field in extended command header
IB/uverbs: check comp_mask in destroy_flow
IB/uverbs: check reserved fields in create_flow
IB/uverbs: set error code when fail to consume all flow_spec items
IB/uverbs: check access to userspace response buffer in extended
command
IB/uverbs: check input length in flow steering uverbs
drivers/infiniband/core/uverbs.h | 12 ++++++------
drivers/infiniband/core/uverbs_cmd.c | 37 +++++++++++++++++++++++++----------
drivers/infiniband/core/uverbs_main.c | 21 +++++++++++++++-----
include/rdma/ib_verbs.h | 2 +-
4 files changed, 50 insertions(+), 22 deletions(-)
--
1.8.4.2
--
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 [flat|nested] 12+ messages in thread
* [PATCHv3 for-3.13 1/9] IB/core: const'ify inbuf in struct ib_udata
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
@ 2013-12-11 22:01 ` Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 2/9] IB/uverbs: remove implicit cast in INIT_UDATA() Yann Droneaud
` (7 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
Userspace input buffer is not modified by kernel,
let it be 'const'.
It's also a prerequisite to remove the implicit cast
from INIT_UDATA().
Link: http://marc.info/?i=cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs.h | 2 +-
include/rdma/ib_verbs.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index bdc842e9faef..9879568aed8c 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -49,7 +49,7 @@
#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
do { \
- (udata)->inbuf = (void __user *) (ibuf); \
+ (udata)->inbuf = (const void __user *) (ibuf); \
(udata)->outbuf = (void __user *) (obuf); \
(udata)->inlen = (ilen); \
(udata)->outlen = (olen); \
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 979874c627ee..61e1935c91b1 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -978,7 +978,7 @@ struct ib_uobject {
};
struct ib_udata {
- void __user *inbuf;
+ const void __user *inbuf;
void __user *outbuf;
size_t inlen;
size_t outlen;
--
1.8.4.2
--
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] 12+ messages in thread
* [PATCHv3 for-3.13 2/9] IB/uverbs: remove implicit cast in INIT_UDATA()
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
2013-12-11 22:01 ` [PATCHv3 for-3.13 1/9] IB/core: const'ify inbuf in struct ib_udata Yann Droneaud
@ 2013-12-11 22:01 ` Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 3/9] IB/uverbs: set outbuf to NULL when no core response space is provided Yann Droneaud
` (6 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
Currently, INIT_UDATA() does an implicit cast to a pointer,
so that 'response' address, eg. output buffer, can be used
as is to initialize a struct ib_udata:
do { \
(udata)->inbuf = (void __user *) (ibuf); \
(udata)->outbuf = (void __user *) (obuf); \
(udata)->inlen = (ilen); \
(udata)->outlen = (olen); \
} while (0)
...
INIT_UDATA(&udata, buf + sizeof cmd,
(unsigned long) cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
...
Hidding the integer to pointer conversion is prone to error
that won't be catched by compiler/static analyzer is some case.
In the other hand, sparse reports an error if literal 0 is used
to initialize inbuf or outbuf, for example in:
INIT_UDATA(&ucore,
(hdr.in_words) ? buf : 0,
(unsigned long)ex_hdr.response,
hdr.in_words * 8,
hdr.out_words * 8);
It was reported by kbuild test robot in message[1]:
From: kbuild test robot <fengguang.wu-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Subject: "drivers/infiniband/core/uverbs_main.c:683:17:
sparse: Using plain integer as NULL pointer",
Message-Id: <528b3984.SVGs20ZWpcuR/Jls%fengguang.wu-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
This patch fixes the warnings reported by sparse and allows the compiler
to report a warning in case a plain integer get used to initialize
a udata pointer.
This patch requires struct ib_udata to be modified to have a
const void __user *inbuf field[2], otherwise compiler will report warnings
regarding const to non const conversion:
drivers/infiniband/core/uverbs_main.c: In function ‘ib_uverbs_write’:
drivers/infiniband/core/uverbs_main.c:682:24: attention : assignment discards ‘const’ qualifier from pointer target type [enabled by default]
drivers/infiniband/core/uverbs_main.c:688:22: attention : assignment discards ‘const’ qualifier from pointer target type [enabled by default]
drivers/infiniband/core/uverbs_cmd.c: In function ‘ib_uverbs_get_context’:
drivers/infiniband/core/uverbs_cmd.c:307:23: attention : assignment discards ‘const’ qualifier from pointer target type [enabled by default]
drivers/infiniband/core/uverbs_cmd.c: In function ‘ib_uverbs_alloc_pd’:
drivers/infiniband/core/uverbs_cmd.c:516:23: attention : assignment discards ‘const’ qualifier from pointer target type [enabled by default]
...
[1] https://lists.01.org/pipermail/kbuild-all/2013-November/002120.html
[2] https://patchwork.kernel.org/patch/2846202/
http://marc.info/?i=3050a98379b4342ea59d59aeaf1ce162171df928.1376847403.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org
Link: http://marc.info/?i=cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs.h | 12 ++++++------
drivers/infiniband/core/uverbs_cmd.c | 20 ++++++++++----------
drivers/infiniband/core/uverbs_main.c | 13 ++++++++-----
3 files changed, 24 insertions(+), 21 deletions(-)
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 9879568aed8c..0dca1975d59d 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -47,12 +47,12 @@
#include <rdma/ib_umem.h>
#include <rdma/ib_user_verbs.h>
-#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
- do { \
- (udata)->inbuf = (const void __user *) (ibuf); \
- (udata)->outbuf = (void __user *) (obuf); \
- (udata)->inlen = (ilen); \
- (udata)->outlen = (olen); \
+#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
+ do { \
+ (udata)->inbuf = (ibuf); \
+ (udata)->outbuf = (obuf); \
+ (udata)->inlen = (ilen); \
+ (udata)->outlen = (olen); \
} while (0)
/*
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 65f6e7dc380c..d9d91c412628 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -305,7 +305,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
}
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
ucontext = ibdev->alloc_ucontext(ibdev, &udata);
@@ -514,7 +514,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
return -EFAULT;
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
@@ -711,7 +711,7 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
return -EFAULT;
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
mutex_lock(&file->device->xrcd_tree_mutex);
@@ -923,7 +923,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
return -EFAULT;
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
@@ -1215,7 +1215,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
return -EFAULT;
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
if (cmd.comp_vector >= file->device->num_comp_vectors)
@@ -1311,7 +1311,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
return -EFAULT;
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
@@ -1513,7 +1513,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
return -EPERM;
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
obj = kzalloc(sizeof *obj, GFP_KERNEL);
@@ -1700,7 +1700,7 @@ ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
return -EFAULT;
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
obj = kmalloc(sizeof *obj, GFP_KERNEL);
@@ -2976,7 +2976,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
xcmd.srq_limit = cmd.srq_limit;
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
ret = __uverbs_create_xsrq(file, &xcmd, &udata);
@@ -3001,7 +3001,7 @@ ssize_t ib_uverbs_create_xsrq(struct ib_uverbs_file *file,
return -EFAULT;
INIT_UDATA(&udata, buf + sizeof cmd,
- (unsigned long) cmd.response + sizeof resp,
+ (void __user *)(unsigned long)cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
ret = __uverbs_create_xsrq(file, &cmd, &udata);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 34386943ebcf..14d864371050 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -635,6 +635,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
__u32 command;
struct ib_uverbs_ex_cmd_hdr ex_hdr;
+ char __user *response;
struct ib_udata ucore;
struct ib_udata uhw;
int err;
@@ -668,7 +669,9 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
if ((hdr.in_words + ex_hdr.provider_in_words) * 8 != count)
return -EINVAL;
- if (ex_hdr.response) {
+ response = (char __user *)(unsigned long)ex_hdr.response;
+
+ if (response) {
if (!hdr.out_words && !ex_hdr.provider_out_words)
return -EINVAL;
} else {
@@ -677,14 +680,14 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
}
INIT_UDATA(&ucore,
- (hdr.in_words) ? buf : 0,
- (unsigned long)ex_hdr.response,
+ (hdr.in_words) ? buf : NULL,
+ response,
hdr.in_words * 8,
hdr.out_words * 8);
INIT_UDATA(&uhw,
- (ex_hdr.provider_in_words) ? buf + ucore.inlen : 0,
- (ex_hdr.provider_out_words) ? (unsigned long)ex_hdr.response + ucore.outlen : 0,
+ (ex_hdr.provider_in_words) ? buf + ucore.inlen : NULL,
+ (ex_hdr.provider_out_words) ? response + ucore.outlen : NULL,
ex_hdr.provider_in_words * 8,
ex_hdr.provider_out_words * 8);
--
1.8.4.2
--
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] 12+ messages in thread
* [PATCHv3 for-3.13 3/9] IB/uverbs: set outbuf to NULL when no core response space is provided
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
2013-12-11 22:01 ` [PATCHv3 for-3.13 1/9] IB/core: const'ify inbuf in struct ib_udata Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 2/9] IB/uverbs: remove implicit cast in INIT_UDATA() Yann Droneaud
@ 2013-12-11 22:01 ` Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 4/9] IB/uverbs: check reserved field in extended command header Yann Droneaud
` (5 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
In the currently uncommon case of core (eg. uverbs) response
space being omitted, but hw (eg. provider) response space being
available, outbuf get defined to "response" while it must be NULL.
This patch takes care of setting ucore->outbuf to NULL
if hdr.out_words is equal to 0.
Link: http://marc.info/?i=cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 14d864371050..6c4fc6338b26 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -681,7 +681,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
INIT_UDATA(&ucore,
(hdr.in_words) ? buf : NULL,
- response,
+ (hdr.out_words) ? response : NULL,
hdr.in_words * 8,
hdr.out_words * 8);
--
1.8.4.2
--
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] 12+ messages in thread
* [PATCHv3 for-3.13 4/9] IB/uverbs: check reserved field in extended command header
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
` (2 preceding siblings ...)
2013-12-11 22:01 ` [PATCHv3 for-3.13 3/9] IB/uverbs: set outbuf to NULL when no core response space is provided Yann Droneaud
@ 2013-12-11 22:01 ` Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 5/9] IB/uverbs: check comp_mask in destroy_flow Yann Droneaud
` (4 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
As noted by Daniel Vetter in its article "Botching up ioctls"[1]
"Check *all* unused fields and flags and all the padding for
whether it's 0, and reject the ioctl if that's not the case.
Otherwise your nice plan for future extensions is going right
down the gutters since someone *will* submit an ioctl struct
with random stack garbage in the yet unused parts. Which then
bakes in the ABI that those fields can never be used for
anything else but garbage."
It's important to ensure that reserved fields are set to known
value, so that it will be possible to use them latter to extend
the ABI.
The same reasonning apply to comp_mask field present in newer
uverbs command: per commit 22878dbc9173, unsupported values in
comp_mask are rejected.
[1] http://blog.ffwll.ch/2013/11/botching-up-ioctls.html
Link: http://marc.info/?i=cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_main.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 6c4fc6338b26..8652c13f6ea2 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -669,6 +669,9 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
if ((hdr.in_words + ex_hdr.provider_in_words) * 8 != count)
return -EINVAL;
+ if (ex_hdr.cmd_hdr_reserved)
+ return -EINVAL;
+
response = (char __user *)(unsigned long)ex_hdr.response;
if (response) {
--
1.8.4.2
--
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] 12+ messages in thread
* [PATCHv3 for-3.13 5/9] IB/uverbs: check comp_mask in destroy_flow
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
` (3 preceding siblings ...)
2013-12-11 22:01 ` [PATCHv3 for-3.13 4/9] IB/uverbs: check reserved field in extended command header Yann Droneaud
@ 2013-12-11 22:01 ` Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 6/9] IB/uverbs: check reserved fields in create_flow Yann Droneaud
` (3 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud, Matan Barak
Just like the check added to create_flow in 22878dbc9173,
comp_mask must be checked in destroy_flow too.
Since only empty comp_mask is currently supported,
any other value must be rejected.
This check was silently added in a previous patch[1] to move
comp_mask in extended command header, part of previous patchset[2]
against create/destroy_flow uverbs. The idea of moving comp_mask
to the header was discarded for the final patchset[3].
Unfortunately the check added in destroy_flow uverb was not
integrated in the final patchset.
[1] http://marc.info/?i=40175eda10d670d098204da6aa4c327a0171ae5f.1381510045.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org
[2] http://marc.info/?i=cover.1381510045.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org
[3] http://marc.info/?i=cover.1383773832.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org
Cc: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Link: http://marc.info/?i=cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_cmd.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index d9d91c412628..f1ba441cd2ed 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -2795,6 +2795,9 @@ int ib_uverbs_ex_destroy_flow(struct ib_uverbs_file *file,
if (ret)
return ret;
+ if (cmd.comp_mask)
+ return -EINVAL;
+
uobj = idr_write_uobj(&ib_uverbs_rule_idr, cmd.flow_handle,
file->ucontext);
if (!uobj)
--
1.8.4.2
--
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] 12+ messages in thread
* [PATCHv3 for-3.13 6/9] IB/uverbs: check reserved fields in create_flow
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
` (4 preceding siblings ...)
2013-12-11 22:01 ` [PATCHv3 for-3.13 5/9] IB/uverbs: check comp_mask in destroy_flow Yann Droneaud
@ 2013-12-11 22:01 ` Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 7/9] IB/uverbs: set error code when fail to consume all flow_spec items Yann Droneaud
` (2 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
As noted by Daniel Vetter in its article "Botching up ioctls"[1]
"Check *all* unused fields and flags and all the padding for
whether it's 0, and reject the ioctl if that's not the case.
Otherwise your nice plan for future extensions is going right
down the gutters since someone *will* submit an ioctl struct
with random stack garbage in the yet unused parts. Which then
bakes in the ABI that those fields can never be used for
anything else but garbage."
It's important to ensure that reserved fields are set to known
value, so that it will be possible to use them latter to extend
the ABI.
The same reasonning apply to comp_mask field present in newer
uverbs command: per commit 22878dbc9173, unsupported values in
comp_mask are rejected.
[1] http://blog.ffwll.ch/2013/11/botching-up-ioctls.html
Link: http://marc.info/?i=cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_cmd.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index f1ba441cd2ed..dd1c5b6ab019 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -2593,6 +2593,9 @@ out_put:
static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec,
union ib_flow_spec *ib_spec)
{
+ if (kern_spec->reserved)
+ return -EINVAL;
+
ib_spec->type = kern_spec->type;
switch (ib_spec->type) {
@@ -2671,6 +2674,10 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
(cmd.flow_attr.num_of_specs * sizeof(struct ib_uverbs_flow_spec)))
return -EINVAL;
+ if (cmd.flow_attr.reserved[0] ||
+ cmd.flow_attr.reserved[1])
+ return -EINVAL;
+
if (cmd.flow_attr.num_of_specs) {
kern_flow_attr = kmalloc(sizeof(*kern_flow_attr) + cmd.flow_attr.size,
GFP_KERNEL);
--
1.8.4.2
--
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] 12+ messages in thread
* [PATCHv3 for-3.13 7/9] IB/uverbs: set error code when fail to consume all flow_spec items
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
` (5 preceding siblings ...)
2013-12-11 22:01 ` [PATCHv3 for-3.13 6/9] IB/uverbs: check reserved fields in create_flow Yann Droneaud
@ 2013-12-11 22:01 ` Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 8/9] IB/uverbs: check access to userspace response buffer in extended command Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 9/9] IB/uverbs: check input length in flow steering uverbs Yann Droneaud
8 siblings, 0 replies; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
If the flow_spec items parsed count does not match the number
of items declared in the flow_attr command, or if not all
bytes are used for flow_spec items (eg. trailing garbage),
a log message is reported and the function leave through
the error path. Unfortunately the error code is currently
not set.
This patch set error code to -EINVAL in such cases, so
that the error is reported to userspace instead of silently
fail.
Link: http://marc.info/?i=cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_cmd.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index dd1c5b6ab019..5976d885f408 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -2738,6 +2738,7 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
if (cmd.flow_attr.size || (i != flow_attr->num_of_specs)) {
pr_warn("create flow failed, flow %d: %d bytes left from uverb cmd\n",
i, cmd.flow_attr.size);
+ err = -EINVAL;
goto err_free;
}
flow_id = ib_create_flow(qp, flow_attr, IB_FLOW_DOMAIN_USER);
--
1.8.4.2
--
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] 12+ messages in thread
* [PATCHv3 for-3.13 8/9] IB/uverbs: check access to userspace response buffer in extended command
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
` (6 preceding siblings ...)
2013-12-11 22:01 ` [PATCHv3 for-3.13 7/9] IB/uverbs: set error code when fail to consume all flow_spec items Yann Droneaud
@ 2013-12-11 22:01 ` Yann Droneaud
[not found] ` <701fc3ee1136bbb4a0fd3d560c3ec1ee3bb3b828.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
2013-12-11 22:01 ` [PATCHv3 for-3.13 9/9] IB/uverbs: check input length in flow steering uverbs Yann Droneaud
8 siblings, 1 reply; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
Just like vfs_read(), uverbs_write() must check output buffer
(eg. response) with access_ok(VERIFY_WRITE,...) to ensure
it's in userspace memory before using the pointer in uverbs
functions.
If the buffer or a subset of the buffer is not valid,
returns -EFAULT.
Note: there's no need to check input buffer (eg. command)
since vfs_write() does the check access_ok(VERIFY_READ, ...)
as part of write() syscall.
Link: http://marc.info/?i=cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_main.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 8652c13f6ea2..0be1dd86f768 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -677,6 +677,11 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
if (response) {
if (!hdr.out_words && !ex_hdr.provider_out_words)
return -EINVAL;
+
+ if (!access_ok(VERIFY_WRITE,
+ response,
+ (hdr.out_words + ex_hdr.provider_out_words) * 8))
+ return -EFAULT;
} else {
if (hdr.out_words || ex_hdr.provider_out_words)
return -EINVAL;
--
1.8.4.2
--
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] 12+ messages in thread
* [PATCHv3 for-3.13 9/9] IB/uverbs: check input length in flow steering uverbs
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
` (7 preceding siblings ...)
2013-12-11 22:01 ` [PATCHv3 for-3.13 8/9] IB/uverbs: check access to userspace response buffer in extended command Yann Droneaud
@ 2013-12-11 22:01 ` Yann Droneaud
8 siblings, 0 replies; 12+ messages in thread
From: Yann Droneaud @ 2013-12-11 22:01 UTC (permalink / raw)
To: Roland Dreier, Roland Dreier
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yann Droneaud
Since ib_copy_from_udata() doesn't check yet the available
input data length before accessing userspace memory,
an explicit check of this length is required to prevent:
- reading past the user provided buffer,
- underflow when subtracting the expected command size
from the input length.
This will ensure the newly added flow steering uverbs
don't try to process truncated commands.
Link: http://marc.info/?i=cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
---
drivers/infiniband/core/uverbs_cmd.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 5976d885f408..d39062466a7a 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -2649,6 +2649,9 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
void *ib_spec;
int i;
+ if (ucore->inlen < sizeof(cmd))
+ return -EINVAL;
+
if (ucore->outlen < sizeof(resp))
return -ENOSPC;
@@ -2799,6 +2802,9 @@ int ib_uverbs_ex_destroy_flow(struct ib_uverbs_file *file,
struct ib_uobject *uobj;
int ret;
+ if (ucore->inlen < sizeof(cmd))
+ return -EINVAL;
+
ret = ib_copy_from_udata(&cmd, ucore, sizeof(cmd));
if (ret)
return ret;
--
1.8.4.2
--
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] 12+ messages in thread
* Re: [PATCHv3 for-3.13 8/9] IB/uverbs: check access to userspace response buffer in extended command
[not found] ` <701fc3ee1136bbb4a0fd3d560c3ec1ee3bb3b828.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
@ 2013-12-15 16:21 ` Roland Dreier
[not found] ` <CAL1RGDVThe_=F3EOCzYfxB8zCgv+4Z_PXiYEPqnphMEOi-drbw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 12+ messages in thread
From: Roland Dreier @ 2013-12-15 16:21 UTC (permalink / raw)
To: Yann Droneaud; +Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
On Wed, Dec 11, 2013 at 2:01 PM, Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org> wrote:
> Just like vfs_read(), uverbs_write() must check output buffer
> (eg. response) with access_ok(VERIFY_WRITE,...) to ensure
> it's in userspace memory before using the pointer in uverbs
> functions.
Is there any place where we use this pointer through something other
than copy_to_user()? I don't think there is or ever should be, in
which case this check is redundant.
- R.
--
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 [flat|nested] 12+ messages in thread
* Re: [PATCHv3 for-3.13 8/9] IB/uverbs: check access to userspace response buffer in extended command
[not found] ` <CAL1RGDVThe_=F3EOCzYfxB8zCgv+4Z_PXiYEPqnphMEOi-drbw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2013-12-15 17:44 ` Ydroneaud
0 siblings, 0 replies; 12+ messages in thread
From: Ydroneaud @ 2013-12-15 17:44 UTC (permalink / raw)
To: roland-BHEL68pLQRGGvPXPguhicg, ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA
Hi Roland,
> On Wed, Dec 11, 2013 at 2:01 PM, Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org> wrote:
>> Just like vfs_read(), uverbs_write() must check output buffer
>> (eg. response) with access_ok(VERIFY_WRITE,...) to ensure
>> it's in userspace memory before using the pointer in uverbs
>> functions.
> Is there any place where we use this pointer through something other
> than copy_to_user()? I don't think there is or ever should be, in
> which case this check is redundant.
Since this check is applied on the 'extended' uverbs, there's only a limited amount
of existing code to check.
Anyway the purpose of this check is to ensure that *whole* buffer passed as response
buffer is valid, and the whole buffer may be larger than the response to be returned.
Just like the check in read(2) syscall, it's a sanity check to refuse to process
malformed syscall:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/read_write.c#n389
This particular check was added by Linus in 2005, the commit message might be interesting:
https://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/?id=fd770e66c9a65b14ce114e171266cf6f393df502
Make read/write always do the full "access_ok()" tests.
The actual user copy will do them too, but only for the
range that ends up being actually copied. That hides
bugs when the range has been clamped by file size or other
issues.
So I don't see this check as redundant with call to copy_to_user(),
it's checking a different thing.
Regards.
--
Yann Droneaud
OPTEYA
--
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 [flat|nested] 12+ messages in thread
end of thread, other threads:[~2013-12-15 17:44 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-11 22:01 [PATCHv3 for-3.13 0/9] create_flow/destroy_flow fixes for v3.13 Yann Droneaud
[not found] ` <cover.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
2013-12-11 22:01 ` [PATCHv3 for-3.13 1/9] IB/core: const'ify inbuf in struct ib_udata Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 2/9] IB/uverbs: remove implicit cast in INIT_UDATA() Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 3/9] IB/uverbs: set outbuf to NULL when no core response space is provided Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 4/9] IB/uverbs: check reserved field in extended command header Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 5/9] IB/uverbs: check comp_mask in destroy_flow Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 6/9] IB/uverbs: check reserved fields in create_flow Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 7/9] IB/uverbs: set error code when fail to consume all flow_spec items Yann Droneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 8/9] IB/uverbs: check access to userspace response buffer in extended command Yann Droneaud
[not found] ` <701fc3ee1136bbb4a0fd3d560c3ec1ee3bb3b828.1386798254.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
2013-12-15 16:21 ` Roland Dreier
[not found] ` <CAL1RGDVThe_=F3EOCzYfxB8zCgv+4Z_PXiYEPqnphMEOi-drbw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-12-15 17:44 ` Ydroneaud
2013-12-11 22:01 ` [PATCHv3 for-3.13 9/9] IB/uverbs: check input length in flow steering uverbs Yann Droneaud
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox