Commit ca745723 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull rdma fixes from Jason Gunthorpe:

 - Older "does not even boot" regression in qib from July

 - Bug fixes for error unwind in rtrs

 - Avoid a deadlock syzkaller found in srp

 - Fix another UAF syzkaller found in cma

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma:
  RDMA/cma: Do not change route.addr.src_addr outside state checks
  RDMA/ib_srp: Fix a deadlock
  RDMA/rtrs-clt: Move free_permit from free_clt to rtrs_clt_close
  RDMA/rtrs-clt: Fix possible double free in error case
  IB/qib: Fix duplicate sysfs directory name
parents 115ccd22 22e9f710
Loading
Loading
Loading
Loading
+24 −16
Original line number Diff line number Diff line
@@ -3370,22 +3370,30 @@ static int cma_resolve_ib_addr(struct rdma_id_private *id_priv)
static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
			 const struct sockaddr *dst_addr)
{
	if (!src_addr || !src_addr->sa_family) {
		src_addr = (struct sockaddr *) &id->route.addr.src_addr;
		src_addr->sa_family = dst_addr->sa_family;
		if (IS_ENABLED(CONFIG_IPV6) &&
		    dst_addr->sa_family == AF_INET6) {
			struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr;
			struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr;
	struct sockaddr_storage zero_sock = {};

	if (src_addr && src_addr->sa_family)
		return rdma_bind_addr(id, src_addr);

	/*
	 * When the src_addr is not specified, automatically supply an any addr
	 */
	zero_sock.ss_family = dst_addr->sa_family;
	if (IS_ENABLED(CONFIG_IPV6) && dst_addr->sa_family == AF_INET6) {
		struct sockaddr_in6 *src_addr6 =
			(struct sockaddr_in6 *)&zero_sock;
		struct sockaddr_in6 *dst_addr6 =
			(struct sockaddr_in6 *)dst_addr;

		src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id;
		if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
				id->route.addr.dev_addr.bound_dev_if = dst_addr6->sin6_scope_id;
			id->route.addr.dev_addr.bound_dev_if =
				dst_addr6->sin6_scope_id;
	} else if (dst_addr->sa_family == AF_IB) {
			((struct sockaddr_ib *) src_addr)->sib_pkey =
		((struct sockaddr_ib *)&zero_sock)->sib_pkey =
			((struct sockaddr_ib *)dst_addr)->sib_pkey;
	}
	}
	return rdma_bind_addr(id, src_addr);
	return rdma_bind_addr(id, (struct sockaddr *)&zero_sock);
}

/*
+1 −1
Original line number Diff line number Diff line
@@ -541,7 +541,7 @@ static struct attribute *port_diagc_attributes[] = {
};

static const struct attribute_group port_diagc_group = {
	.name = "linkcontrol",
	.name = "diag_counters",
	.attrs = port_diagc_attributes,
};

+21 −18
Original line number Diff line number Diff line
@@ -2682,6 +2682,8 @@ static void rtrs_clt_dev_release(struct device *dev)
	struct rtrs_clt_sess *clt = container_of(dev, struct rtrs_clt_sess,
						 dev);

	mutex_destroy(&clt->paths_ev_mutex);
	mutex_destroy(&clt->paths_mutex);
	kfree(clt);
}

@@ -2711,6 +2713,8 @@ static struct rtrs_clt_sess *alloc_clt(const char *sessname, size_t paths_num,
		return ERR_PTR(-ENOMEM);
	}

	clt->dev.class = rtrs_clt_dev_class;
	clt->dev.release = rtrs_clt_dev_release;
	uuid_gen(&clt->paths_uuid);
	INIT_LIST_HEAD_RCU(&clt->paths_list);
	clt->paths_num = paths_num;
@@ -2727,53 +2731,51 @@ static struct rtrs_clt_sess *alloc_clt(const char *sessname, size_t paths_num,
	init_waitqueue_head(&clt->permits_wait);
	mutex_init(&clt->paths_ev_mutex);
	mutex_init(&clt->paths_mutex);
	device_initialize(&clt->dev);

	clt->dev.class = rtrs_clt_dev_class;
	clt->dev.release = rtrs_clt_dev_release;
	err = dev_set_name(&clt->dev, "%s", sessname);
	if (err)
		goto err;
		goto err_put;

	/*
	 * Suppress user space notification until
	 * sysfs files are created
	 */
	dev_set_uevent_suppress(&clt->dev, true);
	err = device_register(&clt->dev);
	if (err) {
		put_device(&clt->dev);
		goto err;
	}
	err = device_add(&clt->dev);
	if (err)
		goto err_put;

	clt->kobj_paths = kobject_create_and_add("paths", &clt->dev.kobj);
	if (!clt->kobj_paths) {
		err = -ENOMEM;
		goto err_dev;
		goto err_del;
	}
	err = rtrs_clt_create_sysfs_root_files(clt);
	if (err) {
		kobject_del(clt->kobj_paths);
		kobject_put(clt->kobj_paths);
		goto err_dev;
		goto err_del;
	}
	dev_set_uevent_suppress(&clt->dev, false);
	kobject_uevent(&clt->dev.kobj, KOBJ_ADD);

	return clt;
err_dev:
	device_unregister(&clt->dev);
err:
err_del:
	device_del(&clt->dev);
err_put:
	free_percpu(clt->pcpu_path);
	kfree(clt);
	put_device(&clt->dev);
	return ERR_PTR(err);
}

static void free_clt(struct rtrs_clt_sess *clt)
{
	free_permits(clt);
	free_percpu(clt->pcpu_path);
	mutex_destroy(&clt->paths_ev_mutex);
	mutex_destroy(&clt->paths_mutex);
	/* release callback will free clt in last put */

	/*
	 * release callback will free clt and destroy mutexes in last put
	 */
	device_unregister(&clt->dev);
}

@@ -2890,6 +2892,7 @@ void rtrs_clt_close(struct rtrs_clt_sess *clt)
		rtrs_clt_destroy_path_files(clt_path, NULL);
		kobject_put(&clt_path->kobj);
	}
	free_permits(clt);
	free_clt(clt);
}
EXPORT_SYMBOL(rtrs_clt_close);
+4 −2
Original line number Diff line number Diff line
@@ -4047,9 +4047,11 @@ static void srp_remove_one(struct ib_device *device, void *client_data)
		spin_unlock(&host->target_lock);

		/*
		 * Wait for tl_err and target port removal tasks.
		 * srp_queue_remove_work() queues a call to
		 * srp_remove_target(). The latter function cancels
		 * target->tl_err_work so waiting for the remove works to
		 * finish is sufficient.
		 */
		flush_workqueue(system_long_wq);
		flush_workqueue(srp_remove_wq);

		kfree(host);