.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * inet_diag.c Module for monitoring INET transport protocols sockets. |
---|
3 | 4 | * |
---|
4 | 5 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or |
---|
7 | | - * modify it under the terms of the GNU General Public License |
---|
8 | | - * as published by the Free Software Foundation; either version |
---|
9 | | - * 2 of the License, or (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/kernel.h> |
---|
.. | .. |
---|
27 | 23 | #include <net/inet_hashtables.h> |
---|
28 | 24 | #include <net/inet_timewait_sock.h> |
---|
29 | 25 | #include <net/inet6_hashtables.h> |
---|
| 26 | +#include <net/bpf_sk_storage.h> |
---|
30 | 27 | #include <net/netlink.h> |
---|
31 | 28 | |
---|
32 | 29 | #include <linux/inet.h> |
---|
.. | .. |
---|
46 | 43 | u16 userlocks; |
---|
47 | 44 | u32 ifindex; |
---|
48 | 45 | u32 mark; |
---|
| 46 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
---|
| 47 | + u64 cgroup_id; |
---|
| 48 | +#endif |
---|
49 | 49 | }; |
---|
50 | 50 | |
---|
51 | 51 | static DEFINE_MUTEX(inet_diag_table_mutex); |
---|
52 | 52 | |
---|
53 | 53 | static const struct inet_diag_handler *inet_diag_lock_handler(int proto) |
---|
54 | 54 | { |
---|
| 55 | + if (proto < 0 || proto >= IPPROTO_MAX) { |
---|
| 56 | + mutex_lock(&inet_diag_table_mutex); |
---|
| 57 | + return ERR_PTR(-ENOENT); |
---|
| 58 | + } |
---|
| 59 | + |
---|
55 | 60 | if (!inet_diag_table[proto]) |
---|
56 | 61 | sock_load_diag_module(AF_INET, proto); |
---|
57 | 62 | |
---|
.. | .. |
---|
120 | 125 | bool net_admin) |
---|
121 | 126 | { |
---|
122 | 127 | const struct inet_sock *inet = inet_sk(sk); |
---|
| 128 | + struct inet_diag_sockopt inet_sockopt; |
---|
123 | 129 | |
---|
124 | 130 | if (nla_put_u8(skb, INET_DIAG_SHUTDOWN, sk->sk_shutdown)) |
---|
125 | 131 | goto errout; |
---|
.. | .. |
---|
165 | 171 | goto errout; |
---|
166 | 172 | } |
---|
167 | 173 | |
---|
| 174 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
---|
| 175 | + if (nla_put_u64_64bit(skb, INET_DIAG_CGROUP_ID, |
---|
| 176 | + cgroup_id(sock_cgroup_ptr(&sk->sk_cgrp_data)), |
---|
| 177 | + INET_DIAG_PAD)) |
---|
| 178 | + goto errout; |
---|
| 179 | +#endif |
---|
| 180 | + |
---|
168 | 181 | r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk)); |
---|
169 | 182 | r->idiag_inode = sock_i_ino(sk); |
---|
| 183 | + |
---|
| 184 | + memset(&inet_sockopt, 0, sizeof(inet_sockopt)); |
---|
| 185 | + inet_sockopt.recverr = inet->recverr; |
---|
| 186 | + inet_sockopt.is_icsk = inet->is_icsk; |
---|
| 187 | + inet_sockopt.freebind = inet->freebind; |
---|
| 188 | + inet_sockopt.hdrincl = inet->hdrincl; |
---|
| 189 | + inet_sockopt.mc_loop = inet->mc_loop; |
---|
| 190 | + inet_sockopt.transparent = inet->transparent; |
---|
| 191 | + inet_sockopt.mc_all = inet->mc_all; |
---|
| 192 | + inet_sockopt.nodefrag = inet->nodefrag; |
---|
| 193 | + inet_sockopt.bind_address_no_port = inet->bind_address_no_port; |
---|
| 194 | + inet_sockopt.recverr_rfc4884 = inet->recverr_rfc4884; |
---|
| 195 | + inet_sockopt.defer_connect = inet->defer_connect; |
---|
| 196 | + if (nla_put(skb, INET_DIAG_SOCKOPT, sizeof(inet_sockopt), |
---|
| 197 | + &inet_sockopt)) |
---|
| 198 | + goto errout; |
---|
170 | 199 | |
---|
171 | 200 | return 0; |
---|
172 | 201 | errout: |
---|
.. | .. |
---|
174 | 203 | } |
---|
175 | 204 | EXPORT_SYMBOL_GPL(inet_diag_msg_attrs_fill); |
---|
176 | 205 | |
---|
| 206 | +static int inet_diag_parse_attrs(const struct nlmsghdr *nlh, int hdrlen, |
---|
| 207 | + struct nlattr **req_nlas) |
---|
| 208 | +{ |
---|
| 209 | + struct nlattr *nla; |
---|
| 210 | + int remaining; |
---|
| 211 | + |
---|
| 212 | + nlmsg_for_each_attr(nla, nlh, hdrlen, remaining) { |
---|
| 213 | + int type = nla_type(nla); |
---|
| 214 | + |
---|
| 215 | + if (type == INET_DIAG_REQ_PROTOCOL && nla_len(nla) != sizeof(u32)) |
---|
| 216 | + return -EINVAL; |
---|
| 217 | + |
---|
| 218 | + if (type < __INET_DIAG_REQ_MAX) |
---|
| 219 | + req_nlas[type] = nla; |
---|
| 220 | + } |
---|
| 221 | + return 0; |
---|
| 222 | +} |
---|
| 223 | + |
---|
| 224 | +static int inet_diag_get_protocol(const struct inet_diag_req_v2 *req, |
---|
| 225 | + const struct inet_diag_dump_data *data) |
---|
| 226 | +{ |
---|
| 227 | + if (data->req_nlas[INET_DIAG_REQ_PROTOCOL]) |
---|
| 228 | + return nla_get_u32(data->req_nlas[INET_DIAG_REQ_PROTOCOL]); |
---|
| 229 | + return req->sdiag_protocol; |
---|
| 230 | +} |
---|
| 231 | + |
---|
| 232 | +#define MAX_DUMP_ALLOC_SIZE (KMALLOC_MAX_SIZE - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) |
---|
| 233 | + |
---|
177 | 234 | int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, |
---|
178 | | - struct sk_buff *skb, const struct inet_diag_req_v2 *req, |
---|
179 | | - struct user_namespace *user_ns, |
---|
180 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
---|
181 | | - const struct nlmsghdr *unlh, |
---|
182 | | - bool net_admin) |
---|
| 235 | + struct sk_buff *skb, struct netlink_callback *cb, |
---|
| 236 | + const struct inet_diag_req_v2 *req, |
---|
| 237 | + u16 nlmsg_flags, bool net_admin) |
---|
183 | 238 | { |
---|
184 | 239 | const struct tcp_congestion_ops *ca_ops; |
---|
185 | 240 | const struct inet_diag_handler *handler; |
---|
| 241 | + struct inet_diag_dump_data *cb_data; |
---|
186 | 242 | int ext = req->idiag_ext; |
---|
187 | 243 | struct inet_diag_msg *r; |
---|
188 | 244 | struct nlmsghdr *nlh; |
---|
189 | 245 | struct nlattr *attr; |
---|
190 | 246 | void *info = NULL; |
---|
191 | 247 | |
---|
192 | | - handler = inet_diag_table[req->sdiag_protocol]; |
---|
| 248 | + cb_data = cb->data; |
---|
| 249 | + handler = inet_diag_table[inet_diag_get_protocol(req, cb_data)]; |
---|
193 | 250 | BUG_ON(!handler); |
---|
194 | 251 | |
---|
195 | | - nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r), |
---|
196 | | - nlmsg_flags); |
---|
| 252 | + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, |
---|
| 253 | + cb->nlh->nlmsg_type, sizeof(*r), nlmsg_flags); |
---|
197 | 254 | if (!nlh) |
---|
198 | 255 | return -EMSGSIZE; |
---|
199 | 256 | |
---|
.. | .. |
---|
204 | 261 | r->idiag_state = sk->sk_state; |
---|
205 | 262 | r->idiag_timer = 0; |
---|
206 | 263 | r->idiag_retrans = 0; |
---|
| 264 | + r->idiag_expires = 0; |
---|
207 | 265 | |
---|
208 | | - if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns, net_admin)) |
---|
| 266 | + if (inet_diag_msg_attrs_fill(sk, skb, r, ext, |
---|
| 267 | + sk_user_ns(NETLINK_CB(cb->skb).sk), |
---|
| 268 | + net_admin)) |
---|
209 | 269 | goto errout; |
---|
210 | 270 | |
---|
211 | 271 | if (ext & (1 << (INET_DIAG_MEMINFO - 1))) { |
---|
212 | 272 | struct inet_diag_meminfo minfo = { |
---|
213 | 273 | .idiag_rmem = sk_rmem_alloc_get(sk), |
---|
214 | | - .idiag_wmem = sk->sk_wmem_queued, |
---|
| 274 | + .idiag_wmem = READ_ONCE(sk->sk_wmem_queued), |
---|
215 | 275 | .idiag_fmem = sk->sk_forward_alloc, |
---|
216 | 276 | .idiag_tmem = sk_wmem_alloc_get(sk), |
---|
217 | 277 | }; |
---|
.. | .. |
---|
244 | 304 | r->idiag_timer = 1; |
---|
245 | 305 | r->idiag_retrans = icsk->icsk_retransmits; |
---|
246 | 306 | r->idiag_expires = |
---|
247 | | - jiffies_to_msecs(icsk->icsk_timeout - jiffies); |
---|
| 307 | + jiffies_delta_to_msecs(icsk->icsk_timeout - jiffies); |
---|
248 | 308 | } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { |
---|
249 | 309 | r->idiag_timer = 4; |
---|
250 | 310 | r->idiag_retrans = icsk->icsk_probes_out; |
---|
251 | 311 | r->idiag_expires = |
---|
252 | | - jiffies_to_msecs(icsk->icsk_timeout - jiffies); |
---|
| 312 | + jiffies_delta_to_msecs(icsk->icsk_timeout - jiffies); |
---|
253 | 313 | } else if (timer_pending(&sk->sk_timer)) { |
---|
254 | 314 | r->idiag_timer = 2; |
---|
255 | 315 | r->idiag_retrans = icsk->icsk_probes_out; |
---|
256 | 316 | r->idiag_expires = |
---|
257 | | - jiffies_to_msecs(sk->sk_timer.expires - jiffies); |
---|
258 | | - } else { |
---|
259 | | - r->idiag_timer = 0; |
---|
260 | | - r->idiag_expires = 0; |
---|
| 317 | + jiffies_delta_to_msecs(sk->sk_timer.expires - jiffies); |
---|
261 | 318 | } |
---|
262 | 319 | |
---|
263 | 320 | if ((ext & (1 << (INET_DIAG_INFO - 1))) && handler->idiag_info_size) { |
---|
.. | .. |
---|
302 | 359 | goto errout; |
---|
303 | 360 | } |
---|
304 | 361 | |
---|
| 362 | + /* Keep it at the end for potential retry with a larger skb, |
---|
| 363 | + * or else do best-effort fitting, which is only done for the |
---|
| 364 | + * first_nlmsg. |
---|
| 365 | + */ |
---|
| 366 | + if (cb_data->bpf_stg_diag) { |
---|
| 367 | + bool first_nlmsg = ((unsigned char *)nlh == skb->data); |
---|
| 368 | + unsigned int prev_min_dump_alloc; |
---|
| 369 | + unsigned int total_nla_size = 0; |
---|
| 370 | + unsigned int msg_len; |
---|
| 371 | + int err; |
---|
| 372 | + |
---|
| 373 | + msg_len = skb_tail_pointer(skb) - (unsigned char *)nlh; |
---|
| 374 | + err = bpf_sk_storage_diag_put(cb_data->bpf_stg_diag, sk, skb, |
---|
| 375 | + INET_DIAG_SK_BPF_STORAGES, |
---|
| 376 | + &total_nla_size); |
---|
| 377 | + |
---|
| 378 | + if (!err) |
---|
| 379 | + goto out; |
---|
| 380 | + |
---|
| 381 | + total_nla_size += msg_len; |
---|
| 382 | + prev_min_dump_alloc = cb->min_dump_alloc; |
---|
| 383 | + if (total_nla_size > prev_min_dump_alloc) |
---|
| 384 | + cb->min_dump_alloc = min_t(u32, total_nla_size, |
---|
| 385 | + MAX_DUMP_ALLOC_SIZE); |
---|
| 386 | + |
---|
| 387 | + if (!first_nlmsg) |
---|
| 388 | + goto errout; |
---|
| 389 | + |
---|
| 390 | + if (cb->min_dump_alloc > prev_min_dump_alloc) |
---|
| 391 | + /* Retry with pskb_expand_head() with |
---|
| 392 | + * __GFP_DIRECT_RECLAIM |
---|
| 393 | + */ |
---|
| 394 | + goto errout; |
---|
| 395 | + |
---|
| 396 | + WARN_ON_ONCE(total_nla_size <= prev_min_dump_alloc); |
---|
| 397 | + |
---|
| 398 | + /* Send what we have for this sk |
---|
| 399 | + * and move on to the next sk in the following |
---|
| 400 | + * dump() |
---|
| 401 | + */ |
---|
| 402 | + } |
---|
| 403 | + |
---|
305 | 404 | out: |
---|
306 | 405 | nlmsg_end(skb, nlh); |
---|
307 | 406 | return 0; |
---|
.. | .. |
---|
312 | 411 | } |
---|
313 | 412 | EXPORT_SYMBOL_GPL(inet_sk_diag_fill); |
---|
314 | 413 | |
---|
315 | | -static int inet_csk_diag_fill(struct sock *sk, |
---|
316 | | - struct sk_buff *skb, |
---|
317 | | - const struct inet_diag_req_v2 *req, |
---|
318 | | - struct user_namespace *user_ns, |
---|
319 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
---|
320 | | - const struct nlmsghdr *unlh, |
---|
321 | | - bool net_admin) |
---|
322 | | -{ |
---|
323 | | - return inet_sk_diag_fill(sk, inet_csk(sk), skb, req, user_ns, |
---|
324 | | - portid, seq, nlmsg_flags, unlh, net_admin); |
---|
325 | | -} |
---|
326 | | - |
---|
327 | 414 | static int inet_twsk_diag_fill(struct sock *sk, |
---|
328 | 415 | struct sk_buff *skb, |
---|
329 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
---|
330 | | - const struct nlmsghdr *unlh) |
---|
| 416 | + struct netlink_callback *cb, |
---|
| 417 | + u16 nlmsg_flags) |
---|
331 | 418 | { |
---|
332 | 419 | struct inet_timewait_sock *tw = inet_twsk(sk); |
---|
333 | 420 | struct inet_diag_msg *r; |
---|
334 | 421 | struct nlmsghdr *nlh; |
---|
335 | 422 | long tmo; |
---|
336 | 423 | |
---|
337 | | - nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r), |
---|
338 | | - nlmsg_flags); |
---|
| 424 | + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, |
---|
| 425 | + cb->nlh->nlmsg_seq, cb->nlh->nlmsg_type, |
---|
| 426 | + sizeof(*r), nlmsg_flags); |
---|
339 | 427 | if (!nlh) |
---|
340 | 428 | return -EMSGSIZE; |
---|
341 | 429 | |
---|
342 | 430 | r = nlmsg_data(nlh); |
---|
343 | 431 | BUG_ON(tw->tw_state != TCP_TIME_WAIT); |
---|
344 | 432 | |
---|
345 | | - tmo = tw->tw_timer.expires - jiffies; |
---|
346 | | - if (tmo < 0) |
---|
347 | | - tmo = 0; |
---|
348 | | - |
---|
349 | 433 | inet_diag_msg_common_fill(r, sk); |
---|
350 | 434 | r->idiag_retrans = 0; |
---|
351 | 435 | |
---|
352 | 436 | r->idiag_state = tw->tw_substate; |
---|
353 | 437 | r->idiag_timer = 3; |
---|
354 | | - r->idiag_expires = jiffies_to_msecs(tmo); |
---|
| 438 | + tmo = tw->tw_timer.expires - jiffies; |
---|
| 439 | + r->idiag_expires = jiffies_delta_to_msecs(tmo); |
---|
355 | 440 | r->idiag_rqueue = 0; |
---|
356 | 441 | r->idiag_wqueue = 0; |
---|
357 | 442 | r->idiag_uid = 0; |
---|
.. | .. |
---|
362 | 447 | } |
---|
363 | 448 | |
---|
364 | 449 | static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb, |
---|
365 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
---|
366 | | - const struct nlmsghdr *unlh, bool net_admin) |
---|
| 450 | + struct netlink_callback *cb, |
---|
| 451 | + u16 nlmsg_flags, bool net_admin) |
---|
367 | 452 | { |
---|
368 | 453 | struct request_sock *reqsk = inet_reqsk(sk); |
---|
369 | 454 | struct inet_diag_msg *r; |
---|
370 | 455 | struct nlmsghdr *nlh; |
---|
371 | 456 | long tmo; |
---|
372 | 457 | |
---|
373 | | - nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r), |
---|
374 | | - nlmsg_flags); |
---|
| 458 | + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, |
---|
| 459 | + cb->nlh->nlmsg_type, sizeof(*r), nlmsg_flags); |
---|
375 | 460 | if (!nlh) |
---|
376 | 461 | return -EMSGSIZE; |
---|
377 | 462 | |
---|
.. | .. |
---|
385 | 470 | offsetof(struct sock, sk_cookie)); |
---|
386 | 471 | |
---|
387 | 472 | tmo = inet_reqsk(sk)->rsk_timer.expires - jiffies; |
---|
388 | | - r->idiag_expires = (tmo >= 0) ? jiffies_to_msecs(tmo) : 0; |
---|
| 473 | + r->idiag_expires = jiffies_delta_to_msecs(tmo); |
---|
389 | 474 | r->idiag_rqueue = 0; |
---|
390 | 475 | r->idiag_wqueue = 0; |
---|
391 | 476 | r->idiag_uid = 0; |
---|
.. | .. |
---|
402 | 487 | } |
---|
403 | 488 | |
---|
404 | 489 | static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, |
---|
| 490 | + struct netlink_callback *cb, |
---|
405 | 491 | const struct inet_diag_req_v2 *r, |
---|
406 | | - struct user_namespace *user_ns, |
---|
407 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
---|
408 | | - const struct nlmsghdr *unlh, bool net_admin) |
---|
| 492 | + u16 nlmsg_flags, bool net_admin) |
---|
409 | 493 | { |
---|
410 | 494 | if (sk->sk_state == TCP_TIME_WAIT) |
---|
411 | | - return inet_twsk_diag_fill(sk, skb, portid, seq, |
---|
412 | | - nlmsg_flags, unlh); |
---|
| 495 | + return inet_twsk_diag_fill(sk, skb, cb, nlmsg_flags); |
---|
413 | 496 | |
---|
414 | 497 | if (sk->sk_state == TCP_NEW_SYN_RECV) |
---|
415 | | - return inet_req_diag_fill(sk, skb, portid, seq, |
---|
416 | | - nlmsg_flags, unlh, net_admin); |
---|
| 498 | + return inet_req_diag_fill(sk, skb, cb, nlmsg_flags, net_admin); |
---|
417 | 499 | |
---|
418 | | - return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq, |
---|
419 | | - nlmsg_flags, unlh, net_admin); |
---|
| 500 | + return inet_sk_diag_fill(sk, inet_csk(sk), skb, cb, r, nlmsg_flags, |
---|
| 501 | + net_admin); |
---|
420 | 502 | } |
---|
421 | 503 | |
---|
422 | 504 | struct sock *inet_diag_find_one_icsk(struct net *net, |
---|
.. | .. |
---|
464 | 546 | EXPORT_SYMBOL_GPL(inet_diag_find_one_icsk); |
---|
465 | 547 | |
---|
466 | 548 | int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, |
---|
467 | | - struct sk_buff *in_skb, |
---|
468 | | - const struct nlmsghdr *nlh, |
---|
| 549 | + struct netlink_callback *cb, |
---|
469 | 550 | const struct inet_diag_req_v2 *req) |
---|
470 | 551 | { |
---|
| 552 | + struct sk_buff *in_skb = cb->skb; |
---|
471 | 553 | bool net_admin = netlink_net_capable(in_skb, CAP_NET_ADMIN); |
---|
472 | 554 | struct net *net = sock_net(in_skb->sk); |
---|
473 | 555 | struct sk_buff *rep; |
---|
.. | .. |
---|
484 | 566 | goto out; |
---|
485 | 567 | } |
---|
486 | 568 | |
---|
487 | | - err = sk_diag_fill(sk, rep, req, |
---|
488 | | - sk_user_ns(NETLINK_CB(in_skb).sk), |
---|
489 | | - NETLINK_CB(in_skb).portid, |
---|
490 | | - nlh->nlmsg_seq, 0, nlh, net_admin); |
---|
| 569 | + err = sk_diag_fill(sk, rep, cb, req, 0, net_admin); |
---|
491 | 570 | if (err < 0) { |
---|
492 | 571 | WARN_ON(err == -EMSGSIZE); |
---|
493 | 572 | nlmsg_free(rep); |
---|
.. | .. |
---|
508 | 587 | |
---|
509 | 588 | static int inet_diag_cmd_exact(int cmd, struct sk_buff *in_skb, |
---|
510 | 589 | const struct nlmsghdr *nlh, |
---|
| 590 | + int hdrlen, |
---|
511 | 591 | const struct inet_diag_req_v2 *req) |
---|
512 | 592 | { |
---|
513 | 593 | const struct inet_diag_handler *handler; |
---|
514 | | - int err; |
---|
| 594 | + struct inet_diag_dump_data dump_data; |
---|
| 595 | + int err, protocol; |
---|
515 | 596 | |
---|
516 | | - handler = inet_diag_lock_handler(req->sdiag_protocol); |
---|
517 | | - if (IS_ERR(handler)) |
---|
| 597 | + memset(&dump_data, 0, sizeof(dump_data)); |
---|
| 598 | + err = inet_diag_parse_attrs(nlh, hdrlen, dump_data.req_nlas); |
---|
| 599 | + if (err) |
---|
| 600 | + return err; |
---|
| 601 | + |
---|
| 602 | + protocol = inet_diag_get_protocol(req, &dump_data); |
---|
| 603 | + |
---|
| 604 | + handler = inet_diag_lock_handler(protocol); |
---|
| 605 | + if (IS_ERR(handler)) { |
---|
518 | 606 | err = PTR_ERR(handler); |
---|
519 | | - else if (cmd == SOCK_DIAG_BY_FAMILY) |
---|
520 | | - err = handler->dump_one(in_skb, nlh, req); |
---|
521 | | - else if (cmd == SOCK_DESTROY && handler->destroy) |
---|
| 607 | + } else if (cmd == SOCK_DIAG_BY_FAMILY) { |
---|
| 608 | + struct netlink_callback cb = { |
---|
| 609 | + .nlh = nlh, |
---|
| 610 | + .skb = in_skb, |
---|
| 611 | + .data = &dump_data, |
---|
| 612 | + }; |
---|
| 613 | + err = handler->dump_one(&cb, req); |
---|
| 614 | + } else if (cmd == SOCK_DESTROY && handler->destroy) { |
---|
522 | 615 | err = handler->destroy(in_skb, req); |
---|
523 | | - else |
---|
| 616 | + } else { |
---|
524 | 617 | err = -EOPNOTSUPP; |
---|
| 618 | + } |
---|
525 | 619 | inet_diag_unlock_handler(handler); |
---|
526 | 620 | |
---|
527 | 621 | return err; |
---|
.. | .. |
---|
647 | 741 | yes = 0; |
---|
648 | 742 | break; |
---|
649 | 743 | } |
---|
| 744 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
---|
| 745 | + case INET_DIAG_BC_CGROUP_COND: { |
---|
| 746 | + u64 cgroup_id; |
---|
| 747 | + |
---|
| 748 | + cgroup_id = get_unaligned((const u64 *)(op + 1)); |
---|
| 749 | + if (cgroup_id != entry->cgroup_id) |
---|
| 750 | + yes = 0; |
---|
| 751 | + break; |
---|
| 752 | + } |
---|
| 753 | +#endif |
---|
650 | 754 | } |
---|
651 | 755 | |
---|
652 | 756 | if (yes) { |
---|
.. | .. |
---|
697 | 801 | entry.mark = inet_rsk(inet_reqsk(sk))->ir_mark; |
---|
698 | 802 | else |
---|
699 | 803 | entry.mark = 0; |
---|
| 804 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
---|
| 805 | + entry.cgroup_id = sk_fullsock(sk) ? |
---|
| 806 | + cgroup_id(sock_cgroup_ptr(&sk->sk_cgrp_data)) : 0; |
---|
| 807 | +#endif |
---|
700 | 808 | |
---|
701 | 809 | return inet_diag_bc_run(bc, &entry); |
---|
702 | 810 | } |
---|
.. | .. |
---|
786 | 894 | return len >= *min_len; |
---|
787 | 895 | } |
---|
788 | 896 | |
---|
| 897 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
---|
| 898 | +static bool valid_cgroupcond(const struct inet_diag_bc_op *op, int len, |
---|
| 899 | + int *min_len) |
---|
| 900 | +{ |
---|
| 901 | + *min_len += sizeof(u64); |
---|
| 902 | + return len >= *min_len; |
---|
| 903 | +} |
---|
| 904 | +#endif |
---|
| 905 | + |
---|
789 | 906 | static int inet_diag_bc_audit(const struct nlattr *attr, |
---|
790 | 907 | const struct sk_buff *skb) |
---|
791 | 908 | { |
---|
.. | .. |
---|
828 | 945 | if (!valid_markcond(bc, len, &min_len)) |
---|
829 | 946 | return -EINVAL; |
---|
830 | 947 | break; |
---|
| 948 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
---|
| 949 | + case INET_DIAG_BC_CGROUP_COND: |
---|
| 950 | + if (!valid_cgroupcond(bc, len, &min_len)) |
---|
| 951 | + return -EINVAL; |
---|
| 952 | + break; |
---|
| 953 | +#endif |
---|
831 | 954 | case INET_DIAG_BC_AUTO: |
---|
832 | 955 | case INET_DIAG_BC_JMP: |
---|
833 | 956 | case INET_DIAG_BC_NOP: |
---|
.. | .. |
---|
850 | 973 | len -= op->yes; |
---|
851 | 974 | } |
---|
852 | 975 | return len == 0 ? 0 : -EINVAL; |
---|
853 | | -} |
---|
854 | | - |
---|
855 | | -static int inet_csk_diag_dump(struct sock *sk, |
---|
856 | | - struct sk_buff *skb, |
---|
857 | | - struct netlink_callback *cb, |
---|
858 | | - const struct inet_diag_req_v2 *r, |
---|
859 | | - const struct nlattr *bc, |
---|
860 | | - bool net_admin) |
---|
861 | | -{ |
---|
862 | | - if (!inet_diag_bc_sk(bc, sk)) |
---|
863 | | - return 0; |
---|
864 | | - |
---|
865 | | - return inet_csk_diag_fill(sk, skb, r, |
---|
866 | | - sk_user_ns(NETLINK_CB(cb->skb).sk), |
---|
867 | | - NETLINK_CB(cb->skb).portid, |
---|
868 | | - cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, |
---|
869 | | - net_admin); |
---|
870 | 976 | } |
---|
871 | 977 | |
---|
872 | 978 | static void twsk_build_assert(void) |
---|
.. | .. |
---|
897 | 1003 | |
---|
898 | 1004 | void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, |
---|
899 | 1005 | struct netlink_callback *cb, |
---|
900 | | - const struct inet_diag_req_v2 *r, struct nlattr *bc) |
---|
| 1006 | + const struct inet_diag_req_v2 *r) |
---|
901 | 1007 | { |
---|
902 | 1008 | bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); |
---|
| 1009 | + struct inet_diag_dump_data *cb_data = cb->data; |
---|
903 | 1010 | struct net *net = sock_net(skb->sk); |
---|
904 | 1011 | u32 idiag_states = r->idiag_states; |
---|
905 | 1012 | int i, num, s_i, s_num; |
---|
| 1013 | + struct nlattr *bc; |
---|
906 | 1014 | struct sock *sk; |
---|
907 | 1015 | |
---|
| 1016 | + bc = cb_data->inet_diag_nla_bc; |
---|
908 | 1017 | if (idiag_states & TCPF_SYN_RECV) |
---|
909 | 1018 | idiag_states |= TCPF_NEW_SYN_RECV; |
---|
910 | 1019 | s_i = cb->args[1]; |
---|
.. | .. |
---|
940 | 1049 | r->id.idiag_sport) |
---|
941 | 1050 | goto next_listen; |
---|
942 | 1051 | |
---|
943 | | - if (inet_csk_diag_dump(sk, skb, cb, r, |
---|
944 | | - bc, net_admin) < 0) { |
---|
| 1052 | + if (!inet_diag_bc_sk(bc, sk)) |
---|
| 1053 | + goto next_listen; |
---|
| 1054 | + |
---|
| 1055 | + if (inet_sk_diag_fill(sk, inet_csk(sk), skb, |
---|
| 1056 | + cb, r, NLM_F_MULTI, |
---|
| 1057 | + net_admin) < 0) { |
---|
945 | 1058 | spin_unlock(&ilb->lock); |
---|
946 | 1059 | goto done; |
---|
947 | 1060 | } |
---|
.. | .. |
---|
1019 | 1132 | res = 0; |
---|
1020 | 1133 | for (idx = 0; idx < accum; idx++) { |
---|
1021 | 1134 | if (res >= 0) { |
---|
1022 | | - res = sk_diag_fill(sk_arr[idx], skb, r, |
---|
1023 | | - sk_user_ns(NETLINK_CB(cb->skb).sk), |
---|
1024 | | - NETLINK_CB(cb->skb).portid, |
---|
1025 | | - cb->nlh->nlmsg_seq, NLM_F_MULTI, |
---|
1026 | | - cb->nlh, net_admin); |
---|
| 1135 | + res = sk_diag_fill(sk_arr[idx], skb, cb, r, |
---|
| 1136 | + NLM_F_MULTI, net_admin); |
---|
1027 | 1137 | if (res < 0) |
---|
1028 | 1138 | num = num_arr[idx]; |
---|
1029 | 1139 | } |
---|
.. | .. |
---|
1047 | 1157 | EXPORT_SYMBOL_GPL(inet_diag_dump_icsk); |
---|
1048 | 1158 | |
---|
1049 | 1159 | static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, |
---|
1050 | | - const struct inet_diag_req_v2 *r, |
---|
1051 | | - struct nlattr *bc) |
---|
| 1160 | + const struct inet_diag_req_v2 *r) |
---|
1052 | 1161 | { |
---|
| 1162 | + struct inet_diag_dump_data *cb_data = cb->data; |
---|
1053 | 1163 | const struct inet_diag_handler *handler; |
---|
1054 | | - int err = 0; |
---|
| 1164 | + u32 prev_min_dump_alloc; |
---|
| 1165 | + int protocol, err = 0; |
---|
1055 | 1166 | |
---|
1056 | | - handler = inet_diag_lock_handler(r->sdiag_protocol); |
---|
| 1167 | + protocol = inet_diag_get_protocol(r, cb_data); |
---|
| 1168 | + |
---|
| 1169 | +again: |
---|
| 1170 | + prev_min_dump_alloc = cb->min_dump_alloc; |
---|
| 1171 | + handler = inet_diag_lock_handler(protocol); |
---|
1057 | 1172 | if (!IS_ERR(handler)) |
---|
1058 | | - handler->dump(skb, cb, r, bc); |
---|
| 1173 | + handler->dump(skb, cb, r); |
---|
1059 | 1174 | else |
---|
1060 | 1175 | err = PTR_ERR(handler); |
---|
1061 | 1176 | inet_diag_unlock_handler(handler); |
---|
| 1177 | + |
---|
| 1178 | + /* The skb is not large enough to fit one sk info and |
---|
| 1179 | + * inet_sk_diag_fill() has requested for a larger skb. |
---|
| 1180 | + */ |
---|
| 1181 | + if (!skb->len && cb->min_dump_alloc > prev_min_dump_alloc) { |
---|
| 1182 | + err = pskb_expand_head(skb, 0, cb->min_dump_alloc, GFP_KERNEL); |
---|
| 1183 | + if (!err) |
---|
| 1184 | + goto again; |
---|
| 1185 | + } |
---|
1062 | 1186 | |
---|
1063 | 1187 | return err ? : skb->len; |
---|
1064 | 1188 | } |
---|
1065 | 1189 | |
---|
1066 | 1190 | static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) |
---|
1067 | 1191 | { |
---|
1068 | | - int hdrlen = sizeof(struct inet_diag_req_v2); |
---|
1069 | | - struct nlattr *bc = NULL; |
---|
| 1192 | + return __inet_diag_dump(skb, cb, nlmsg_data(cb->nlh)); |
---|
| 1193 | +} |
---|
1070 | 1194 | |
---|
1071 | | - if (nlmsg_attrlen(cb->nlh, hdrlen)) |
---|
1072 | | - bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE); |
---|
| 1195 | +static int __inet_diag_dump_start(struct netlink_callback *cb, int hdrlen) |
---|
| 1196 | +{ |
---|
| 1197 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
| 1198 | + struct inet_diag_dump_data *cb_data; |
---|
| 1199 | + struct sk_buff *skb = cb->skb; |
---|
| 1200 | + struct nlattr *nla; |
---|
| 1201 | + int err; |
---|
1073 | 1202 | |
---|
1074 | | - return __inet_diag_dump(skb, cb, nlmsg_data(cb->nlh), bc); |
---|
| 1203 | + cb_data = kzalloc(sizeof(*cb_data), GFP_KERNEL); |
---|
| 1204 | + if (!cb_data) |
---|
| 1205 | + return -ENOMEM; |
---|
| 1206 | + |
---|
| 1207 | + err = inet_diag_parse_attrs(nlh, hdrlen, cb_data->req_nlas); |
---|
| 1208 | + if (err) { |
---|
| 1209 | + kfree(cb_data); |
---|
| 1210 | + return err; |
---|
| 1211 | + } |
---|
| 1212 | + nla = cb_data->inet_diag_nla_bc; |
---|
| 1213 | + if (nla) { |
---|
| 1214 | + err = inet_diag_bc_audit(nla, skb); |
---|
| 1215 | + if (err) { |
---|
| 1216 | + kfree(cb_data); |
---|
| 1217 | + return err; |
---|
| 1218 | + } |
---|
| 1219 | + } |
---|
| 1220 | + |
---|
| 1221 | + nla = cb_data->inet_diag_nla_bpf_stgs; |
---|
| 1222 | + if (nla) { |
---|
| 1223 | + struct bpf_sk_storage_diag *bpf_stg_diag; |
---|
| 1224 | + |
---|
| 1225 | + bpf_stg_diag = bpf_sk_storage_diag_alloc(nla); |
---|
| 1226 | + if (IS_ERR(bpf_stg_diag)) { |
---|
| 1227 | + kfree(cb_data); |
---|
| 1228 | + return PTR_ERR(bpf_stg_diag); |
---|
| 1229 | + } |
---|
| 1230 | + cb_data->bpf_stg_diag = bpf_stg_diag; |
---|
| 1231 | + } |
---|
| 1232 | + |
---|
| 1233 | + cb->data = cb_data; |
---|
| 1234 | + return 0; |
---|
| 1235 | +} |
---|
| 1236 | + |
---|
| 1237 | +static int inet_diag_dump_start(struct netlink_callback *cb) |
---|
| 1238 | +{ |
---|
| 1239 | + return __inet_diag_dump_start(cb, sizeof(struct inet_diag_req_v2)); |
---|
| 1240 | +} |
---|
| 1241 | + |
---|
| 1242 | +static int inet_diag_dump_start_compat(struct netlink_callback *cb) |
---|
| 1243 | +{ |
---|
| 1244 | + return __inet_diag_dump_start(cb, sizeof(struct inet_diag_req)); |
---|
| 1245 | +} |
---|
| 1246 | + |
---|
| 1247 | +static int inet_diag_dump_done(struct netlink_callback *cb) |
---|
| 1248 | +{ |
---|
| 1249 | + struct inet_diag_dump_data *cb_data = cb->data; |
---|
| 1250 | + |
---|
| 1251 | + bpf_sk_storage_diag_free(cb_data->bpf_stg_diag); |
---|
| 1252 | + kfree(cb->data); |
---|
| 1253 | + |
---|
| 1254 | + return 0; |
---|
1075 | 1255 | } |
---|
1076 | 1256 | |
---|
1077 | 1257 | static int inet_diag_type2proto(int type) |
---|
.. | .. |
---|
1090 | 1270 | struct netlink_callback *cb) |
---|
1091 | 1271 | { |
---|
1092 | 1272 | struct inet_diag_req *rc = nlmsg_data(cb->nlh); |
---|
1093 | | - int hdrlen = sizeof(struct inet_diag_req); |
---|
1094 | 1273 | struct inet_diag_req_v2 req; |
---|
1095 | | - struct nlattr *bc = NULL; |
---|
1096 | 1274 | |
---|
1097 | 1275 | req.sdiag_family = AF_UNSPEC; /* compatibility */ |
---|
1098 | 1276 | req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type); |
---|
.. | .. |
---|
1100 | 1278 | req.idiag_states = rc->idiag_states; |
---|
1101 | 1279 | req.id = rc->id; |
---|
1102 | 1280 | |
---|
1103 | | - if (nlmsg_attrlen(cb->nlh, hdrlen)) |
---|
1104 | | - bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE); |
---|
1105 | | - |
---|
1106 | | - return __inet_diag_dump(skb, cb, &req, bc); |
---|
| 1281 | + return __inet_diag_dump(skb, cb, &req); |
---|
1107 | 1282 | } |
---|
1108 | 1283 | |
---|
1109 | 1284 | static int inet_diag_get_exact_compat(struct sk_buff *in_skb, |
---|
.. | .. |
---|
1118 | 1293 | req.idiag_states = rc->idiag_states; |
---|
1119 | 1294 | req.id = rc->id; |
---|
1120 | 1295 | |
---|
1121 | | - return inet_diag_cmd_exact(SOCK_DIAG_BY_FAMILY, in_skb, nlh, &req); |
---|
| 1296 | + return inet_diag_cmd_exact(SOCK_DIAG_BY_FAMILY, in_skb, nlh, |
---|
| 1297 | + sizeof(struct inet_diag_req), &req); |
---|
1122 | 1298 | } |
---|
1123 | 1299 | |
---|
1124 | 1300 | static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) |
---|
.. | .. |
---|
1131 | 1307 | return -EINVAL; |
---|
1132 | 1308 | |
---|
1133 | 1309 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
---|
1134 | | - if (nlmsg_attrlen(nlh, hdrlen)) { |
---|
1135 | | - struct nlattr *attr; |
---|
1136 | | - int err; |
---|
1137 | | - |
---|
1138 | | - attr = nlmsg_find_attr(nlh, hdrlen, |
---|
1139 | | - INET_DIAG_REQ_BYTECODE); |
---|
1140 | | - err = inet_diag_bc_audit(attr, skb); |
---|
1141 | | - if (err) |
---|
1142 | | - return err; |
---|
1143 | | - } |
---|
1144 | | - { |
---|
1145 | | - struct netlink_dump_control c = { |
---|
1146 | | - .dump = inet_diag_dump_compat, |
---|
1147 | | - }; |
---|
1148 | | - return netlink_dump_start(net->diag_nlsk, skb, nlh, &c); |
---|
1149 | | - } |
---|
| 1310 | + struct netlink_dump_control c = { |
---|
| 1311 | + .start = inet_diag_dump_start_compat, |
---|
| 1312 | + .done = inet_diag_dump_done, |
---|
| 1313 | + .dump = inet_diag_dump_compat, |
---|
| 1314 | + }; |
---|
| 1315 | + return netlink_dump_start(net->diag_nlsk, skb, nlh, &c); |
---|
1150 | 1316 | } |
---|
1151 | 1317 | |
---|
1152 | 1318 | return inet_diag_get_exact_compat(skb, nlh); |
---|
.. | .. |
---|
1162 | 1328 | |
---|
1163 | 1329 | if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY && |
---|
1164 | 1330 | h->nlmsg_flags & NLM_F_DUMP) { |
---|
1165 | | - if (nlmsg_attrlen(h, hdrlen)) { |
---|
1166 | | - struct nlattr *attr; |
---|
1167 | | - int err; |
---|
1168 | | - |
---|
1169 | | - attr = nlmsg_find_attr(h, hdrlen, |
---|
1170 | | - INET_DIAG_REQ_BYTECODE); |
---|
1171 | | - err = inet_diag_bc_audit(attr, skb); |
---|
1172 | | - if (err) |
---|
1173 | | - return err; |
---|
1174 | | - } |
---|
1175 | | - { |
---|
1176 | | - struct netlink_dump_control c = { |
---|
1177 | | - .dump = inet_diag_dump, |
---|
1178 | | - }; |
---|
1179 | | - return netlink_dump_start(net->diag_nlsk, skb, h, &c); |
---|
1180 | | - } |
---|
| 1331 | + struct netlink_dump_control c = { |
---|
| 1332 | + .start = inet_diag_dump_start, |
---|
| 1333 | + .done = inet_diag_dump_done, |
---|
| 1334 | + .dump = inet_diag_dump, |
---|
| 1335 | + }; |
---|
| 1336 | + return netlink_dump_start(net->diag_nlsk, skb, h, &c); |
---|
1181 | 1337 | } |
---|
1182 | 1338 | |
---|
1183 | | - return inet_diag_cmd_exact(h->nlmsg_type, skb, h, nlmsg_data(h)); |
---|
| 1339 | + return inet_diag_cmd_exact(h->nlmsg_type, skb, h, hdrlen, |
---|
| 1340 | + nlmsg_data(h)); |
---|
1184 | 1341 | } |
---|
1185 | 1342 | |
---|
1186 | 1343 | static |
---|
.. | .. |
---|
1315 | 1472 | kfree(inet_diag_table); |
---|
1316 | 1473 | } |
---|
1317 | 1474 | |
---|
1318 | | -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT |
---|
1319 | | -rootfs_initcall(inet_diag_init); |
---|
1320 | | -#else |
---|
1321 | 1475 | module_init(inet_diag_init); |
---|
1322 | | -#endif |
---|
1323 | 1476 | module_exit(inet_diag_exit); |
---|
1324 | 1477 | MODULE_LICENSE("GPL"); |
---|
1325 | 1478 | MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2 /* AF_INET */); |
---|