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