Commit 0b0e4d51 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Jakub Kicinski
Browse files

smc: Use __sk_dst_get() and dst_dev_rcu() in smc_vlan_by_tcpsk().



smc_vlan_by_tcpsk() fetches sk_dst_get(sk)->dev before RTNL and
passes it to netdev_walk_all_lower_dev(), which is illegal.

Also, smc_vlan_by_tcpsk_walk() does not require RTNL at all.

Let's use __sk_dst_get(), dst_dev_rcu(), and
netdev_walk_all_lower_dev_rcu().

Note that the returned value of smc_vlan_by_tcpsk() is not used
in the caller.

Fixes: 0cfdd8f9 ("smc: connection and link group creation")
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250916214758.650211-5-kuniyu@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 235f8104
Loading
Loading
Loading
Loading
+12 −15
Original line number Diff line number Diff line
@@ -1883,35 +1883,32 @@ static int smc_vlan_by_tcpsk_walk(struct net_device *lower_dev,
/* Determine vlan of internal TCP socket. */
int smc_vlan_by_tcpsk(struct socket *clcsock, struct smc_init_info *ini)
{
	struct dst_entry *dst = sk_dst_get(clcsock->sk);
	struct netdev_nested_priv priv;
	struct net_device *ndev;
	struct dst_entry *dst;
	int rc = 0;

	ini->vlan_id = 0;
	if (!dst) {
		rc = -ENOTCONN;
		goto out;
	}
	if (!dst->dev) {

	rcu_read_lock();

	dst = __sk_dst_get(clcsock->sk);
	ndev = dst ? dst_dev_rcu(dst) : NULL;
	if (!ndev) {
		rc = -ENODEV;
		goto out_rel;
		goto out;
	}

	ndev = dst->dev;
	if (is_vlan_dev(ndev)) {
		ini->vlan_id = vlan_dev_vlan_id(ndev);
		goto out_rel;
		goto out;
	}

	priv.data = (void *)&ini->vlan_id;
	rtnl_lock();
	netdev_walk_all_lower_dev(ndev, smc_vlan_by_tcpsk_walk, &priv);
	rtnl_unlock();

out_rel:
	dst_release(dst);
	netdev_walk_all_lower_dev_rcu(ndev, smc_vlan_by_tcpsk_walk, &priv);
out:
	rcu_read_unlock();

	return rc;
}