Commit 847748fc authored by Hangbin Liu's avatar Hangbin Liu Committed by Paolo Abeni
Browse files

hsr: hold rcu and dev lock for hsr_get_port_ndev



hsr_get_port_ndev calls hsr_for_each_port, which need to hold rcu lock.
On the other hand, before return the port device, we need to hold the
device reference to avoid UaF in the caller function.

Suggested-by: default avatarPaolo Abeni <pabeni@redhat.com>
Fixes: 9c10dd8e ("net: hsr: Create and export hsr_get_port_ndev()")
Signed-off-by: default avatarHangbin Liu <liuhangbin@gmail.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250905091533.377443-4-liuhangbin@gmail.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 393c841f
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -654,7 +654,7 @@ static void icssg_prueth_hsr_fdb_add_del(struct prueth_emac *emac,

static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)
{
	struct net_device *real_dev;
	struct net_device *real_dev, *port_dev;
	struct prueth_emac *emac;
	u8 vlan_id, i;

@@ -663,11 +663,15 @@ static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)

	if (is_hsr_master(real_dev)) {
		for (i = HSR_PT_SLAVE_A; i < HSR_PT_INTERLINK; i++) {
			emac = netdev_priv(hsr_get_port_ndev(real_dev, i));
			if (!emac)
			port_dev = hsr_get_port_ndev(real_dev, i);
			emac = netdev_priv(port_dev);
			if (!emac) {
				dev_put(port_dev);
				return -EINVAL;
			}
			icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id,
						     true);
			dev_put(port_dev);
		}
	} else {
		emac = netdev_priv(real_dev);
@@ -679,7 +683,7 @@ static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)

static int icssg_prueth_hsr_del_mcast(struct net_device *ndev, const u8 *addr)
{
	struct net_device *real_dev;
	struct net_device *real_dev, *port_dev;
	struct prueth_emac *emac;
	u8 vlan_id, i;

@@ -688,11 +692,15 @@ static int icssg_prueth_hsr_del_mcast(struct net_device *ndev, const u8 *addr)

	if (is_hsr_master(real_dev)) {
		for (i = HSR_PT_SLAVE_A; i < HSR_PT_INTERLINK; i++) {
			emac = netdev_priv(hsr_get_port_ndev(real_dev, i));
			if (!emac)
			port_dev = hsr_get_port_ndev(real_dev, i);
			emac = netdev_priv(port_dev);
			if (!emac) {
				dev_put(port_dev);
				return -EINVAL;
			}
			icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id,
						     false);
			dev_put(port_dev);
		}
	} else {
		emac = netdev_priv(real_dev);
+6 −1
Original line number Diff line number Diff line
@@ -675,9 +675,14 @@ struct net_device *hsr_get_port_ndev(struct net_device *ndev,
	struct hsr_priv *hsr = netdev_priv(ndev);
	struct hsr_port *port;

	rcu_read_lock();
	hsr_for_each_port(hsr, port)
		if (port->type == pt)
		if (port->type == pt) {
			dev_hold(port->dev);
			rcu_read_unlock();
			return port->dev;
		}
	rcu_read_unlock();
	return NULL;
}
EXPORT_SYMBOL(hsr_get_port_ndev);