smc: Use __sk_dst_get() and dst_dev_rcu() in in smc_clc_prfx_set().
smc_clc_prfx_set() is called during connect() and not under RCU
nor RTNL.
Using sk_dst_get(sk)->dev could trigger UAF.
Let's use __sk_dst_get() and dev_dst_rcu() under rcu_read_lock()
after kernel_getsockname().
Note that the returned value of smc_clc_prfx_set() is not used
in the caller.
While at it, we change the 1st arg of smc_clc_prfx_set[46]_rcu()
not to touch dst there.
Fixes: a046d57da1 ("smc: CLC handshake (incl. preparation steps)")
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250916214758.650211-3-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
3d3466878a
commit
935d783e5d
|
|
@ -509,10 +509,10 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl)
|
|||
}
|
||||
|
||||
/* find ipv4 addr on device and get the prefix len, fill CLC proposal msg */
|
||||
static int smc_clc_prfx_set4_rcu(struct dst_entry *dst, __be32 ipv4,
|
||||
static int smc_clc_prfx_set4_rcu(struct net_device *dev, __be32 ipv4,
|
||||
struct smc_clc_msg_proposal_prefix *prop)
|
||||
{
|
||||
struct in_device *in_dev = __in_dev_get_rcu(dst->dev);
|
||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||
const struct in_ifaddr *ifa;
|
||||
|
||||
if (!in_dev)
|
||||
|
|
@ -530,12 +530,12 @@ static int smc_clc_prfx_set4_rcu(struct dst_entry *dst, __be32 ipv4,
|
|||
}
|
||||
|
||||
/* fill CLC proposal msg with ipv6 prefixes from device */
|
||||
static int smc_clc_prfx_set6_rcu(struct dst_entry *dst,
|
||||
static int smc_clc_prfx_set6_rcu(struct net_device *dev,
|
||||
struct smc_clc_msg_proposal_prefix *prop,
|
||||
struct smc_clc_ipv6_prefix *ipv6_prfx)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct inet6_dev *in6_dev = __in6_dev_get(dst->dev);
|
||||
struct inet6_dev *in6_dev = __in6_dev_get(dev);
|
||||
struct inet6_ifaddr *ifa;
|
||||
int cnt = 0;
|
||||
|
||||
|
|
@ -564,41 +564,44 @@ static int smc_clc_prfx_set(struct socket *clcsock,
|
|||
struct smc_clc_msg_proposal_prefix *prop,
|
||||
struct smc_clc_ipv6_prefix *ipv6_prfx)
|
||||
{
|
||||
struct dst_entry *dst = sk_dst_get(clcsock->sk);
|
||||
struct sockaddr_storage addrs;
|
||||
struct sockaddr_in6 *addr6;
|
||||
struct sockaddr_in *addr;
|
||||
struct net_device *dev;
|
||||
struct dst_entry *dst;
|
||||
int rc = -ENOENT;
|
||||
|
||||
if (!dst) {
|
||||
rc = -ENOTCONN;
|
||||
goto out;
|
||||
}
|
||||
if (!dst->dev) {
|
||||
rc = -ENODEV;
|
||||
goto out_rel;
|
||||
}
|
||||
/* get address to which the internal TCP socket is bound */
|
||||
if (kernel_getsockname(clcsock, (struct sockaddr *)&addrs) < 0)
|
||||
goto out_rel;
|
||||
goto out;
|
||||
|
||||
/* analyze IP specific data of net_device belonging to TCP socket */
|
||||
addr6 = (struct sockaddr_in6 *)&addrs;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
dst = __sk_dst_get(clcsock->sk);
|
||||
dev = dst ? dst_dev_rcu(dst) : NULL;
|
||||
if (!dev) {
|
||||
rc = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (addrs.ss_family == PF_INET) {
|
||||
/* IPv4 */
|
||||
addr = (struct sockaddr_in *)&addrs;
|
||||
rc = smc_clc_prfx_set4_rcu(dst, addr->sin_addr.s_addr, prop);
|
||||
rc = smc_clc_prfx_set4_rcu(dev, addr->sin_addr.s_addr, prop);
|
||||
} else if (ipv6_addr_v4mapped(&addr6->sin6_addr)) {
|
||||
/* mapped IPv4 address - peer is IPv4 only */
|
||||
rc = smc_clc_prfx_set4_rcu(dst, addr6->sin6_addr.s6_addr32[3],
|
||||
rc = smc_clc_prfx_set4_rcu(dev, addr6->sin6_addr.s6_addr32[3],
|
||||
prop);
|
||||
} else {
|
||||
/* IPv6 */
|
||||
rc = smc_clc_prfx_set6_rcu(dst, prop, ipv6_prfx);
|
||||
rc = smc_clc_prfx_set6_rcu(dev, prop, ipv6_prfx);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
out_rel:
|
||||
dst_release(dst);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue