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

Commit 39096420 authored by Matan Barak's avatar Matan Barak Committed by Doug Ledford
Browse files

IB/core: Fix use after free of ifa



When using ifup/ifdown while executing enum_netdev_ipv4_ips,
ifa could become invalid and cause use after free error.
Fixing it by protecting with RCU lock.

Fixes: 03db3a2d ('IB/core: Add RoCE GID table management')
Signed-off-by: default avatarMatan Barak <matanb@mellanox.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 17b38fb8
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -250,25 +250,44 @@ static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
				 u8 port, struct net_device *ndev)
{
	struct in_device *in_dev;
	struct sin_list {
		struct list_head	list;
		struct sockaddr_in	ip;
	};
	struct sin_list *sin_iter;
	struct sin_list *sin_temp;

	LIST_HEAD(sin_list);
	if (ndev->reg_state >= NETREG_UNREGISTERING)
		return;

	in_dev = in_dev_get(ndev);
	if (!in_dev)
	rcu_read_lock();
	in_dev = __in_dev_get_rcu(ndev);
	if (!in_dev) {
		rcu_read_unlock();
		return;
	}

	for_ifa(in_dev) {
		struct sockaddr_in ip;
		struct sin_list *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);

		ip.sin_family = AF_INET;
		ip.sin_addr.s_addr = ifa->ifa_address;
		update_gid_ip(GID_ADD, ib_dev, port, ndev,
			      (struct sockaddr *)&ip);
		if (!entry) {
			pr_warn("roce_gid_mgmt: couldn't allocate entry for IPv4 update\n");
			continue;
		}
		entry->ip.sin_family = AF_INET;
		entry->ip.sin_addr.s_addr = ifa->ifa_address;
		list_add_tail(&entry->list, &sin_list);
	}
	endfor_ifa(in_dev);
	rcu_read_unlock();

	in_dev_put(in_dev);
	list_for_each_entry_safe(sin_iter, sin_temp, &sin_list, list) {
		update_gid_ip(GID_ADD, ib_dev, port, ndev,
			      (struct sockaddr *)&sin_iter->ip);
		list_del(&sin_iter->list);
		kfree(sin_iter);
	}
}

static void enum_netdev_ipv6_ips(struct ib_device *ib_dev,