]> Git Repo - linux.git/commitdiff
af_unix: Annotate data-races around sk->sk_state in UNIX_DIAG.
authorKuniyuki Iwashima <[email protected]>
Tue, 4 Jun 2024 16:52:35 +0000 (09:52 -0700)
committerPaolo Abeni <[email protected]>
Thu, 6 Jun 2024 10:57:15 +0000 (12:57 +0200)
While dumping AF_UNIX sockets via UNIX_DIAG, sk->sk_state is read
locklessly.

Let's use READ_ONCE() there.

Note that the result could be inconsistent if the socket is dumped
during the state change.  This is common for other SOCK_DIAG and
similar interfaces.

Fixes: c9da99e6475f ("unix_diag: Fixup RQLEN extension report")
Fixes: 2aac7a2cb0d9 ("unix_diag: Pending connections IDs NLA")
Fixes: 45a96b9be6ec ("unix_diag: Dumping all sockets core")
Signed-off-by: Kuniyuki Iwashima <[email protected]>
Signed-off-by: Paolo Abeni <[email protected]>
net/unix/diag.c

index ae39538c5042b34e864e709004bf554841eaf4c9..116cf508aea4abc8d2e87ddd254e982bb3928f1b 100644 (file)
@@ -65,7 +65,7 @@ static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb)
        u32 *buf;
        int i;
 
-       if (sk->sk_state == TCP_LISTEN) {
+       if (READ_ONCE(sk->sk_state) == TCP_LISTEN) {
                spin_lock(&sk->sk_receive_queue.lock);
 
                attr = nla_reserve(nlskb, UNIX_DIAG_ICONS,
@@ -103,7 +103,7 @@ static int sk_diag_show_rqlen(struct sock *sk, struct sk_buff *nlskb)
 {
        struct unix_diag_rqlen rql;
 
-       if (sk->sk_state == TCP_LISTEN) {
+       if (READ_ONCE(sk->sk_state) == TCP_LISTEN) {
                rql.udiag_rqueue = sk->sk_receive_queue.qlen;
                rql.udiag_wqueue = sk->sk_max_ack_backlog;
        } else {
@@ -136,7 +136,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
        rep = nlmsg_data(nlh);
        rep->udiag_family = AF_UNIX;
        rep->udiag_type = sk->sk_type;
-       rep->udiag_state = sk->sk_state;
+       rep->udiag_state = READ_ONCE(sk->sk_state);
        rep->pad = 0;
        rep->udiag_ino = sk_ino;
        sock_diag_save_cookie(sk, rep->udiag_cookie);
@@ -215,7 +215,7 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
                sk_for_each(sk, &net->unx.table.buckets[slot]) {
                        if (num < s_num)
                                goto next;
-                       if (!(req->udiag_states & (1 << sk->sk_state)))
+                       if (!(req->udiag_states & (1 << READ_ONCE(sk->sk_state))))
                                goto next;
                        if (sk_diag_dump(sk, skb, req, sk_user_ns(skb->sk),
                                         NETLINK_CB(cb->skb).portid,
This page took 0.059786 seconds and 4 git commands to generate.