Skip to content

Commit 2aac7a2

Browse files
xemuldavem330
authored andcommitted
unix_diag: Pending connections IDs NLA
When establishing a unix connection on stream sockets the server end receives an skb with socket in its receive queue. Report who is waiting for these ends to be accepted for listening sockets via NLA. There's a lokcing issue with this -- the unix sk state lock is required to access the peer, and it is taken under the listening sk's queue lock. Strictly speaking the queue lock should be taken inside the state lock, but since in this case these two sockets are different it shouldn't lead to deadlock. Signed-off-by: Pavel Emelyanov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ac02be8 commit 2aac7a2

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

include/linux/unix_diag.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct unix_diag_req {
1414
#define UDIAG_SHOW_NAME 0x00000001 /* show name (not path) */
1515
#define UDIAG_SHOW_VFS 0x00000002 /* show VFS inode info */
1616
#define UDIAG_SHOW_PEER 0x00000004 /* show peer socket info */
17+
#define UDIAG_SHOW_ICONS 0x00000008 /* show pending connections */
1718

1819
struct unix_diag_msg {
1920
__u8 udiag_family;
@@ -29,6 +30,7 @@ enum {
2930
UNIX_DIAG_NAME,
3031
UNIX_DIAG_VFS,
3132
UNIX_DIAG_PEER,
33+
UNIX_DIAG_ICONS,
3234

3335
UNIX_DIAG_MAX,
3436
};

net/unix/diag.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,41 @@ static int sk_diag_dump_peer(struct sock *sk, struct sk_buff *nlskb)
6363
return -EMSGSIZE;
6464
}
6565

66+
static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb)
67+
{
68+
struct sk_buff *skb;
69+
u32 *buf;
70+
int i;
71+
72+
if (sk->sk_state == TCP_LISTEN) {
73+
spin_lock(&sk->sk_receive_queue.lock);
74+
buf = UNIX_DIAG_PUT(nlskb, UNIX_DIAG_ICONS, sk->sk_receive_queue.qlen);
75+
i = 0;
76+
skb_queue_walk(&sk->sk_receive_queue, skb) {
77+
struct sock *req, *peer;
78+
79+
req = skb->sk;
80+
/*
81+
* The state lock is outer for the same sk's
82+
* queue lock. With the other's queue locked it's
83+
* OK to lock the state.
84+
*/
85+
unix_state_lock_nested(req);
86+
peer = unix_sk(req)->peer;
87+
if (peer)
88+
buf[i++] = sock_i_ino(peer);
89+
unix_state_unlock(req);
90+
}
91+
spin_unlock(&sk->sk_receive_queue.lock);
92+
}
93+
94+
return 0;
95+
96+
rtattr_failure:
97+
spin_unlock(&sk->sk_receive_queue.lock);
98+
return -EMSGSIZE;
99+
}
100+
66101
static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
67102
u32 pid, u32 seq, u32 flags, int sk_ino)
68103
{
@@ -93,6 +128,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
93128
sk_diag_dump_peer(sk, skb))
94129
goto nlmsg_failure;
95130

131+
if ((req->udiag_show & UDIAG_SHOW_ICONS) &&
132+
sk_diag_dump_icons(sk, skb))
133+
goto nlmsg_failure;
134+
96135
nlh->nlmsg_len = skb_tail_pointer(skb) - b;
97136
return skb->len;
98137

0 commit comments

Comments
 (0)