Commit e97e68b5 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sk_bound_dev_if-annotations'



Eric Dumazet says:

====================
net: add annotations for sk->sk_bound_dev_if

While writes on sk->sk_bound_dev_if are protected by socket lock,
we have many lockless reads all over the places.

This is based on syzbot report found in the first patch changelog.

v2: inline ipv6 function only defined if IS_ENABLED(CONFIG_IPV6) (kernel bots)
    Change the INET6_MATCH() to inet6_match(), this is no longer a macro.
    Change INET_MATCH() to inet_match() (Olivier Hartkopp & Jakub Kicinski)

====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7fa2e481 eda090c3
Loading
Loading
Loading
Loading
+19 −9
Original line number Diff line number Diff line
@@ -103,15 +103,25 @@ struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
			  const int dif);

int inet6_hash(struct sock *sk);
#endif /* IS_ENABLED(CONFIG_IPV6) */

#define INET6_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif, __sdif) \
	(((__sk)->sk_portpair == (__ports))			&&	\
	 ((__sk)->sk_family == AF_INET6)			&&	\
	 ipv6_addr_equal(&(__sk)->sk_v6_daddr, (__saddr))		&&	\
	 ipv6_addr_equal(&(__sk)->sk_v6_rcv_saddr, (__daddr))	&&	\
	 (((__sk)->sk_bound_dev_if == (__dif))	||			\
	  ((__sk)->sk_bound_dev_if == (__sdif)))		&&	\
	 net_eq(sock_net(__sk), (__net)))
static inline bool inet6_match(struct net *net, const struct sock *sk,
			       const struct in6_addr *saddr,
			       const struct in6_addr *daddr,
			       const __portpair ports,
			       const int dif, const int sdif)
{
	int bound_dev_if;

	if (!net_eq(sock_net(sk), net) ||
	    sk->sk_family != AF_INET6 ||
	    sk->sk_portpair != ports ||
	    !ipv6_addr_equal(&sk->sk_v6_daddr, saddr) ||
	    !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr))
		return false;

	bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
	return bound_dev_if == dif || bound_dev_if == sdif;
}
#endif /* IS_ENABLED(CONFIG_IPV6) */

#endif /* _INET6_HASHTABLES_H */
+1 −1
Original line number Diff line number Diff line
@@ -267,7 +267,7 @@ static inline struct sock *inet_lookup_listener(struct net *net,
				   ((__force __u64)(__be32)(__saddr)))
#endif /* __BIG_ENDIAN */

static inline bool INET_MATCH(struct net *net, const struct sock *sk,
static inline bool inet_match(struct net *net, const struct sock *sk,
			      const __addrpair cookie, const __portpair ports,
			      int dif, int sdif)
{
+3 −2
Original line number Diff line number Diff line
@@ -116,14 +116,15 @@ static inline u32 inet_request_mark(const struct sock *sk, struct sk_buff *skb)
static inline int inet_request_bound_dev_if(const struct sock *sk,
					    struct sk_buff *skb)
{
	int bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
#ifdef CONFIG_NET_L3_MASTER_DEV
	struct net *net = sock_net(sk);

	if (!sk->sk_bound_dev_if && net->ipv4.sysctl_tcp_l3mdev_accept)
	if (!bound_dev_if && net->ipv4.sysctl_tcp_l3mdev_accept)
		return l3mdev_master_ifindex_by_index(net, skb->skb_iif);
#endif

	return sk->sk_bound_dev_if;
	return bound_dev_if;
}

static inline int inet_sk_bound_l3mdev(const struct sock *sk)
+1 −1
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ static inline void ipcm_init_sk(struct ipcm_cookie *ipcm,

	ipcm->sockc.mark = inet->sk.sk_mark;
	ipcm->sockc.tsflags = inet->sk.sk_tsflags;
	ipcm->oif = inet->sk.sk_bound_dev_if;
	ipcm->oif = READ_ONCE(inet->sk.sk_bound_dev_if);
	ipcm->addr = inet->inet_saddr;
}

+3 −2
Original line number Diff line number Diff line
@@ -2875,13 +2875,14 @@ static inline void sk_pacing_shift_update(struct sock *sk, int val)
 */
static inline bool sk_dev_equal_l3scope(struct sock *sk, int dif)
{
	int bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
	int mdif;

	if (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)
	if (!bound_dev_if || bound_dev_if == dif)
		return true;

	mdif = l3mdev_master_ifindex_by_index(sock_net(sk), dif);
	if (mdif && mdif == sk->sk_bound_dev_if)
	if (mdif && mdif == bound_dev_if)
		return true;

	return false;
Loading