xref: /openbmc/linux/net/vmw_vsock/diag.c (revision e7bae9bb)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * vsock sock_diag(7) module
4  *
5  * Copyright (C) 2017 Red Hat, Inc.
6  * Author: Stefan Hajnoczi <stefanha@redhat.com>
7  */
8 
9 #include <linux/module.h>
10 #include <linux/sock_diag.h>
11 #include <linux/vm_sockets_diag.h>
12 #include <net/af_vsock.h>
13 
14 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
15 			u32 portid, u32 seq, u32 flags)
16 {
17 	struct vsock_sock *vsk = vsock_sk(sk);
18 	struct vsock_diag_msg *rep;
19 	struct nlmsghdr *nlh;
20 
21 	nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
22 			flags);
23 	if (!nlh)
24 		return -EMSGSIZE;
25 
26 	rep = nlmsg_data(nlh);
27 	rep->vdiag_family = AF_VSOCK;
28 
29 	/* Lock order dictates that sk_lock is acquired before
30 	 * vsock_table_lock, so we cannot lock here.  Simply don't take
31 	 * sk_lock; sk is guaranteed to stay alive since vsock_table_lock is
32 	 * held.
33 	 */
34 	rep->vdiag_type = sk->sk_type;
35 	rep->vdiag_state = sk->sk_state;
36 	rep->vdiag_shutdown = sk->sk_shutdown;
37 	rep->vdiag_src_cid = vsk->local_addr.svm_cid;
38 	rep->vdiag_src_port = vsk->local_addr.svm_port;
39 	rep->vdiag_dst_cid = vsk->remote_addr.svm_cid;
40 	rep->vdiag_dst_port = vsk->remote_addr.svm_port;
41 	rep->vdiag_ino = sock_i_ino(sk);
42 
43 	sock_diag_save_cookie(sk, rep->vdiag_cookie);
44 
45 	return 0;
46 }
47 
48 static int vsock_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
49 {
50 	struct vsock_diag_req *req;
51 	struct vsock_sock *vsk;
52 	unsigned int bucket;
53 	unsigned int last_i;
54 	unsigned int table;
55 	struct net *net;
56 	unsigned int i;
57 
58 	req = nlmsg_data(cb->nlh);
59 	net = sock_net(skb->sk);
60 
61 	/* State saved between calls: */
62 	table = cb->args[0];
63 	bucket = cb->args[1];
64 	i = last_i = cb->args[2];
65 
66 	/* TODO VMCI pending sockets? */
67 
68 	spin_lock_bh(&vsock_table_lock);
69 
70 	/* Bind table (locally created sockets) */
71 	if (table == 0) {
72 		while (bucket < ARRAY_SIZE(vsock_bind_table)) {
73 			struct list_head *head = &vsock_bind_table[bucket];
74 
75 			i = 0;
76 			list_for_each_entry(vsk, head, bound_table) {
77 				struct sock *sk = sk_vsock(vsk);
78 
79 				if (!net_eq(sock_net(sk), net))
80 					continue;
81 				if (i < last_i)
82 					goto next_bind;
83 				if (!(req->vdiag_states & (1 << sk->sk_state)))
84 					goto next_bind;
85 				if (sk_diag_fill(sk, skb,
86 						 NETLINK_CB(cb->skb).portid,
87 						 cb->nlh->nlmsg_seq,
88 						 NLM_F_MULTI) < 0)
89 					goto done;
90 next_bind:
91 				i++;
92 			}
93 			last_i = 0;
94 			bucket++;
95 		}
96 
97 		table++;
98 		bucket = 0;
99 	}
100 
101 	/* Connected table (accepted connections) */
102 	while (bucket < ARRAY_SIZE(vsock_connected_table)) {
103 		struct list_head *head = &vsock_connected_table[bucket];
104 
105 		i = 0;
106 		list_for_each_entry(vsk, head, connected_table) {
107 			struct sock *sk = sk_vsock(vsk);
108 
109 			/* Skip sockets we've already seen above */
110 			if (__vsock_in_bound_table(vsk))
111 				continue;
112 
113 			if (!net_eq(sock_net(sk), net))
114 				continue;
115 			if (i < last_i)
116 				goto next_connected;
117 			if (!(req->vdiag_states & (1 << sk->sk_state)))
118 				goto next_connected;
119 			if (sk_diag_fill(sk, skb,
120 					 NETLINK_CB(cb->skb).portid,
121 					 cb->nlh->nlmsg_seq,
122 					 NLM_F_MULTI) < 0)
123 				goto done;
124 next_connected:
125 			i++;
126 		}
127 		last_i = 0;
128 		bucket++;
129 	}
130 
131 done:
132 	spin_unlock_bh(&vsock_table_lock);
133 
134 	cb->args[0] = table;
135 	cb->args[1] = bucket;
136 	cb->args[2] = i;
137 
138 	return skb->len;
139 }
140 
141 static int vsock_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
142 {
143 	int hdrlen = sizeof(struct vsock_diag_req);
144 	struct net *net = sock_net(skb->sk);
145 
146 	if (nlmsg_len(h) < hdrlen)
147 		return -EINVAL;
148 
149 	if (h->nlmsg_flags & NLM_F_DUMP) {
150 		struct netlink_dump_control c = {
151 			.dump = vsock_diag_dump,
152 		};
153 		return netlink_dump_start(net->diag_nlsk, skb, h, &c);
154 	}
155 
156 	return -EOPNOTSUPP;
157 }
158 
159 static const struct sock_diag_handler vsock_diag_handler = {
160 	.family = AF_VSOCK,
161 	.dump = vsock_diag_handler_dump,
162 };
163 
164 static int __init vsock_diag_init(void)
165 {
166 	return sock_diag_register(&vsock_diag_handler);
167 }
168 
169 static void __exit vsock_diag_exit(void)
170 {
171 	sock_diag_unregister(&vsock_diag_handler);
172 }
173 
174 module_init(vsock_diag_init);
175 module_exit(vsock_diag_exit);
176 MODULE_LICENSE("GPL");
177 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG,
178 			       40 /* AF_VSOCK */);
179