udp: annotate data-races around udp->encap_type
authorEric Dumazet <edumazet@google.com>
Tue, 12 Sep 2023 09:17:28 +0000 (09:17 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:58:56 +0000 (11:58 +0100)
[ Upstream commit 70a36f571362a8de8b8c02d21ae524fc776287f2 ]

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: 1da177e4c3f4 ("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>
drivers/net/gtp.c
net/ipv4/udp.c
net/ipv4/xfrm4_input.c
net/ipv6/udp.c
net/ipv6/xfrm6_input.c
net/l2tp/l2tp_core.c

index b22596b..b191927 100644 (file)
@@ -630,7 +630,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);
@@ -682,7 +682,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);
index 637a4fa..2eeab4a 100644 (file)
@@ -714,7 +714,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,
@@ -2081,7 +2081,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);
 
                /*
@@ -2684,7 +2685,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:
@@ -2785,7 +2786,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:
index eac206a..183f6dc 100644 (file)
@@ -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;
index 9068887..0e79d18 100644 (file)
@@ -571,7 +571,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,
@@ -688,7 +688,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);
 
                /*
index 4907ab2..4156387 100644 (file)
@@ -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;
index 03608d3..8d21ff2 100644 (file)
@@ -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;