Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net/tcp: Add missing lockdep annotations for TCP-AO hlist traversals

Under CONFIG_PROVE_RCU_LIST + CONFIG_RCU_EXPERT
hlist_for_each_entry_rcu() provides very helpful splats, which help
to find possible issues. I missed CONFIG_RCU_EXPERT=y in my testing
config the same as described in
a3e4bf7f9675 ("configs/debug: make sure PROVE_RCU_LIST=y takes effect").

The fix itself is trivial: add the very same lockdep annotations
as were used to dereference ao_info from the socket.

Reported-by: Jakub Kicinski <kuba@kernel.org>
Closes: https://lore.kernel.org/netdev/20241028152645.35a8be66@kernel.org/
Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com>
Link: https://patch.msgid.link/20241030-tcp-ao-hlist-lockdep-annotate-v1-1-bf641a64d7c6@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Dmitry Safonov and committed by
Jakub Kicinski
6b2d11e2 6578a749

+29 -23
+2 -1
include/net/tcp_ao.h
··· 183 183 const u8 *tkey, int hash_offset, u32 sne); 184 184 int tcp_parse_ao(struct sock *sk, int cmd, unsigned short int family, 185 185 sockptr_t optval, int optlen); 186 - struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao, 186 + struct tcp_ao_key *tcp_ao_established_key(const struct sock *sk, 187 + struct tcp_ao_info *ao, 187 188 int sndid, int rcvid); 188 189 int tcp_ao_copy_all_matching(const struct sock *sk, struct sock *newsk, 189 190 struct request_sock *req, struct sk_buff *skb,
+23 -19
net/ipv4/tcp_ao.c
··· 109 109 * it's known that the keys in ao_info are matching peer's 110 110 * family/address/VRF/etc. 111 111 */ 112 - struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao, 112 + struct tcp_ao_key *tcp_ao_established_key(const struct sock *sk, 113 + struct tcp_ao_info *ao, 113 114 int sndid, int rcvid) 114 115 { 115 116 struct tcp_ao_key *key; 116 117 117 - hlist_for_each_entry_rcu(key, &ao->head, node) { 118 + hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) { 118 119 if ((sndid >= 0 && key->sndid != sndid) || 119 120 (rcvid >= 0 && key->rcvid != rcvid)) 120 121 continue; ··· 206 205 if (!ao) 207 206 return NULL; 208 207 209 - hlist_for_each_entry_rcu(key, &ao->head, node) { 208 + hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) { 210 209 u8 prefixlen = min(prefix, key->prefixlen); 211 210 212 211 if (!tcp_ao_key_cmp(key, l3index, addr, prefixlen, ··· 794 793 if (!ao_info) 795 794 return -ENOENT; 796 795 797 - *key = tcp_ao_established_key(ao_info, aoh->rnext_keyid, -1); 796 + *key = tcp_ao_established_key(sk, ao_info, aoh->rnext_keyid, -1); 798 797 if (!*key) 799 798 return -ENOENT; 800 799 *traffic_key = snd_other_key(*key); ··· 980 979 */ 981 980 key = READ_ONCE(info->rnext_key); 982 981 if (key->rcvid != aoh->keyid) { 983 - key = tcp_ao_established_key(info, -1, aoh->keyid); 982 + key = tcp_ao_established_key(sk, info, -1, aoh->keyid); 984 983 if (!key) 985 984 goto key_not_found; 986 985 } ··· 1004 1003 aoh->rnext_keyid, 1005 1004 tcp_ao_hdr_maclen(aoh)); 1006 1005 /* If the key is not found we do nothing. */ 1007 - key = tcp_ao_established_key(info, aoh->rnext_keyid, -1); 1006 + key = tcp_ao_established_key(sk, info, aoh->rnext_keyid, -1); 1008 1007 if (key) 1009 1008 /* pairs with tcp_ao_del_cmd */ 1010 1009 WRITE_ONCE(info->current_key, key); ··· 1164 1163 if (!ao) 1165 1164 return; 1166 1165 1167 - hlist_for_each_entry_rcu(key, &ao->head, node) 1166 + hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) 1168 1167 tcp_ao_cache_traffic_keys(sk, ao, key); 1169 1168 } 1170 1169 ··· 1181 1180 WRITE_ONCE(ao->risn, tcp_hdr(skb)->seq); 1182 1181 ao->rcv_sne = 0; 1183 1182 1184 - hlist_for_each_entry_rcu(key, &ao->head, node) 1183 + hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) 1185 1184 tcp_ao_cache_traffic_keys(sk, ao, key); 1186 1185 } 1187 1186 ··· 1257 1256 key_head = rcu_dereference(hlist_first_rcu(&new_ao->head)); 1258 1257 first_key = hlist_entry_safe(key_head, struct tcp_ao_key, node); 1259 1258 1260 - key = tcp_ao_established_key(new_ao, tcp_rsk(req)->ao_keyid, -1); 1259 + key = tcp_ao_established_key(req_to_sk(req), new_ao, tcp_rsk(req)->ao_keyid, -1); 1261 1260 if (key) 1262 1261 new_ao->current_key = key; 1263 1262 else 1264 1263 new_ao->current_key = first_key; 1265 1264 1266 1265 /* set rnext_key */ 1267 - key = tcp_ao_established_key(new_ao, -1, tcp_rsk(req)->ao_rcv_next); 1266 + key = tcp_ao_established_key(req_to_sk(req), new_ao, -1, tcp_rsk(req)->ao_rcv_next); 1268 1267 if (key) 1269 1268 new_ao->rnext_key = key; 1270 1269 else ··· 1858 1857 * if there's any. 1859 1858 */ 1860 1859 if (cmd.set_current) { 1861 - new_current = tcp_ao_established_key(ao_info, cmd.current_key, -1); 1860 + new_current = tcp_ao_established_key(sk, ao_info, cmd.current_key, -1); 1862 1861 if (!new_current) 1863 1862 return -ENOENT; 1864 1863 } 1865 1864 if (cmd.set_rnext) { 1866 - new_rnext = tcp_ao_established_key(ao_info, -1, cmd.rnext); 1865 + new_rnext = tcp_ao_established_key(sk, ao_info, -1, cmd.rnext); 1867 1866 if (!new_rnext) 1868 1867 return -ENOENT; 1869 1868 } ··· 1903 1902 * "It is presumed that an MKT affecting a particular 1904 1903 * connection cannot be destroyed during an active connection" 1905 1904 */ 1906 - hlist_for_each_entry_rcu(key, &ao_info->head, node) { 1905 + hlist_for_each_entry_rcu(key, &ao_info->head, node, 1906 + lockdep_sock_is_held(sk)) { 1907 1907 if (cmd.sndid != key->sndid || 1908 1908 cmd.rcvid != key->rcvid) 1909 1909 continue; ··· 2002 2000 * if there's any. 2003 2001 */ 2004 2002 if (cmd.set_current) { 2005 - new_current = tcp_ao_established_key(ao_info, cmd.current_key, -1); 2003 + new_current = tcp_ao_established_key(sk, ao_info, cmd.current_key, -1); 2006 2004 if (!new_current) { 2007 2005 err = -ENOENT; 2008 2006 goto out; 2009 2007 } 2010 2008 } 2011 2009 if (cmd.set_rnext) { 2012 - new_rnext = tcp_ao_established_key(ao_info, -1, cmd.rnext); 2010 + new_rnext = tcp_ao_established_key(sk, ao_info, -1, cmd.rnext); 2013 2011 if (!new_rnext) { 2014 2012 err = -ENOENT; 2015 2013 goto out; ··· 2103 2101 * The layout of the fields in the user and kernel structures is expected to 2104 2102 * be the same (including in the 32bit vs 64bit case). 2105 2103 */ 2106 - static int tcp_ao_copy_mkts_to_user(struct tcp_ao_info *ao_info, 2104 + static int tcp_ao_copy_mkts_to_user(const struct sock *sk, 2105 + struct tcp_ao_info *ao_info, 2107 2106 sockptr_t optval, sockptr_t optlen) 2108 2107 { 2109 2108 struct tcp_ao_getsockopt opt_in, opt_out; ··· 2232 2229 /* May change in RX, while we're dumping, pre-fetch it */ 2233 2230 current_key = READ_ONCE(ao_info->current_key); 2234 2231 2235 - hlist_for_each_entry_rcu(key, &ao_info->head, node) { 2232 + hlist_for_each_entry_rcu(key, &ao_info->head, node, 2233 + lockdep_sock_is_held(sk)) { 2236 2234 if (opt_in.get_all) 2237 2235 goto match; 2238 2236 ··· 2313 2309 if (!ao_info) 2314 2310 return -ENOENT; 2315 2311 2316 - return tcp_ao_copy_mkts_to_user(ao_info, optval, optlen); 2312 + return tcp_ao_copy_mkts_to_user(sk, ao_info, optval, optlen); 2317 2313 } 2318 2314 2319 2315 int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockptr_t optlen) ··· 2400 2396 WRITE_ONCE(ao->snd_sne, cmd.snd_sne); 2401 2397 WRITE_ONCE(ao->rcv_sne, cmd.rcv_sne); 2402 2398 2403 - hlist_for_each_entry_rcu(key, &ao->head, node) 2399 + hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) 2404 2400 tcp_ao_cache_traffic_keys(sk, ao, key); 2405 2401 2406 2402 return 0;
+2 -1
net/ipv4/tcp_ipv4.c
··· 1053 1053 } 1054 1054 1055 1055 if (aoh) 1056 - key.ao_key = tcp_ao_established_key(ao_info, aoh->rnext_keyid, -1); 1056 + key.ao_key = tcp_ao_established_key(sk, ao_info, 1057 + aoh->rnext_keyid, -1); 1057 1058 } 1058 1059 } 1059 1060 if (key.ao_key) {
+2 -2
net/ipv6/tcp_ipv6.c
··· 1172 1172 if (tcp_parse_auth_options(tcp_hdr(skb), NULL, &aoh)) 1173 1173 goto out; 1174 1174 if (aoh) 1175 - key.ao_key = tcp_ao_established_key(ao_info, 1176 - aoh->rnext_keyid, -1); 1175 + key.ao_key = tcp_ao_established_key(sk, ao_info, 1176 + aoh->rnext_keyid, -1); 1177 1177 } 1178 1178 } 1179 1179 if (key.ao_key) {