Last batch of InfiniBand/RDMA changes for 3.13 / 2014:
- Additional checks for uverbs to ensure forward compatibility, handle malformed input better. - Fix potential use-after-free in iWARP connection manager. - Make a function static. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABCAAGBQJSuHFcAAoJEENa44ZhAt0hetAP/2lMjThZ/dK/Q4eyGXr86qQ6 ygjFc26H7SPEqZ2cjmcm0mgObHhVj4+94YiJDcemHpjwfzLhhZywZxjySTTJdKna ZSzmSb8si0KNdPAoEdldPmtmO04oTI0+mz7kK2sz9mbn033xDVcJ24M8jSUy6/dl KBmYWCaiE6rabSyvRNwXOIFilj5RwomQFZzJMjg9JGvWY5qpmwKbcvVdZMCSzAwS VsZ2Z5UEDaghsGtnYjKQzvR1TDGeq6XyWtR4rfjCH19U6rUcInbA1oZFDWcOqE3C r/o9jOCUszAVefG3iPX5PJ+A3kKCHB2lcDK9owfoIM/cLfV8KWBFkp0WouD5wiGr 8sfENcKI7aMq+Rptsa24FDNkJVCcdG1HhribRqWY/mn4CwI4c3Qe+5s4x+kgHnxU VngX/Hp54lw+pnrgWWrKCT5tFVuDgdVhHqyYLabtnKrCHIPsb2Eqp8Kaz2JPNLkI OYWOcS17wzg7nAPoiqbMVfWInGmziqOpWqVZkFwZ+EBTfJIjE7td+Mxn46PzKsrO gbVYifn+q5cToDGwmK4pn14G1Xh45tqYW/P3KfZNwyGB6+Ui7u18Q5/epp8BHIWy 8bn3jTcJzBIMlOmFxqirrJ2OixaeAWJhZjgAMJIA3So9MHwmhbkJfgo0J+S6jLnI p1WRy0kTmPC5NNX21YN8 =bol6 -----END PGP SIGNATURE----- Merge tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband Pull infiniband fixes from Roland Dreier: "Last batch of InfiniBand/RDMA changes for 3.13 / 2014: - Additional checks for uverbs to ensure forward compatibility, handle malformed input better. - Fix potential use-after-free in iWARP connection manager. - Make a function static" * tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband: IB/uverbs: Check access to userspace response buffer in extended command IB/uverbs: Check input length in flow steering uverbs IB/uverbs: Set error code when fail to consume all flow_spec items IB/uverbs: Check reserved fields in create_flow IB/uverbs: Check comp_mask in destroy_flow IB/uverbs: Check reserved field in extended command header IB/uverbs: New macro to set pointers to NULL if length is 0 in INIT_UDATA() IB/core: const'ify inbuf in struct ib_udata RDMA/iwcm: Don't touch cm_id after deref in rem_ref RDMA/cxgb4: Make _c4iw_write_mem_dma() static
This commit is contained in:
Коммит
6961bc6c70
|
@ -181,9 +181,16 @@ static void add_ref(struct iw_cm_id *cm_id)
|
||||||
static void rem_ref(struct iw_cm_id *cm_id)
|
static void rem_ref(struct iw_cm_id *cm_id)
|
||||||
{
|
{
|
||||||
struct iwcm_id_private *cm_id_priv;
|
struct iwcm_id_private *cm_id_priv;
|
||||||
|
int cb_destroy;
|
||||||
|
|
||||||
cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
|
cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
|
||||||
if (iwcm_deref_id(cm_id_priv) &&
|
|
||||||
test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) {
|
/*
|
||||||
|
* Test bit before deref in case the cm_id gets freed on another
|
||||||
|
* thread.
|
||||||
|
*/
|
||||||
|
cb_destroy = test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
|
||||||
|
if (iwcm_deref_id(cm_id_priv) && cb_destroy) {
|
||||||
BUG_ON(!list_empty(&cm_id_priv->work_list));
|
BUG_ON(!list_empty(&cm_id_priv->work_list));
|
||||||
free_cm_id(cm_id_priv);
|
free_cm_id(cm_id_priv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,12 +49,20 @@
|
||||||
|
|
||||||
#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
|
#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
|
||||||
do { \
|
do { \
|
||||||
(udata)->inbuf = (void __user *) (ibuf); \
|
(udata)->inbuf = (const void __user *) (ibuf); \
|
||||||
(udata)->outbuf = (void __user *) (obuf); \
|
(udata)->outbuf = (void __user *) (obuf); \
|
||||||
(udata)->inlen = (ilen); \
|
(udata)->inlen = (ilen); \
|
||||||
(udata)->outlen = (olen); \
|
(udata)->outlen = (olen); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define INIT_UDATA_BUF_OR_NULL(udata, ibuf, obuf, ilen, olen) \
|
||||||
|
do { \
|
||||||
|
(udata)->inbuf = (ilen) ? (const void __user *) (ibuf) : NULL; \
|
||||||
|
(udata)->outbuf = (olen) ? (void __user *) (obuf) : NULL; \
|
||||||
|
(udata)->inlen = (ilen); \
|
||||||
|
(udata)->outlen = (olen); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Our lifetime rules for these structs are the following:
|
* Our lifetime rules for these structs are the following:
|
||||||
*
|
*
|
||||||
|
|
|
@ -2593,6 +2593,9 @@ out_put:
|
||||||
static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec,
|
static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec,
|
||||||
union ib_flow_spec *ib_spec)
|
union ib_flow_spec *ib_spec)
|
||||||
{
|
{
|
||||||
|
if (kern_spec->reserved)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
ib_spec->type = kern_spec->type;
|
ib_spec->type = kern_spec->type;
|
||||||
|
|
||||||
switch (ib_spec->type) {
|
switch (ib_spec->type) {
|
||||||
|
@ -2646,6 +2649,9 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
|
||||||
void *ib_spec;
|
void *ib_spec;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (ucore->inlen < sizeof(cmd))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (ucore->outlen < sizeof(resp))
|
if (ucore->outlen < sizeof(resp))
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
|
@ -2671,6 +2677,10 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
|
||||||
(cmd.flow_attr.num_of_specs * sizeof(struct ib_uverbs_flow_spec)))
|
(cmd.flow_attr.num_of_specs * sizeof(struct ib_uverbs_flow_spec)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (cmd.flow_attr.reserved[0] ||
|
||||||
|
cmd.flow_attr.reserved[1])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (cmd.flow_attr.num_of_specs) {
|
if (cmd.flow_attr.num_of_specs) {
|
||||||
kern_flow_attr = kmalloc(sizeof(*kern_flow_attr) + cmd.flow_attr.size,
|
kern_flow_attr = kmalloc(sizeof(*kern_flow_attr) + cmd.flow_attr.size,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
@ -2731,6 +2741,7 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
|
||||||
if (cmd.flow_attr.size || (i != flow_attr->num_of_specs)) {
|
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",
|
pr_warn("create flow failed, flow %d: %d bytes left from uverb cmd\n",
|
||||||
i, cmd.flow_attr.size);
|
i, cmd.flow_attr.size);
|
||||||
|
err = -EINVAL;
|
||||||
goto err_free;
|
goto err_free;
|
||||||
}
|
}
|
||||||
flow_id = ib_create_flow(qp, flow_attr, IB_FLOW_DOMAIN_USER);
|
flow_id = ib_create_flow(qp, flow_attr, IB_FLOW_DOMAIN_USER);
|
||||||
|
@ -2791,10 +2802,16 @@ int ib_uverbs_ex_destroy_flow(struct ib_uverbs_file *file,
|
||||||
struct ib_uobject *uobj;
|
struct ib_uobject *uobj;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (ucore->inlen < sizeof(cmd))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
ret = ib_copy_from_udata(&cmd, ucore, sizeof(cmd));
|
ret = ib_copy_from_udata(&cmd, ucore, sizeof(cmd));
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (cmd.comp_mask)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
uobj = idr_write_uobj(&ib_uverbs_rule_idr, cmd.flow_handle,
|
uobj = idr_write_uobj(&ib_uverbs_rule_idr, cmd.flow_handle,
|
||||||
file->ucontext);
|
file->ucontext);
|
||||||
if (!uobj)
|
if (!uobj)
|
||||||
|
|
|
@ -668,25 +668,30 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
|
||||||
if ((hdr.in_words + ex_hdr.provider_in_words) * 8 != count)
|
if ((hdr.in_words + ex_hdr.provider_in_words) * 8 != count)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (ex_hdr.cmd_hdr_reserved)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (ex_hdr.response) {
|
if (ex_hdr.response) {
|
||||||
if (!hdr.out_words && !ex_hdr.provider_out_words)
|
if (!hdr.out_words && !ex_hdr.provider_out_words)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_WRITE,
|
||||||
|
(void __user *) (unsigned long) ex_hdr.response,
|
||||||
|
(hdr.out_words + ex_hdr.provider_out_words) * 8))
|
||||||
|
return -EFAULT;
|
||||||
} else {
|
} else {
|
||||||
if (hdr.out_words || ex_hdr.provider_out_words)
|
if (hdr.out_words || ex_hdr.provider_out_words)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_UDATA(&ucore,
|
INIT_UDATA_BUF_OR_NULL(&ucore, buf, (unsigned long) ex_hdr.response,
|
||||||
(hdr.in_words) ? buf : 0,
|
hdr.in_words * 8, hdr.out_words * 8);
|
||||||
(unsigned long)ex_hdr.response,
|
|
||||||
hdr.in_words * 8,
|
|
||||||
hdr.out_words * 8);
|
|
||||||
|
|
||||||
INIT_UDATA(&uhw,
|
INIT_UDATA_BUF_OR_NULL(&uhw,
|
||||||
(ex_hdr.provider_in_words) ? buf + ucore.inlen : 0,
|
buf + ucore.inlen,
|
||||||
(ex_hdr.provider_out_words) ? (unsigned long)ex_hdr.response + ucore.outlen : 0,
|
(unsigned long) ex_hdr.response + ucore.outlen,
|
||||||
ex_hdr.provider_in_words * 8,
|
ex_hdr.provider_in_words * 8,
|
||||||
ex_hdr.provider_out_words * 8);
|
ex_hdr.provider_out_words * 8);
|
||||||
|
|
||||||
err = uverbs_ex_cmd_table[command](file,
|
err = uverbs_ex_cmd_table[command](file,
|
||||||
&ucore,
|
&ucore,
|
||||||
|
|
|
@ -173,7 +173,7 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len, void *data)
|
static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len, void *data)
|
||||||
{
|
{
|
||||||
u32 remain = len;
|
u32 remain = len;
|
||||||
u32 dmalen;
|
u32 dmalen;
|
||||||
|
|
|
@ -978,7 +978,7 @@ struct ib_uobject {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ib_udata {
|
struct ib_udata {
|
||||||
void __user *inbuf;
|
const void __user *inbuf;
|
||||||
void __user *outbuf;
|
void __user *outbuf;
|
||||||
size_t inlen;
|
size_t inlen;
|
||||||
size_t outlen;
|
size_t outlen;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче