mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
udp: annotate data-races around udp->encap_type
[ Upstream commit70a36f5713
] syzbot/KCSAN complained about UDP_ENCAP_L2TPINUDP setsockopt() racing. Add READ_ONCE()/WRITE_ONCE() to document races on this lockless field. syzbot report was: BUG: KCSAN: data-race in udp_lib_setsockopt / udp_lib_setsockopt read-write to 0xffff8881083603fa of 1 bytes by task 16557 on cpu 0: udp_lib_setsockopt+0x682/0x6c0 udp_setsockopt+0x73/0xa0 net/ipv4/udp.c:2779 sock_common_setsockopt+0x61/0x70 net/core/sock.c:3697 __sys_setsockopt+0x1c9/0x230 net/socket.c:2263 __do_sys_setsockopt net/socket.c:2274 [inline] __se_sys_setsockopt net/socket.c:2271 [inline] __x64_sys_setsockopt+0x66/0x80 net/socket.c:2271 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd read-write to 0xffff8881083603fa of 1 bytes by task 16554 on cpu 1: udp_lib_setsockopt+0x682/0x6c0 udp_setsockopt+0x73/0xa0 net/ipv4/udp.c:2779 sock_common_setsockopt+0x61/0x70 net/core/sock.c:3697 __sys_setsockopt+0x1c9/0x230 net/socket.c:2263 __do_sys_setsockopt net/socket.c:2274 [inline] __se_sys_setsockopt net/socket.c:2271 [inline] __x64_sys_setsockopt+0x66/0x80 net/socket.c:2271 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd value changed: 0x01 -> 0x05 Reported by Kernel Concurrency Sanitizer on: CPU: 1 PID: 16554 Comm: syz-executor.5 Not tainted 6.5.0-rc7-syzkaller-00004-gf7757129e3de #0 Fixes:1da177e4c3
("Linux-2.6.12-rc2") Reported-by: syzbot <syzkaller@googlegroups.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
b92fd3e60d
commit
645d838018
@ -629,7 +629,7 @@ static void __gtp_encap_destroy(struct sock *sk)
|
||||
gtp->sk0 = NULL;
|
||||
else
|
||||
gtp->sk1u = NULL;
|
||||
udp_sk(sk)->encap_type = 0;
|
||||
WRITE_ONCE(udp_sk(sk)->encap_type, 0);
|
||||
rcu_assign_sk_user_data(sk, NULL);
|
||||
release_sock(sk);
|
||||
sock_put(sk);
|
||||
@ -681,7 +681,7 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
|
||||
|
||||
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
|
||||
|
||||
switch (udp_sk(sk)->encap_type) {
|
||||
switch (READ_ONCE(udp_sk(sk)->encap_type)) {
|
||||
case UDP_ENCAP_GTP0:
|
||||
netdev_dbg(gtp->dev, "received GTP0 packet\n");
|
||||
ret = gtp0_udp_encap_recv(gtp, skb);
|
||||
|
@ -744,7 +744,7 @@ int __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
|
||||
iph->saddr, uh->source, skb->dev->ifindex,
|
||||
inet_sdif(skb), udptable, NULL);
|
||||
|
||||
if (!sk || udp_sk(sk)->encap_type) {
|
||||
if (!sk || READ_ONCE(udp_sk(sk)->encap_type)) {
|
||||
/* No socket for error: try tunnels before discarding */
|
||||
if (static_branch_unlikely(&udp_encap_needed_key)) {
|
||||
sk = __udp4_lib_err_encap(net, iph, uh, udptable, sk, skb,
|
||||
@ -2110,7 +2110,8 @@ static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
|
||||
}
|
||||
nf_reset_ct(skb);
|
||||
|
||||
if (static_branch_unlikely(&udp_encap_needed_key) && up->encap_type) {
|
||||
if (static_branch_unlikely(&udp_encap_needed_key) &&
|
||||
READ_ONCE(up->encap_type)) {
|
||||
int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
|
||||
|
||||
/*
|
||||
@ -2709,7 +2710,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
|
||||
#endif
|
||||
fallthrough;
|
||||
case UDP_ENCAP_L2TPINUDP:
|
||||
up->encap_type = val;
|
||||
WRITE_ONCE(up->encap_type, val);
|
||||
udp_tunnel_encap_enable(sk);
|
||||
break;
|
||||
default:
|
||||
@ -2810,7 +2811,7 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
|
||||
break;
|
||||
|
||||
case UDP_ENCAP:
|
||||
val = up->encap_type;
|
||||
val = READ_ONCE(up->encap_type);
|
||||
break;
|
||||
|
||||
case UDP_NO_CHECK6_TX:
|
||||
|
@ -85,11 +85,11 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
struct udphdr *uh;
|
||||
struct iphdr *iph;
|
||||
int iphlen, len;
|
||||
|
||||
__u8 *udpdata;
|
||||
__be32 *udpdata32;
|
||||
__u16 encap_type = up->encap_type;
|
||||
u16 encap_type;
|
||||
|
||||
encap_type = READ_ONCE(up->encap_type);
|
||||
/* if this is not encapsulated socket, then just return now */
|
||||
if (!encap_type)
|
||||
return 1;
|
||||
|
@ -604,7 +604,7 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source,
|
||||
inet6_iif(skb), inet6_sdif(skb), udptable, NULL);
|
||||
|
||||
if (!sk || udp_sk(sk)->encap_type) {
|
||||
if (!sk || READ_ONCE(udp_sk(sk)->encap_type)) {
|
||||
/* No socket for error: try tunnels before discarding */
|
||||
if (static_branch_unlikely(&udpv6_encap_needed_key)) {
|
||||
sk = __udp6_lib_err_encap(net, hdr, offset, uh,
|
||||
@ -721,7 +721,8 @@ static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
|
||||
}
|
||||
nf_reset_ct(skb);
|
||||
|
||||
if (static_branch_unlikely(&udpv6_encap_needed_key) && up->encap_type) {
|
||||
if (static_branch_unlikely(&udpv6_encap_needed_key) &&
|
||||
READ_ONCE(up->encap_type)) {
|
||||
int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
|
||||
|
||||
/*
|
||||
|
@ -81,14 +81,14 @@ int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
struct ipv6hdr *ip6h;
|
||||
int len;
|
||||
int ip6hlen = sizeof(struct ipv6hdr);
|
||||
|
||||
__u8 *udpdata;
|
||||
__be32 *udpdata32;
|
||||
__u16 encap_type = up->encap_type;
|
||||
u16 encap_type;
|
||||
|
||||
if (skb->protocol == htons(ETH_P_IP))
|
||||
return xfrm4_udp_encap_rcv(sk, skb);
|
||||
|
||||
encap_type = READ_ONCE(up->encap_type);
|
||||
/* if this is not encapsulated socket, then just return now */
|
||||
if (!encap_type)
|
||||
return 1;
|
||||
|
@ -1139,9 +1139,9 @@ static void l2tp_tunnel_destruct(struct sock *sk)
|
||||
switch (tunnel->encap) {
|
||||
case L2TP_ENCAPTYPE_UDP:
|
||||
/* No longer an encapsulation socket. See net/ipv4/udp.c */
|
||||
(udp_sk(sk))->encap_type = 0;
|
||||
(udp_sk(sk))->encap_rcv = NULL;
|
||||
(udp_sk(sk))->encap_destroy = NULL;
|
||||
WRITE_ONCE(udp_sk(sk)->encap_type, 0);
|
||||
udp_sk(sk)->encap_rcv = NULL;
|
||||
udp_sk(sk)->encap_destroy = NULL;
|
||||
break;
|
||||
case L2TP_ENCAPTYPE_IP:
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user