Branch data Line data Source code
1 : : /* License: GPL */
2 : :
3 : : #include <linux/mutex.h>
4 : : #include <linux/socket.h>
5 : : #include <linux/skbuff.h>
6 : : #include <net/netlink.h>
7 : : #include <net/net_namespace.h>
8 : : #include <linux/module.h>
9 : : #include <net/sock.h>
10 : : #include <linux/kernel.h>
11 : : #include <linux/tcp.h>
12 : : #include <linux/workqueue.h>
13 : : #include <linux/nospec.h>
14 : :
15 : : #include <linux/inet_diag.h>
16 : : #include <linux/sock_diag.h>
17 : :
18 : : static const struct sock_diag_handler *sock_diag_handlers[AF_MAX];
19 : : static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
20 : : static DEFINE_MUTEX(sock_diag_table_mutex);
21 : : static struct workqueue_struct *broadcast_wq;
22 : : static atomic64_t cookie_gen;
23 : :
24 : 0 : u64 sock_gen_cookie(struct sock *sk)
25 : : {
26 : : while (1) {
27 : 0 : u64 res = atomic64_read(&sk->sk_cookie);
28 : :
29 [ # # ]: 0 : if (res)
30 : 0 : return res;
31 : 0 : res = atomic64_inc_return(&cookie_gen);
32 : : atomic64_cmpxchg(&sk->sk_cookie, 0, res);
33 : : }
34 : : }
35 : :
36 : 0 : int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie)
37 : : {
38 : : u64 res;
39 : :
40 [ # # # # ]: 0 : if (cookie[0] == INET_DIAG_NOCOOKIE && cookie[1] == INET_DIAG_NOCOOKIE)
41 : : return 0;
42 : :
43 : 0 : res = sock_gen_cookie(sk);
44 [ # # # # ]: 0 : if ((u32)res != cookie[0] || (u32)(res >> 32) != cookie[1])
45 : : return -ESTALE;
46 : :
47 : 0 : return 0;
48 : : }
49 : : EXPORT_SYMBOL_GPL(sock_diag_check_cookie);
50 : :
51 : 0 : void sock_diag_save_cookie(struct sock *sk, __u32 *cookie)
52 : : {
53 : 0 : u64 res = sock_gen_cookie(sk);
54 : :
55 : 0 : cookie[0] = (u32)res;
56 : 0 : cookie[1] = (u32)(res >> 32);
57 : 0 : }
58 : : EXPORT_SYMBOL_GPL(sock_diag_save_cookie);
59 : :
60 : 0 : int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)
61 : : {
62 : : u32 mem[SK_MEMINFO_VARS];
63 : :
64 : 0 : sk_get_meminfo(sk, mem);
65 : :
66 : 0 : return nla_put(skb, attrtype, sizeof(mem), &mem);
67 : : }
68 : : EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
69 : :
70 : 0 : int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk,
71 : : struct sk_buff *skb, int attrtype)
72 : : {
73 : : struct sock_fprog_kern *fprog;
74 : : struct sk_filter *filter;
75 : : struct nlattr *attr;
76 : : unsigned int flen;
77 : : int err = 0;
78 : :
79 [ # # ]: 0 : if (!may_report_filterinfo) {
80 : 0 : nla_reserve(skb, attrtype, 0);
81 : 0 : return 0;
82 : : }
83 : :
84 : : rcu_read_lock();
85 : 0 : filter = rcu_dereference(sk->sk_filter);
86 [ # # ]: 0 : if (!filter)
87 : : goto out;
88 : :
89 : 0 : fprog = filter->prog->orig_prog;
90 [ # # ]: 0 : if (!fprog)
91 : : goto out;
92 : :
93 : 0 : flen = bpf_classic_proglen(fprog);
94 : :
95 : 0 : attr = nla_reserve(skb, attrtype, flen);
96 [ # # ]: 0 : if (attr == NULL) {
97 : : err = -EMSGSIZE;
98 : : goto out;
99 : : }
100 : :
101 : 0 : memcpy(nla_data(attr), fprog->filter, flen);
102 : : out:
103 : : rcu_read_unlock();
104 : 0 : return err;
105 : : }
106 : : EXPORT_SYMBOL(sock_diag_put_filterinfo);
107 : :
108 : : struct broadcast_sk {
109 : : struct sock *sk;
110 : : struct work_struct work;
111 : : };
112 : :
113 : : static size_t sock_diag_nlmsg_size(void)
114 : : {
115 : : return NLMSG_ALIGN(sizeof(struct inet_diag_msg)
116 : : + nla_total_size(sizeof(u8)) /* INET_DIAG_PROTOCOL */
117 : : + nla_total_size_64bit(sizeof(struct tcp_info))); /* INET_DIAG_INFO */
118 : : }
119 : :
120 : 0 : static void sock_diag_broadcast_destroy_work(struct work_struct *work)
121 : : {
122 : : struct broadcast_sk *bsk =
123 : 0 : container_of(work, struct broadcast_sk, work);
124 : 0 : struct sock *sk = bsk->sk;
125 : : const struct sock_diag_handler *hndl;
126 : : struct sk_buff *skb;
127 : 0 : const enum sknetlink_groups group = sock_diag_destroy_group(sk);
128 : : int err = -1;
129 : :
130 [ # # ]: 0 : WARN_ON(group == SKNLGRP_NONE);
131 : :
132 : : skb = nlmsg_new(sock_diag_nlmsg_size(), GFP_KERNEL);
133 [ # # ]: 0 : if (!skb)
134 : : goto out;
135 : :
136 : 0 : mutex_lock(&sock_diag_table_mutex);
137 : 0 : hndl = sock_diag_handlers[sk->sk_family];
138 [ # # # # ]: 0 : if (hndl && hndl->get_info)
139 : 0 : err = hndl->get_info(skb, sk);
140 : 0 : mutex_unlock(&sock_diag_table_mutex);
141 : :
142 [ # # ]: 0 : if (!err)
143 : 0 : nlmsg_multicast(sock_net(sk)->diag_nlsk, skb, 0, group,
144 : : GFP_KERNEL);
145 : : else
146 : 0 : kfree_skb(skb);
147 : : out:
148 : 0 : sk_destruct(sk);
149 : 0 : kfree(bsk);
150 : 0 : }
151 : :
152 : 0 : void sock_diag_broadcast_destroy(struct sock *sk)
153 : : {
154 : : /* Note, this function is often called from an interrupt context. */
155 : : struct broadcast_sk *bsk =
156 : : kmalloc(sizeof(struct broadcast_sk), GFP_ATOMIC);
157 [ # # ]: 0 : if (!bsk)
158 : 0 : return sk_destruct(sk);
159 : 0 : bsk->sk = sk;
160 : 0 : INIT_WORK(&bsk->work, sock_diag_broadcast_destroy_work);
161 : 0 : queue_work(broadcast_wq, &bsk->work);
162 : : }
163 : :
164 : 0 : void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
165 : : {
166 : 0 : mutex_lock(&sock_diag_table_mutex);
167 : 0 : inet_rcv_compat = fn;
168 : 0 : mutex_unlock(&sock_diag_table_mutex);
169 : 0 : }
170 : : EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat);
171 : :
172 : 0 : void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
173 : : {
174 : 0 : mutex_lock(&sock_diag_table_mutex);
175 : 0 : inet_rcv_compat = NULL;
176 : 0 : mutex_unlock(&sock_diag_table_mutex);
177 : 0 : }
178 : : EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat);
179 : :
180 : 0 : int sock_diag_register(const struct sock_diag_handler *hndl)
181 : : {
182 : : int err = 0;
183 : :
184 [ # # ]: 0 : if (hndl->family >= AF_MAX)
185 : : return -EINVAL;
186 : :
187 : 0 : mutex_lock(&sock_diag_table_mutex);
188 [ # # ]: 0 : if (sock_diag_handlers[hndl->family])
189 : : err = -EBUSY;
190 : : else
191 : 0 : sock_diag_handlers[hndl->family] = hndl;
192 : 0 : mutex_unlock(&sock_diag_table_mutex);
193 : :
194 : 0 : return err;
195 : : }
196 : : EXPORT_SYMBOL_GPL(sock_diag_register);
197 : :
198 : 0 : void sock_diag_unregister(const struct sock_diag_handler *hnld)
199 : : {
200 : 0 : int family = hnld->family;
201 : :
202 [ # # ]: 0 : if (family >= AF_MAX)
203 : 0 : return;
204 : :
205 : 0 : mutex_lock(&sock_diag_table_mutex);
206 [ # # ]: 0 : BUG_ON(sock_diag_handlers[family] != hnld);
207 : 0 : sock_diag_handlers[family] = NULL;
208 : 0 : mutex_unlock(&sock_diag_table_mutex);
209 : : }
210 : : EXPORT_SYMBOL_GPL(sock_diag_unregister);
211 : :
212 : 0 : static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh)
213 : : {
214 : : int err;
215 : : struct sock_diag_req *req = nlmsg_data(nlh);
216 : : const struct sock_diag_handler *hndl;
217 : :
218 [ # # ]: 0 : if (nlmsg_len(nlh) < sizeof(*req))
219 : : return -EINVAL;
220 : :
221 [ # # ]: 0 : if (req->sdiag_family >= AF_MAX)
222 : : return -EINVAL;
223 : 0 : req->sdiag_family = array_index_nospec(req->sdiag_family, AF_MAX);
224 : :
225 [ # # ]: 0 : if (sock_diag_handlers[req->sdiag_family] == NULL)
226 : 0 : sock_load_diag_module(req->sdiag_family, 0);
227 : :
228 : 0 : mutex_lock(&sock_diag_table_mutex);
229 : 0 : hndl = sock_diag_handlers[req->sdiag_family];
230 [ # # ]: 0 : if (hndl == NULL)
231 : : err = -ENOENT;
232 [ # # ]: 0 : else if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY)
233 : 0 : err = hndl->dump(skb, nlh);
234 [ # # # # ]: 0 : else if (nlh->nlmsg_type == SOCK_DESTROY && hndl->destroy)
235 : 0 : err = hndl->destroy(skb, nlh);
236 : : else
237 : : err = -EOPNOTSUPP;
238 : 0 : mutex_unlock(&sock_diag_table_mutex);
239 : :
240 : 0 : return err;
241 : : }
242 : :
243 : 0 : static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
244 : : struct netlink_ext_ack *extack)
245 : : {
246 : : int ret;
247 : :
248 [ # # # ]: 0 : switch (nlh->nlmsg_type) {
249 : : case TCPDIAG_GETSOCK:
250 : : case DCCPDIAG_GETSOCK:
251 [ # # ]: 0 : if (inet_rcv_compat == NULL)
252 : 0 : sock_load_diag_module(AF_INET, 0);
253 : :
254 : 0 : mutex_lock(&sock_diag_table_mutex);
255 [ # # ]: 0 : if (inet_rcv_compat != NULL)
256 : 0 : ret = inet_rcv_compat(skb, nlh);
257 : : else
258 : : ret = -EOPNOTSUPP;
259 : 0 : mutex_unlock(&sock_diag_table_mutex);
260 : :
261 : 0 : return ret;
262 : : case SOCK_DIAG_BY_FAMILY:
263 : : case SOCK_DESTROY:
264 : 0 : return __sock_diag_cmd(skb, nlh);
265 : : default:
266 : : return -EINVAL;
267 : : }
268 : : }
269 : :
270 : : static DEFINE_MUTEX(sock_diag_mutex);
271 : :
272 : 0 : static void sock_diag_rcv(struct sk_buff *skb)
273 : : {
274 : 0 : mutex_lock(&sock_diag_mutex);
275 : 0 : netlink_rcv_skb(skb, &sock_diag_rcv_msg);
276 : 0 : mutex_unlock(&sock_diag_mutex);
277 : 0 : }
278 : :
279 : 0 : static int sock_diag_bind(struct net *net, int group)
280 : : {
281 [ # # # ]: 0 : switch (group) {
282 : : case SKNLGRP_INET_TCP_DESTROY:
283 : : case SKNLGRP_INET_UDP_DESTROY:
284 [ # # ]: 0 : if (!sock_diag_handlers[AF_INET])
285 : 0 : sock_load_diag_module(AF_INET, 0);
286 : : break;
287 : : case SKNLGRP_INET6_TCP_DESTROY:
288 : : case SKNLGRP_INET6_UDP_DESTROY:
289 [ # # ]: 0 : if (!sock_diag_handlers[AF_INET6])
290 : 0 : sock_load_diag_module(AF_INET6, 0);
291 : : break;
292 : : }
293 : 0 : return 0;
294 : : }
295 : :
296 : 0 : int sock_diag_destroy(struct sock *sk, int err)
297 : : {
298 [ # # ]: 0 : if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
299 : : return -EPERM;
300 : :
301 [ # # ]: 0 : if (!sk->sk_prot->diag_destroy)
302 : : return -EOPNOTSUPP;
303 : :
304 : 0 : return sk->sk_prot->diag_destroy(sk, err);
305 : : }
306 : : EXPORT_SYMBOL_GPL(sock_diag_destroy);
307 : :
308 : 207 : static int __net_init diag_net_init(struct net *net)
309 : : {
310 : 207 : struct netlink_kernel_cfg cfg = {
311 : : .groups = SKNLGRP_MAX,
312 : : .input = sock_diag_rcv,
313 : : .bind = sock_diag_bind,
314 : : .flags = NL_CFG_F_NONROOT_RECV,
315 : : };
316 : :
317 : 207 : net->diag_nlsk = netlink_kernel_create(net, NETLINK_SOCK_DIAG, &cfg);
318 [ + - ]: 207 : return net->diag_nlsk == NULL ? -ENOMEM : 0;
319 : : }
320 : :
321 : 0 : static void __net_exit diag_net_exit(struct net *net)
322 : : {
323 : 0 : netlink_kernel_release(net->diag_nlsk);
324 : 0 : net->diag_nlsk = NULL;
325 : 0 : }
326 : :
327 : : static struct pernet_operations diag_net_ops = {
328 : : .init = diag_net_init,
329 : : .exit = diag_net_exit,
330 : : };
331 : :
332 : 207 : static int __init sock_diag_init(void)
333 : : {
334 : 207 : broadcast_wq = alloc_workqueue("sock_diag_events", 0, 0);
335 [ - + ]: 207 : BUG_ON(!broadcast_wq);
336 : 207 : return register_pernet_subsys(&diag_net_ops);
337 : : }
338 : : device_initcall(sock_diag_init);
|