Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6961bc6c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents f5835372 22f12c60
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -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);
	}
+9 −1
Original line number Diff line number Diff line
@@ -49,12 +49,20 @@

#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:
 *
+17 −0
Original line number Diff line number Diff line
@@ -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)
+16 −11
Original line number Diff line number Diff line
@@ -668,23 +668,28 @@ 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_BUF_OR_NULL(&ucore, buf, (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,
		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);

+1 −1
Original line number Diff line number Diff line
@@ -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;
Loading