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

bpf: sockmap: Only check ULP for TCP sockets

The sock map code checks that a socket does not have an active upper
layer protocol before inserting it into the map. This requires casting
via inet_csk, which isn't valid for UDP sockets.

Guard checks for ULP by checking inet_sk(sk)->is_icsk first.

Signed-off-by: Lorenz Bauer <lmb@cloudflare.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/20200309111243.6982-2-lmb@cloudflare.com

authored by

Lorenz Bauer and committed by
Daniel Borkmann
7b70973d 3e7c67d9

+15 -12
+7 -1
include/linux/skmsg.h
··· 360 360 struct sk_psock *psock) 361 361 { 362 362 sk->sk_prot->unhash = psock->saved_unhash; 363 - tcp_update_ulp(sk, psock->sk_proto, psock->saved_write_space); 363 + if (inet_csk_has_ulp(sk)) { 364 + tcp_update_ulp(sk, psock->sk_proto, psock->saved_write_space); 365 + } else { 366 + sk->sk_write_space = psock->saved_write_space; 367 + /* Pairs with lockless read in sk_clone_lock() */ 368 + WRITE_ONCE(sk->sk_prot, psock->sk_proto); 369 + } 364 370 } 365 371 366 372 static inline void sk_psock_set_state(struct sk_psock *psock,
+6
include/net/inet_connection_sock.h
··· 335 335 if (icsk->icsk_ack.pingpong < U8_MAX) 336 336 icsk->icsk_ack.pingpong++; 337 337 } 338 + 339 + static inline bool inet_csk_has_ulp(struct sock *sk) 340 + { 341 + return inet_sk(sk)->is_icsk && !!inet_csk(sk)->icsk_ulp_ops; 342 + } 343 + 338 344 #endif /* _INET_CONNECTION_SOCK_H */
+2 -4
net/core/sock_map.c
··· 384 384 struct sock *sk, u64 flags) 385 385 { 386 386 struct bpf_stab *stab = container_of(map, struct bpf_stab, map); 387 - struct inet_connection_sock *icsk = inet_csk(sk); 388 387 struct sk_psock_link *link; 389 388 struct sk_psock *psock; 390 389 struct sock *osk; ··· 394 395 return -EINVAL; 395 396 if (unlikely(idx >= map->max_entries)) 396 397 return -E2BIG; 397 - if (unlikely(rcu_access_pointer(icsk->icsk_ulp_data))) 398 + if (inet_csk_has_ulp(sk)) 398 399 return -EINVAL; 399 400 400 401 link = sk_psock_init_link(); ··· 737 738 struct sock *sk, u64 flags) 738 739 { 739 740 struct bpf_htab *htab = container_of(map, struct bpf_htab, map); 740 - struct inet_connection_sock *icsk = inet_csk(sk); 741 741 u32 key_size = map->key_size, hash; 742 742 struct bpf_htab_elem *elem, *elem_new; 743 743 struct bpf_htab_bucket *bucket; ··· 747 749 WARN_ON_ONCE(!rcu_read_lock_held()); 748 750 if (unlikely(flags > BPF_EXIST)) 749 751 return -EINVAL; 750 - if (unlikely(icsk->icsk_ulp_data)) 752 + if (inet_csk_has_ulp(sk)) 751 753 return -EINVAL; 752 754 753 755 link = sk_psock_init_link();
-7
net/ipv4/tcp_ulp.c
··· 105 105 { 106 106 struct inet_connection_sock *icsk = inet_csk(sk); 107 107 108 - if (!icsk->icsk_ulp_ops) { 109 - sk->sk_write_space = write_space; 110 - /* Pairs with lockless read in sk_clone_lock() */ 111 - WRITE_ONCE(sk->sk_prot, proto); 112 - return; 113 - } 114 - 115 108 if (icsk->icsk_ulp_ops->update) 116 109 icsk->icsk_ulp_ops->update(sk, proto, write_space); 117 110 }