]> Pileus Git - ~andy/linux/commitdiff
Merge tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 24 Dec 2013 01:23:42 +0000 (17:23 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 24 Dec 2013 01:23:42 +0000 (17:23 -0800)
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

drivers/infiniband/core/iwcm.c
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/cxgb4/mem.c
include/rdma/ib_verbs.h

index c47c2034ca71f9a95f3153fbc31756fc34b1fde0..0717940ec3b5080083cb53e8d8526bdf692c829a 100644 (file)
@@ -181,9 +181,16 @@ static void add_ref(struct iw_cm_id *cm_id)
 static void rem_ref(struct iw_cm_id *cm_id)
 {
        struct iwcm_id_private *cm_id_priv;
+       int cb_destroy;
+
        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));
                free_cm_id(cm_id_priv);
        }
index bdc842e9faefe4ba477b96c479975643bfdc6366..a283274a5a09fa17b0dede8f5819ef9dfaf4458b 100644 (file)
 
 #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);                               \
        } 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:
  *
index 65f6e7dc380c382cc0335e495fb2f583a4eef7b7..f1cc83855af65dd334a21d7c82a94f252413e42a 100644 (file)
@@ -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) {
@@ -2646,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;
 
@@ -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)))
                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);
@@ -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)) {
                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);
@@ -2791,10 +2802,16 @@ 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;
 
+       if (cmd.comp_mask)
+               return -EINVAL;
+
        uobj = idr_write_uobj(&ib_uverbs_rule_idr, cmd.flow_handle,
                              file->ucontext);
        if (!uobj)
index 34386943ebcff4cf18849082add568f5fc73bc5a..08219fb3338b0652f350da1af864b4cfb355ff3c 100644 (file)
@@ -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)
                        return -EINVAL;
 
+               if (ex_hdr.cmd_hdr_reserved)
+                       return -EINVAL;
+
                if (ex_hdr.response) {
                        if (!hdr.out_words && !ex_hdr.provider_out_words)
                                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 {
                        if (hdr.out_words || ex_hdr.provider_out_words)
                                return -EINVAL;
                }
 
-               INIT_UDATA(&ucore,
-                          (hdr.in_words) ? buf : 0,
-                          (unsigned long)ex_hdr.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 * 8,
-                          ex_hdr.provider_out_words * 8);
+               INIT_UDATA_BUF_OR_NULL(&ucore, buf, (unsigned long) ex_hdr.response,
+                                      hdr.in_words * 8, hdr.out_words * 8);
+
+               INIT_UDATA_BUF_OR_NULL(&uhw,
+                                      buf + ucore.inlen,
+                                      (unsigned long) ex_hdr.response + ucore.outlen,
+                                      ex_hdr.provider_in_words * 8,
+                                      ex_hdr.provider_out_words * 8);
 
                err = uverbs_ex_cmd_table[command](file,
                                                   &ucore,
index 4cb8eb24497cfa61821b4863c4026ff5a061405a..84e45006451cd3983cd1b28bfb22d2c0a9c02ef7 100644 (file)
@@ -173,7 +173,7 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
        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 dmalen;
index 979874c627ee7f450c7aabff5c948cb2c87f84c3..61e1935c91b121d0ba6a9e5d6f05221d15060432 100644 (file)
@@ -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;