LCOV - code coverage report
Current view: top level - net/ipv4 - inet_diag.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 443 0.0 %
Date: 2014-04-07 Functions: 0 26 0.0 %
Branches: 0 368 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * inet_diag.c  Module for monitoring INET transport protocols sockets.
       3                 :            :  *
       4                 :            :  * 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                 :            :  */
      11                 :            : 
      12                 :            : #include <linux/kernel.h>
      13                 :            : #include <linux/module.h>
      14                 :            : #include <linux/types.h>
      15                 :            : #include <linux/fcntl.h>
      16                 :            : #include <linux/random.h>
      17                 :            : #include <linux/slab.h>
      18                 :            : #include <linux/cache.h>
      19                 :            : #include <linux/init.h>
      20                 :            : #include <linux/time.h>
      21                 :            : 
      22                 :            : #include <net/icmp.h>
      23                 :            : #include <net/tcp.h>
      24                 :            : #include <net/ipv6.h>
      25                 :            : #include <net/inet_common.h>
      26                 :            : #include <net/inet_connection_sock.h>
      27                 :            : #include <net/inet_hashtables.h>
      28                 :            : #include <net/inet_timewait_sock.h>
      29                 :            : #include <net/inet6_hashtables.h>
      30                 :            : #include <net/netlink.h>
      31                 :            : 
      32                 :            : #include <linux/inet.h>
      33                 :            : #include <linux/stddef.h>
      34                 :            : 
      35                 :            : #include <linux/inet_diag.h>
      36                 :            : #include <linux/sock_diag.h>
      37                 :            : 
      38                 :            : static const struct inet_diag_handler **inet_diag_table;
      39                 :            : 
      40                 :            : struct inet_diag_entry {
      41                 :            :         __be32 *saddr;
      42                 :            :         __be32 *daddr;
      43                 :            :         u16 sport;
      44                 :            :         u16 dport;
      45                 :            :         u16 family;
      46                 :            :         u16 userlocks;
      47                 :            : #if IS_ENABLED(CONFIG_IPV6)
      48                 :            :         struct in6_addr saddr_storage;  /* for IPv4-mapped-IPv6 addresses */
      49                 :            :         struct in6_addr daddr_storage;  /* for IPv4-mapped-IPv6 addresses */
      50                 :            : #endif
      51                 :            : };
      52                 :            : 
      53                 :            : static DEFINE_MUTEX(inet_diag_table_mutex);
      54                 :            : 
      55                 :          0 : static const struct inet_diag_handler *inet_diag_lock_handler(int proto)
      56                 :            : {
      57         [ #  # ]:          0 :         if (!inet_diag_table[proto])
      58                 :          0 :                 request_module("net-pf-%d-proto-%d-type-%d-%d", PF_NETLINK,
      59                 :            :                                NETLINK_SOCK_DIAG, AF_INET, proto);
      60                 :            : 
      61                 :          0 :         mutex_lock(&inet_diag_table_mutex);
      62         [ #  # ]:          0 :         if (!inet_diag_table[proto])
      63                 :            :                 return ERR_PTR(-ENOENT);
      64                 :            : 
      65                 :          0 :         return inet_diag_table[proto];
      66                 :            : }
      67                 :            : 
      68                 :            : static inline void inet_diag_unlock_handler(
      69                 :            :         const struct inet_diag_handler *handler)
      70                 :            : {
      71                 :          0 :         mutex_unlock(&inet_diag_table_mutex);
      72                 :            : }
      73                 :            : 
      74                 :          0 : int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
      75                 :            :                               struct sk_buff *skb, struct inet_diag_req_v2 *req,
      76                 :            :                               struct user_namespace *user_ns,                   
      77                 :            :                               u32 portid, u32 seq, u16 nlmsg_flags,
      78                 :            :                               const struct nlmsghdr *unlh)
      79                 :            : {
      80                 :            :         const struct inet_sock *inet = inet_sk(sk);
      81                 :            :         struct inet_diag_msg *r;
      82                 :            :         struct nlmsghdr  *nlh;
      83                 :            :         struct nlattr *attr;
      84                 :            :         void *info = NULL;
      85                 :            :         const struct inet_diag_handler *handler;
      86                 :          0 :         int ext = req->idiag_ext;
      87                 :            : 
      88                 :          0 :         handler = inet_diag_table[req->sdiag_protocol];
      89         [ #  # ]:          0 :         BUG_ON(handler == NULL);
      90                 :            : 
      91                 :          0 :         nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r),
      92                 :            :                         nlmsg_flags);
      93         [ #  # ]:          0 :         if (!nlh)
      94                 :            :                 return -EMSGSIZE;
      95                 :            : 
      96                 :          0 :         r = nlmsg_data(nlh);
      97         [ #  # ]:          0 :         BUG_ON(sk->sk_state == TCP_TIME_WAIT);
      98                 :            : 
      99                 :          0 :         r->idiag_family = sk->sk_family;
     100                 :          0 :         r->idiag_state = sk->sk_state;
     101                 :          0 :         r->idiag_timer = 0;
     102                 :          0 :         r->idiag_retrans = 0;
     103                 :            : 
     104                 :          0 :         r->id.idiag_if = sk->sk_bound_dev_if;
     105                 :          0 :         sock_diag_save_cookie(sk, r->id.idiag_cookie);
     106                 :            : 
     107                 :          0 :         r->id.idiag_sport = inet->inet_sport;
     108                 :          0 :         r->id.idiag_dport = inet->inet_dport;
     109                 :            : 
     110                 :          0 :         memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src));
     111                 :          0 :         memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst));
     112                 :            : 
     113                 :          0 :         r->id.idiag_src[0] = inet->inet_rcv_saddr;
     114                 :          0 :         r->id.idiag_dst[0] = inet->inet_daddr;
     115                 :            : 
     116         [ #  # ]:          0 :         if (nla_put_u8(skb, INET_DIAG_SHUTDOWN, sk->sk_shutdown))
     117                 :            :                 goto errout;
     118                 :            : 
     119                 :            :         /* IPv6 dual-stack sockets use inet->tos for IPv4 connections,
     120                 :            :          * hence this needs to be included regardless of socket family.
     121                 :            :          */
     122         [ #  # ]:          0 :         if (ext & (1 << (INET_DIAG_TOS - 1)))
     123         [ #  # ]:          0 :                 if (nla_put_u8(skb, INET_DIAG_TOS, inet->tos) < 0)
     124                 :            :                         goto errout;
     125                 :            : 
     126                 :            : #if IS_ENABLED(CONFIG_IPV6)
     127         [ #  # ]:          0 :         if (r->idiag_family == AF_INET6) {
     128                 :            : 
     129                 :          0 :                 *(struct in6_addr *)r->id.idiag_src = sk->sk_v6_rcv_saddr;
     130                 :          0 :                 *(struct in6_addr *)r->id.idiag_dst = sk->sk_v6_daddr;
     131                 :            : 
     132         [ #  # ]:          0 :                 if (ext & (1 << (INET_DIAG_TCLASS - 1)))
     133         [ #  # ]:          0 :                         if (nla_put_u8(skb, INET_DIAG_TCLASS,
     134                 :            :                                        inet6_sk(sk)->tclass) < 0)
     135                 :            :                                 goto errout;
     136                 :            :         }
     137                 :            : #endif
     138                 :            : 
     139                 :          0 :         r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk));
     140                 :          0 :         r->idiag_inode = sock_i_ino(sk);
     141                 :            : 
     142         [ #  # ]:          0 :         if (ext & (1 << (INET_DIAG_MEMINFO - 1))) {
     143                 :          0 :                 struct inet_diag_meminfo minfo = {
     144                 :            :                         .idiag_rmem = sk_rmem_alloc_get(sk),
     145                 :          0 :                         .idiag_wmem = sk->sk_wmem_queued,
     146                 :          0 :                         .idiag_fmem = sk->sk_forward_alloc,
     147                 :            :                         .idiag_tmem = sk_wmem_alloc_get(sk),
     148                 :            :                 };
     149                 :            : 
     150         [ #  # ]:          0 :                 if (nla_put(skb, INET_DIAG_MEMINFO, sizeof(minfo), &minfo) < 0)
     151                 :            :                         goto errout;
     152                 :            :         }
     153                 :            : 
     154         [ #  # ]:          0 :         if (ext & (1 << (INET_DIAG_SKMEMINFO - 1)))
     155         [ #  # ]:          0 :                 if (sock_diag_put_meminfo(sk, skb, INET_DIAG_SKMEMINFO))
     156                 :            :                         goto errout;
     157                 :            : 
     158         [ #  # ]:          0 :         if (icsk == NULL) {
     159                 :          0 :                 handler->idiag_get_info(sk, r, NULL);
     160                 :          0 :                 goto out;
     161                 :            :         }
     162                 :            : 
     163                 :            : #define EXPIRES_IN_MS(tmo)  DIV_ROUND_UP((tmo - jiffies) * 1000, HZ)
     164                 :            : 
     165         [ #  # ]:          0 :         if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
     166         [ #  # ]:          0 :             icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
     167                 :            :             icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
     168                 :          0 :                 r->idiag_timer = 1;
     169                 :          0 :                 r->idiag_retrans = icsk->icsk_retransmits;
     170                 :          0 :                 r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
     171         [ #  # ]:          0 :         } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
     172                 :          0 :                 r->idiag_timer = 4;
     173                 :          0 :                 r->idiag_retrans = icsk->icsk_probes_out;
     174                 :          0 :                 r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
     175         [ #  # ]:          0 :         } else if (timer_pending(&sk->sk_timer)) {
     176                 :          0 :                 r->idiag_timer = 2;
     177                 :          0 :                 r->idiag_retrans = icsk->icsk_probes_out;
     178                 :          0 :                 r->idiag_expires = EXPIRES_IN_MS(sk->sk_timer.expires);
     179                 :            :         } else {
     180                 :          0 :                 r->idiag_timer = 0;
     181                 :          0 :                 r->idiag_expires = 0;
     182                 :            :         }
     183                 :            : #undef EXPIRES_IN_MS
     184                 :            : 
     185         [ #  # ]:          0 :         if (ext & (1 << (INET_DIAG_INFO - 1))) {
     186                 :          0 :                 attr = nla_reserve(skb, INET_DIAG_INFO,
     187                 :            :                                    sizeof(struct tcp_info));
     188         [ #  # ]:          0 :                 if (!attr)
     189                 :            :                         goto errout;
     190                 :            : 
     191                 :          0 :                 info = nla_data(attr);
     192                 :            :         }
     193                 :            : 
     194 [ #  # ][ #  # ]:          0 :         if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops)
     195         [ #  # ]:          0 :                 if (nla_put_string(skb, INET_DIAG_CONG,
     196                 :          0 :                                    icsk->icsk_ca_ops->name) < 0)
     197                 :            :                         goto errout;
     198                 :            : 
     199                 :          0 :         handler->idiag_get_info(sk, r, info);
     200                 :            : 
     201 [ #  # ][ #  # ]:          0 :         if (sk->sk_state < TCP_TIME_WAIT &&
     202         [ #  # ]:          0 :             icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info)
     203                 :          0 :                 icsk->icsk_ca_ops->get_info(sk, ext, skb);
     204                 :            : 
     205                 :            : out:
     206                 :          0 :         return nlmsg_end(skb, nlh);
     207                 :            : 
     208                 :            : errout:
     209                 :            :         nlmsg_cancel(skb, nlh);
     210                 :            :         return -EMSGSIZE;
     211                 :            : }
     212                 :            : EXPORT_SYMBOL_GPL(inet_sk_diag_fill);
     213                 :            : 
     214                 :            : static int inet_csk_diag_fill(struct sock *sk,
     215                 :            :                               struct sk_buff *skb, struct inet_diag_req_v2 *req,
     216                 :            :                               struct user_namespace *user_ns,
     217                 :            :                               u32 portid, u32 seq, u16 nlmsg_flags,
     218                 :            :                               const struct nlmsghdr *unlh)
     219                 :            : {
     220                 :          0 :         return inet_sk_diag_fill(sk, inet_csk(sk),
     221                 :            :                         skb, req, user_ns, portid, seq, nlmsg_flags, unlh);
     222                 :            : }
     223                 :            : 
     224                 :          0 : static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
     225                 :            :                                struct sk_buff *skb, struct inet_diag_req_v2 *req,
     226                 :            :                                u32 portid, u32 seq, u16 nlmsg_flags,
     227                 :            :                                const struct nlmsghdr *unlh)
     228                 :            : {
     229                 :            :         s32 tmo;
     230                 :            :         struct inet_diag_msg *r;
     231                 :            :         struct nlmsghdr *nlh;
     232                 :            : 
     233                 :          0 :         nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r),
     234                 :            :                         nlmsg_flags);
     235         [ #  # ]:          0 :         if (!nlh)
     236                 :            :                 return -EMSGSIZE;
     237                 :            : 
     238                 :            :         r = nlmsg_data(nlh);
     239         [ #  # ]:          0 :         BUG_ON(tw->tw_state != TCP_TIME_WAIT);
     240                 :            : 
     241                 :          0 :         tmo = tw->tw_ttd - inet_tw_time_stamp();
     242         [ #  # ]:          0 :         if (tmo < 0)
     243                 :            :                 tmo = 0;
     244                 :            : 
     245                 :          0 :         r->idiag_family            = tw->tw_family;
     246                 :          0 :         r->idiag_retrans      = 0;
     247                 :            : 
     248                 :          0 :         r->id.idiag_if             = tw->tw_bound_dev_if;
     249                 :          0 :         sock_diag_save_cookie(tw, r->id.idiag_cookie);
     250                 :            : 
     251                 :          0 :         r->id.idiag_sport     = tw->tw_sport;
     252                 :          0 :         r->id.idiag_dport     = tw->tw_dport;
     253                 :            : 
     254                 :          0 :         memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src));
     255                 :          0 :         memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst));
     256                 :            : 
     257                 :          0 :         r->id.idiag_src[0]    = tw->tw_rcv_saddr;
     258                 :          0 :         r->id.idiag_dst[0]    = tw->tw_daddr;
     259                 :            : 
     260                 :          0 :         r->idiag_state             = tw->tw_substate;
     261                 :          0 :         r->idiag_timer             = 3;
     262                 :          0 :         r->idiag_expires      = jiffies_to_msecs(tmo);
     263                 :          0 :         r->idiag_rqueue            = 0;
     264                 :          0 :         r->idiag_wqueue            = 0;
     265                 :          0 :         r->idiag_uid       = 0;
     266                 :          0 :         r->idiag_inode             = 0;
     267                 :            : #if IS_ENABLED(CONFIG_IPV6)
     268         [ #  # ]:          0 :         if (tw->tw_family == AF_INET6) {
     269                 :          0 :                 *(struct in6_addr *)r->id.idiag_src = tw->tw_v6_rcv_saddr;
     270                 :          0 :                 *(struct in6_addr *)r->id.idiag_dst = tw->tw_v6_daddr;
     271                 :            :         }
     272                 :            : #endif
     273                 :            : 
     274                 :            :         return nlmsg_end(skb, nlh);
     275                 :            : }
     276                 :            : 
     277                 :          0 : static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
     278                 :            :                         struct inet_diag_req_v2 *r,
     279                 :            :                         struct user_namespace *user_ns,
     280                 :            :                         u32 portid, u32 seq, u16 nlmsg_flags,
     281                 :          0 :                         const struct nlmsghdr *unlh)
     282                 :            : {
     283         [ #  # ]:          0 :         if (sk->sk_state == TCP_TIME_WAIT)
     284                 :          0 :                 return inet_twsk_diag_fill(inet_twsk(sk), skb, r, portid, seq,
     285                 :            :                                            nlmsg_flags, unlh);
     286                 :            : 
     287                 :          0 :         return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq,
     288                 :            :                                   nlmsg_flags, unlh);
     289                 :            : }
     290                 :            : 
     291                 :          0 : int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_skb,
     292                 :            :                 const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req)
     293                 :            : {
     294                 :            :         int err;
     295                 :            :         struct sock *sk;
     296                 :            :         struct sk_buff *rep;
     297                 :            :         struct net *net = sock_net(in_skb->sk);
     298                 :            : 
     299                 :            :         err = -EINVAL;
     300         [ #  # ]:          0 :         if (req->sdiag_family == AF_INET) {
     301                 :          0 :                 sk = inet_lookup(net, hashinfo, req->id.idiag_dst[0],
     302                 :            :                                  req->id.idiag_dport, req->id.idiag_src[0],
     303                 :          0 :                                  req->id.idiag_sport, req->id.idiag_if);
     304                 :            :         }
     305                 :            : #if IS_ENABLED(CONFIG_IPV6)
     306         [ #  # ]:          0 :         else if (req->sdiag_family == AF_INET6) {
     307                 :          0 :                 sk = inet6_lookup(net, hashinfo,
     308                 :          0 :                                   (struct in6_addr *)req->id.idiag_dst,
     309                 :            :                                   req->id.idiag_dport,
     310                 :          0 :                                   (struct in6_addr *)req->id.idiag_src,
     311                 :            :                                   req->id.idiag_sport,
     312                 :          0 :                                   req->id.idiag_if);
     313                 :            :         }
     314                 :            : #endif
     315                 :            :         else {
     316                 :            :                 goto out_nosk;
     317                 :            :         }
     318                 :            : 
     319                 :            :         err = -ENOENT;
     320         [ #  # ]:          0 :         if (sk == NULL)
     321                 :            :                 goto out_nosk;
     322                 :            : 
     323                 :          0 :         err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
     324         [ #  # ]:          0 :         if (err)
     325                 :            :                 goto out;
     326                 :            : 
     327                 :            :         rep = nlmsg_new(sizeof(struct inet_diag_msg) +
     328                 :            :                         sizeof(struct inet_diag_meminfo) +
     329                 :            :                         sizeof(struct tcp_info) + 64, GFP_KERNEL);
     330         [ #  # ]:          0 :         if (!rep) {
     331                 :            :                 err = -ENOMEM;
     332                 :            :                 goto out;
     333                 :            :         }
     334                 :            : 
     335                 :          0 :         err = sk_diag_fill(sk, rep, req,
     336                 :            :                            sk_user_ns(NETLINK_CB(in_skb).sk),
     337                 :            :                            NETLINK_CB(in_skb).portid,
     338                 :            :                            nlh->nlmsg_seq, 0, nlh);
     339         [ #  # ]:          0 :         if (err < 0) {
     340         [ #  # ]:          0 :                 WARN_ON(err == -EMSGSIZE);
     341                 :            :                 nlmsg_free(rep);
     342                 :            :                 goto out;
     343                 :            :         }
     344                 :          0 :         err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid,
     345                 :            :                               MSG_DONTWAIT);
     346         [ #  # ]:          0 :         if (err > 0)
     347                 :            :                 err = 0;
     348                 :            : 
     349                 :            : out:
     350         [ #  # ]:          0 :         if (sk)
     351                 :          0 :                 sock_gen_put(sk);
     352                 :            : 
     353                 :            : out_nosk:
     354                 :          0 :         return err;
     355                 :            : }
     356                 :            : EXPORT_SYMBOL_GPL(inet_diag_dump_one_icsk);
     357                 :            : 
     358                 :          0 : static int inet_diag_get_exact(struct sk_buff *in_skb,
     359                 :            :                                const struct nlmsghdr *nlh,
     360                 :            :                                struct inet_diag_req_v2 *req)
     361                 :            : {
     362                 :            :         const struct inet_diag_handler *handler;
     363                 :            :         int err;
     364                 :            : 
     365                 :          0 :         handler = inet_diag_lock_handler(req->sdiag_protocol);
     366         [ #  # ]:          0 :         if (IS_ERR(handler))
     367                 :            :                 err = PTR_ERR(handler);
     368                 :            :         else
     369                 :          0 :                 err = handler->dump_one(in_skb, nlh, req);
     370                 :            :         inet_diag_unlock_handler(handler);
     371                 :            : 
     372                 :          0 :         return err;
     373                 :            : }
     374                 :            : 
     375                 :          0 : static int bitstring_match(const __be32 *a1, const __be32 *a2, int bits)
     376                 :            : {
     377                 :          0 :         int words = bits >> 5;
     378                 :            : 
     379                 :          0 :         bits &= 0x1f;
     380                 :            : 
     381         [ #  # ]:          0 :         if (words) {
     382         [ #  # ]:          0 :                 if (memcmp(a1, a2, words << 2))
     383                 :            :                         return 0;
     384                 :            :         }
     385         [ #  # ]:          0 :         if (bits) {
     386                 :            :                 __be32 w1, w2;
     387                 :            :                 __be32 mask;
     388                 :            : 
     389                 :          0 :                 w1 = a1[words];
     390                 :          0 :                 w2 = a2[words];
     391                 :            : 
     392         [ #  # ]:          0 :                 mask = htonl((0xffffffff) << (32 - bits));
     393                 :            : 
     394         [ #  # ]:          0 :                 if ((w1 ^ w2) & mask)
     395                 :            :                         return 0;
     396                 :            :         }
     397                 :            : 
     398                 :          0 :         return 1;
     399                 :            : }
     400                 :            : 
     401                 :            : 
     402                 :          0 : static int inet_diag_bc_run(const struct nlattr *_bc,
     403                 :            :                 const struct inet_diag_entry *entry)
     404                 :            : {
     405                 :          0 :         const void *bc = nla_data(_bc);
     406                 :            :         int len = nla_len(_bc);
     407                 :            : 
     408         [ #  # ]:          0 :         while (len > 0) {
     409                 :            :                 int yes = 1;
     410                 :            :                 const struct inet_diag_bc_op *op = bc;
     411                 :            : 
     412   [ #  #  #  #  :          0 :                 switch (op->code) {
             #  #  #  # ]
     413                 :            :                 case INET_DIAG_BC_NOP:
     414                 :            :                         break;
     415                 :            :                 case INET_DIAG_BC_JMP:
     416                 :            :                         yes = 0;
     417                 :          0 :                         break;
     418                 :            :                 case INET_DIAG_BC_S_GE:
     419                 :          0 :                         yes = entry->sport >= op[1].no;
     420                 :          0 :                         break;
     421                 :            :                 case INET_DIAG_BC_S_LE:
     422                 :          0 :                         yes = entry->sport <= op[1].no;
     423                 :          0 :                         break;
     424                 :            :                 case INET_DIAG_BC_D_GE:
     425                 :          0 :                         yes = entry->dport >= op[1].no;
     426                 :          0 :                         break;
     427                 :            :                 case INET_DIAG_BC_D_LE:
     428                 :          0 :                         yes = entry->dport <= op[1].no;
     429                 :          0 :                         break;
     430                 :            :                 case INET_DIAG_BC_AUTO:
     431                 :          0 :                         yes = !(entry->userlocks & SOCK_BINDPORT_LOCK);
     432                 :          0 :                         break;
     433                 :            :                 case INET_DIAG_BC_S_COND:
     434                 :            :                 case INET_DIAG_BC_D_COND: {
     435                 :            :                         struct inet_diag_hostcond *cond;
     436                 :            :                         __be32 *addr;
     437                 :            : 
     438                 :            :                         cond = (struct inet_diag_hostcond *)(op + 1);
     439 [ #  # ][ #  # ]:          0 :                         if (cond->port != -1 &&
     440                 :            :                             cond->port != (op->code == INET_DIAG_BC_S_COND ?
     441         [ #  # ]:          0 :                                              entry->sport : entry->dport)) {
     442                 :            :                                 yes = 0;
     443                 :            :                                 break;
     444                 :            :                         }
     445                 :            : 
     446         [ #  # ]:          0 :                         if (op->code == INET_DIAG_BC_S_COND)
     447                 :          0 :                                 addr = entry->saddr;
     448                 :            :                         else
     449                 :          0 :                                 addr = entry->daddr;
     450                 :            : 
     451 [ #  # ][ #  # ]:          0 :                         if (cond->family != AF_UNSPEC &&
     452                 :          0 :                             cond->family != entry->family) {
     453 [ #  # ][ #  # ]:          0 :                                 if (entry->family == AF_INET6 &&
     454                 :            :                                     cond->family == AF_INET) {
     455 [ #  # ][ #  # ]:          0 :                                         if (addr[0] == 0 && addr[1] == 0 &&
                 [ #  # ]
     456         [ #  # ]:          0 :                                             addr[2] == htonl(0xffff) &&
     457                 :          0 :                                             bitstring_match(addr + 3,
     458                 :          0 :                                                             cond->addr,
     459                 :          0 :                                                             cond->prefix_len))
     460                 :            :                                                 break;
     461                 :            :                                 }
     462                 :            :                                 yes = 0;
     463                 :          0 :                                 break;
     464                 :            :                         }
     465                 :            : 
     466         [ #  # ]:          0 :                         if (cond->prefix_len == 0)
     467                 :            :                                 break;
     468         [ #  # ]:          0 :                         if (bitstring_match(addr, cond->addr,
     469                 :            :                                             cond->prefix_len))
     470                 :            :                                 break;
     471                 :            :                         yes = 0;
     472                 :          0 :                         break;
     473                 :            :                 }
     474                 :            :                 }
     475                 :            : 
     476         [ #  # ]:          0 :                 if (yes) {
     477                 :          0 :                         len -= op->yes;
     478                 :          0 :                         bc += op->yes;
     479                 :            :                 } else {
     480                 :          0 :                         len -= op->no;
     481                 :          0 :                         bc += op->no;
     482                 :            :                 }
     483                 :            :         }
     484                 :          0 :         return len == 0;
     485                 :            : }
     486                 :            : 
     487                 :          0 : int inet_diag_bc_sk(const struct nlattr *bc, struct sock *sk)
     488                 :            : {
     489                 :            :         struct inet_diag_entry entry;
     490                 :            :         struct inet_sock *inet = inet_sk(sk);
     491                 :            : 
     492         [ #  # ]:          0 :         if (bc == NULL)
     493                 :            :                 return 1;
     494                 :            : 
     495                 :          0 :         entry.family = sk->sk_family;
     496                 :            : #if IS_ENABLED(CONFIG_IPV6)
     497         [ #  # ]:          0 :         if (entry.family == AF_INET6) {
     498                 :            : 
     499                 :          0 :                 entry.saddr = sk->sk_v6_rcv_saddr.s6_addr32;
     500                 :          0 :                 entry.daddr = sk->sk_v6_daddr.s6_addr32;
     501                 :            :         } else
     502                 :            : #endif
     503                 :            :         {
     504                 :          0 :                 entry.saddr = &inet->inet_rcv_saddr;
     505                 :          0 :                 entry.daddr = &inet->inet_daddr;
     506                 :            :         }
     507                 :          0 :         entry.sport = inet->inet_num;
     508         [ #  # ]:          0 :         entry.dport = ntohs(inet->inet_dport);
     509                 :          0 :         entry.userlocks = sk->sk_userlocks;
     510                 :            : 
     511                 :          0 :         return inet_diag_bc_run(bc, &entry);
     512                 :            : }
     513                 :            : EXPORT_SYMBOL_GPL(inet_diag_bc_sk);
     514                 :            : 
     515                 :            : static int valid_cc(const void *bc, int len, int cc)
     516                 :            : {
     517         [ #  # ]:          0 :         while (len >= 0) {
     518                 :            :                 const struct inet_diag_bc_op *op = bc;
     519                 :            : 
     520         [ #  # ]:          0 :                 if (cc > len)
     521                 :            :                         return 0;
     522         [ #  # ]:          0 :                 if (cc == len)
     523                 :            :                         return 1;
     524 [ #  # ][ #  # ]:          0 :                 if (op->yes < 4 || op->yes & 3)
     525                 :            :                         return 0;
     526                 :          0 :                 len -= op->yes;
     527                 :          0 :                 bc  += op->yes;
     528                 :            :         }
     529                 :            :         return 0;
     530                 :            : }
     531                 :            : 
     532                 :            : /* Validate an inet_diag_hostcond. */
     533                 :          0 : static bool valid_hostcond(const struct inet_diag_bc_op *op, int len,
     534                 :            :                            int *min_len)
     535                 :            : {
     536                 :            :         int addr_len;
     537                 :            :         struct inet_diag_hostcond *cond;
     538                 :            : 
     539                 :            :         /* Check hostcond space. */
     540                 :          0 :         *min_len += sizeof(struct inet_diag_hostcond);
     541         [ #  # ]:          0 :         if (len < *min_len)
     542                 :            :                 return false;
     543                 :            :         cond = (struct inet_diag_hostcond *)(op + 1);
     544                 :            : 
     545                 :            :         /* Check address family and address length. */
     546   [ #  #  #  # ]:          0 :         switch (cond->family) {
     547                 :            :         case AF_UNSPEC:
     548                 :            :                 addr_len = 0;
     549                 :            :                 break;
     550                 :            :         case AF_INET:
     551                 :            :                 addr_len = sizeof(struct in_addr);
     552                 :          0 :                 break;
     553                 :            :         case AF_INET6:
     554                 :            :                 addr_len = sizeof(struct in6_addr);
     555                 :          0 :                 break;
     556                 :            :         default:
     557                 :            :                 return false;
     558                 :            :         }
     559                 :          0 :         *min_len += addr_len;
     560         [ #  # ]:          0 :         if (len < *min_len)
     561                 :            :                 return false;
     562                 :            : 
     563                 :            :         /* Check prefix length (in bits) vs address length (in bytes). */
     564         [ #  # ]:          0 :         if (cond->prefix_len > 8 * addr_len)
     565                 :            :                 return false;
     566                 :            : 
     567                 :          0 :         return true;
     568                 :            : }
     569                 :            : 
     570                 :            : /* Validate a port comparison operator. */
     571                 :            : static inline bool valid_port_comparison(const struct inet_diag_bc_op *op,
     572                 :            :                                          int len, int *min_len)
     573                 :            : {
     574                 :            :         /* Port comparisons put the port in a follow-on inet_diag_bc_op. */
     575                 :          0 :         *min_len += sizeof(struct inet_diag_bc_op);
     576         [ #  # ]:          0 :         if (len < *min_len)
     577                 :            :                 return false;
     578                 :            :         return true;
     579                 :            : }
     580                 :            : 
     581                 :          0 : static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
     582                 :            : {
     583                 :            :         const void *bc = bytecode;
     584                 :            :         int  len = bytecode_len;
     585                 :            : 
     586         [ #  # ]:          0 :         while (len > 0) {
     587                 :            :                 const struct inet_diag_bc_op *op = bc;
     588                 :          0 :                 int min_len = sizeof(struct inet_diag_bc_op);
     589                 :            : 
     590                 :            : //printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
     591 [ #  # ][ #  # ]:          0 :                 switch (op->code) {
         [ #  # ][ #  # ]
     592                 :            :                 case INET_DIAG_BC_S_COND:
     593                 :            :                 case INET_DIAG_BC_D_COND:
     594         [ #  # ]:          0 :                         if (!valid_hostcond(bc, len, &min_len))
     595                 :          0 :                                 return -EINVAL;
     596                 :            :                         break;
     597                 :            :                 case INET_DIAG_BC_S_GE:
     598                 :            :                 case INET_DIAG_BC_S_LE:
     599                 :            :                 case INET_DIAG_BC_D_GE:
     600                 :            :                 case INET_DIAG_BC_D_LE:
     601         [ #  # ]:          0 :                         if (!valid_port_comparison(bc, len, &min_len))
     602                 :            :                                 return -EINVAL;
     603                 :            :                         break;
     604                 :            :                 case INET_DIAG_BC_AUTO:
     605                 :            :                 case INET_DIAG_BC_JMP:
     606                 :            :                 case INET_DIAG_BC_NOP:
     607                 :            :                         break;
     608                 :            :                 default:
     609                 :            :                         return -EINVAL;
     610                 :            :                 }
     611                 :            : 
     612         [ #  # ]:          0 :                 if (op->code != INET_DIAG_BC_NOP) {
     613 [ #  # ][ #  # ]:          0 :                         if (op->no < min_len || op->no > len + 4 || op->no & 3)
                 [ #  # ]
     614                 :            :                                 return -EINVAL;
     615 [ #  # ][ #  # ]:          0 :                         if (op->no < len &&
     616                 :          0 :                             !valid_cc(bytecode, bytecode_len, len - op->no))
     617                 :            :                                 return -EINVAL;
     618                 :            :                 }
     619                 :            : 
     620 [ #  # ][ #  # ]:          0 :                 if (op->yes < min_len || op->yes > len + 4 || op->yes & 3)
                 [ #  # ]
     621                 :            :                         return -EINVAL;
     622                 :          0 :                 bc  += op->yes;
     623                 :          0 :                 len -= op->yes;
     624                 :            :         }
     625         [ #  # ]:          0 :         return len == 0 ? 0 : -EINVAL;
     626                 :            : }
     627                 :            : 
     628                 :          0 : static int inet_csk_diag_dump(struct sock *sk,
     629                 :            :                               struct sk_buff *skb,
     630                 :            :                               struct netlink_callback *cb,
     631                 :            :                               struct inet_diag_req_v2 *r,
     632                 :            :                               const struct nlattr *bc)
     633                 :            : {
     634         [ #  # ]:          0 :         if (!inet_diag_bc_sk(bc, sk))
     635                 :            :                 return 0;
     636                 :            : 
     637                 :          0 :         return inet_csk_diag_fill(sk, skb, r,
     638                 :          0 :                                   sk_user_ns(NETLINK_CB(cb->skb).sk),
     639                 :            :                                   NETLINK_CB(cb->skb).portid,
     640                 :          0 :                                   cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
     641                 :            : }
     642                 :            : 
     643                 :          0 : static int inet_twsk_diag_dump(struct sock *sk,
     644                 :            :                                struct sk_buff *skb,
     645                 :            :                                struct netlink_callback *cb,
     646                 :            :                                struct inet_diag_req_v2 *r,
     647                 :            :                                const struct nlattr *bc)
     648                 :            : {
     649                 :            :         struct inet_timewait_sock *tw = inet_twsk(sk);
     650                 :            : 
     651         [ #  # ]:          0 :         if (bc != NULL) {
     652                 :            :                 struct inet_diag_entry entry;
     653                 :            : 
     654                 :          0 :                 entry.family = tw->tw_family;
     655                 :            : #if IS_ENABLED(CONFIG_IPV6)
     656         [ #  # ]:          0 :                 if (tw->tw_family == AF_INET6) {
     657                 :          0 :                         entry.saddr = tw->tw_v6_rcv_saddr.s6_addr32;
     658                 :          0 :                         entry.daddr = tw->tw_v6_daddr.s6_addr32;
     659                 :            :                 } else
     660                 :            : #endif
     661                 :            :                 {
     662                 :          0 :                         entry.saddr = &tw->tw_rcv_saddr;
     663                 :          0 :                         entry.daddr = &tw->tw_daddr;
     664                 :            :                 }
     665                 :          0 :                 entry.sport = tw->tw_num;
     666         [ #  # ]:          0 :                 entry.dport = ntohs(tw->tw_dport);
     667                 :          0 :                 entry.userlocks = 0;
     668                 :            : 
     669         [ #  # ]:          0 :                 if (!inet_diag_bc_run(bc, &entry))
     670                 :          0 :                         return 0;
     671                 :            :         }
     672                 :            : 
     673                 :          0 :         return inet_twsk_diag_fill(tw, skb, r,
     674                 :          0 :                                    NETLINK_CB(cb->skb).portid,
     675                 :          0 :                                    cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
     676                 :            : }
     677                 :            : 
     678                 :            : /* Get the IPv4, IPv6, or IPv4-mapped-IPv6 local and remote addresses
     679                 :            :  * from a request_sock. For IPv4-mapped-IPv6 we must map IPv4 to IPv6.
     680                 :            :  */
     681                 :            : static inline void inet_diag_req_addrs(const struct sock *sk,
     682                 :            :                                        const struct request_sock *req,
     683                 :            :                                        struct inet_diag_entry *entry)
     684                 :            : {
     685                 :            :         struct inet_request_sock *ireq = inet_rsk(req);
     686                 :            : 
     687                 :            : #if IS_ENABLED(CONFIG_IPV6)
     688 [ #  # ][ #  # ]:          0 :         if (sk->sk_family == AF_INET6) {
     689 [ #  # ][ #  # ]:          0 :                 if (req->rsk_ops->family == AF_INET6) {
     690                 :          0 :                         entry->saddr = ireq->ir_v6_loc_addr.s6_addr32;
     691                 :          0 :                         entry->daddr = ireq->ir_v6_rmt_addr.s6_addr32;
     692 [ #  # ][ #  # ]:          0 :                 } else if (req->rsk_ops->family == AF_INET) {
     693                 :          0 :                         ipv6_addr_set_v4mapped(ireq->ir_loc_addr,
     694                 :            :                                                &entry->saddr_storage);
     695                 :          0 :                         ipv6_addr_set_v4mapped(ireq->ir_rmt_addr,
     696                 :            :                                                &entry->daddr_storage);
     697                 :          0 :                         entry->saddr = entry->saddr_storage.s6_addr32;
     698                 :          0 :                         entry->daddr = entry->daddr_storage.s6_addr32;
     699                 :            :                 }
     700                 :            :         } else
     701                 :            : #endif
     702                 :            :         {
     703                 :          0 :                 entry->saddr = &ireq->ir_loc_addr;
     704                 :          0 :                 entry->daddr = &ireq->ir_rmt_addr;
     705                 :            :         }
     706                 :            : }
     707                 :            : 
     708                 :          0 : static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
     709                 :            :                               struct request_sock *req,
     710                 :            :                               struct user_namespace *user_ns,
     711                 :            :                               u32 portid, u32 seq,
     712                 :            :                               const struct nlmsghdr *unlh)
     713                 :            : {
     714                 :            :         const struct inet_request_sock *ireq = inet_rsk(req);
     715                 :            :         struct inet_sock *inet = inet_sk(sk);
     716                 :            :         struct inet_diag_msg *r;
     717                 :            :         struct nlmsghdr *nlh;
     718                 :            :         long tmo;
     719                 :            : 
     720                 :          0 :         nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r),
     721                 :            :                         NLM_F_MULTI);
     722         [ #  # ]:          0 :         if (!nlh)
     723                 :            :                 return -EMSGSIZE;
     724                 :            : 
     725                 :            :         r = nlmsg_data(nlh);
     726                 :          0 :         r->idiag_family = sk->sk_family;
     727                 :          0 :         r->idiag_state = TCP_SYN_RECV;
     728                 :          0 :         r->idiag_timer = 1;
     729                 :          0 :         r->idiag_retrans = req->num_retrans;
     730                 :            : 
     731                 :          0 :         r->id.idiag_if = sk->sk_bound_dev_if;
     732                 :          0 :         sock_diag_save_cookie(req, r->id.idiag_cookie);
     733                 :            : 
     734                 :          0 :         tmo = req->expires - jiffies;
     735         [ #  # ]:          0 :         if (tmo < 0)
     736                 :            :                 tmo = 0;
     737                 :            : 
     738                 :          0 :         r->id.idiag_sport = inet->inet_sport;
     739                 :          0 :         r->id.idiag_dport = ireq->ir_rmt_port;
     740                 :            : 
     741                 :          0 :         memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src));
     742                 :          0 :         memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst));
     743                 :            : 
     744                 :          0 :         r->id.idiag_src[0] = ireq->ir_loc_addr;
     745                 :          0 :         r->id.idiag_dst[0] = ireq->ir_rmt_addr;
     746                 :            : 
     747                 :          0 :         r->idiag_expires = jiffies_to_msecs(tmo);
     748                 :          0 :         r->idiag_rqueue = 0;
     749                 :          0 :         r->idiag_wqueue = 0;
     750                 :          0 :         r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk));
     751                 :          0 :         r->idiag_inode = 0;
     752                 :            : #if IS_ENABLED(CONFIG_IPV6)
     753         [ #  # ]:          0 :         if (r->idiag_family == AF_INET6) {
     754                 :            :                 struct inet_diag_entry entry;
     755                 :            :                 inet_diag_req_addrs(sk, req, &entry);
     756                 :          0 :                 memcpy(r->id.idiag_src, entry.saddr, sizeof(struct in6_addr));
     757                 :          0 :                 memcpy(r->id.idiag_dst, entry.daddr, sizeof(struct in6_addr));
     758                 :            :         }
     759                 :            : #endif
     760                 :            : 
     761                 :            :         return nlmsg_end(skb, nlh);
     762                 :            : }
     763                 :            : 
     764                 :          0 : static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
     765                 :            :                                struct netlink_callback *cb,
     766                 :            :                                struct inet_diag_req_v2 *r,
     767                 :            :                                const struct nlattr *bc)
     768                 :            : {
     769                 :            :         struct inet_diag_entry entry;
     770                 :            :         struct inet_connection_sock *icsk = inet_csk(sk);
     771                 :            :         struct listen_sock *lopt;
     772                 :            :         struct inet_sock *inet = inet_sk(sk);
     773                 :            :         int j, s_j;
     774                 :            :         int reqnum, s_reqnum;
     775                 :            :         int err = 0;
     776                 :            : 
     777                 :          0 :         s_j = cb->args[3];
     778                 :          0 :         s_reqnum = cb->args[4];
     779                 :            : 
     780         [ #  # ]:          0 :         if (s_j > 0)
     781                 :          0 :                 s_j--;
     782                 :            : 
     783                 :          0 :         entry.family = sk->sk_family;
     784                 :            : 
     785                 :          0 :         read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
     786                 :            : 
     787                 :          0 :         lopt = icsk->icsk_accept_queue.listen_opt;
     788 [ #  # ][ #  # ]:          0 :         if (!lopt || !lopt->qlen)
     789                 :            :                 goto out;
     790                 :            : 
     791         [ #  # ]:          0 :         if (bc != NULL) {
     792                 :          0 :                 entry.sport = inet->inet_num;
     793                 :          0 :                 entry.userlocks = sk->sk_userlocks;
     794                 :            :         }
     795                 :            : 
     796         [ #  # ]:          0 :         for (j = s_j; j < lopt->nr_table_entries; j++) {
     797                 :          0 :                 struct request_sock *req, *head = lopt->syn_table[j];
     798                 :            : 
     799                 :            :                 reqnum = 0;
     800         [ #  # ]:          0 :                 for (req = head; req; reqnum++, req = req->dl_next) {
     801                 :            :                         struct inet_request_sock *ireq = inet_rsk(req);
     802                 :            : 
     803         [ #  # ]:          0 :                         if (reqnum < s_reqnum)
     804                 :          0 :                                 continue;
     805 [ #  # ][ #  # ]:          0 :                         if (r->id.idiag_dport != ireq->ir_rmt_port &&
     806                 :            :                             r->id.idiag_dport)
     807                 :          0 :                                 continue;
     808                 :            : 
     809         [ #  # ]:          0 :                         if (bc) {
     810                 :            :                                 inet_diag_req_addrs(sk, req, &entry);
     811         [ #  # ]:          0 :                                 entry.dport = ntohs(ireq->ir_rmt_port);
     812                 :            : 
     813         [ #  # ]:          0 :                                 if (!inet_diag_bc_run(bc, &entry))
     814                 :          0 :                                         continue;
     815                 :            :                         }
     816                 :            : 
     817                 :          0 :                         err = inet_diag_fill_req(skb, sk, req,
     818                 :            :                                                sk_user_ns(NETLINK_CB(cb->skb).sk),
     819                 :          0 :                                                NETLINK_CB(cb->skb).portid,
     820                 :          0 :                                                cb->nlh->nlmsg_seq, cb->nlh);
     821         [ #  # ]:          0 :                         if (err < 0) {
     822                 :          0 :                                 cb->args[3] = j + 1;
     823                 :          0 :                                 cb->args[4] = reqnum;
     824                 :            :                                 goto out;
     825                 :            :                         }
     826                 :            :                 }
     827                 :            : 
     828                 :            :                 s_reqnum = 0;
     829                 :            :         }
     830                 :            : 
     831                 :            : out:
     832                 :          0 :         read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
     833                 :            : 
     834                 :          0 :         return err;
     835                 :            : }
     836                 :            : 
     837                 :          0 : void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
     838                 :            :                 struct netlink_callback *cb, struct inet_diag_req_v2 *r, struct nlattr *bc)
     839                 :            : {
     840                 :            :         int i, num;
     841                 :            :         int s_i, s_num;
     842                 :            :         struct net *net = sock_net(skb->sk);
     843                 :            : 
     844                 :          0 :         s_i = cb->args[1];
     845                 :          0 :         s_num = num = cb->args[2];
     846                 :            : 
     847         [ #  # ]:          0 :         if (cb->args[0] == 0) {
     848         [ #  # ]:          0 :                 if (!(r->idiag_states & (TCPF_LISTEN | TCPF_SYN_RECV)))
     849                 :            :                         goto skip_listen_ht;
     850                 :            : 
     851         [ #  # ]:          0 :                 for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
     852                 :            :                         struct sock *sk;
     853                 :            :                         struct hlist_nulls_node *node;
     854                 :            :                         struct inet_listen_hashbucket *ilb;
     855                 :            : 
     856                 :            :                         num = 0;
     857                 :          0 :                         ilb = &hashinfo->listening_hash[i];
     858                 :            :                         spin_lock_bh(&ilb->lock);
     859         [ #  # ]:          0 :                         sk_nulls_for_each(sk, node, &ilb->head) {
     860                 :            :                                 struct inet_sock *inet = inet_sk(sk);
     861                 :            : 
     862                 :            :                                 if (!net_eq(sock_net(sk), net))
     863                 :            :                                         continue;
     864                 :            : 
     865         [ #  # ]:          0 :                                 if (num < s_num) {
     866                 :          0 :                                         num++;
     867                 :          0 :                                         continue;
     868                 :            :                                 }
     869                 :            : 
     870 [ #  # ][ #  # ]:          0 :                                 if (r->sdiag_family != AF_UNSPEC &&
     871                 :          0 :                                                 sk->sk_family != r->sdiag_family)
     872                 :            :                                         goto next_listen;
     873                 :            : 
     874 [ #  # ][ #  # ]:          0 :                                 if (r->id.idiag_sport != inet->inet_sport &&
     875                 :            :                                     r->id.idiag_sport)
     876                 :            :                                         goto next_listen;
     877                 :            : 
     878 [ #  # ][ #  # ]:          0 :                                 if (!(r->idiag_states & TCPF_LISTEN) ||
     879         [ #  # ]:          0 :                                     r->id.idiag_dport ||
     880                 :          0 :                                     cb->args[3] > 0)
     881                 :            :                                         goto syn_recv;
     882                 :            : 
     883         [ #  # ]:          0 :                                 if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) {
     884                 :            :                                         spin_unlock_bh(&ilb->lock);
     885                 :            :                                         goto done;
     886                 :            :                                 }
     887                 :            : 
     888                 :            : syn_recv:
     889         [ #  # ]:          0 :                                 if (!(r->idiag_states & TCPF_SYN_RECV))
     890                 :            :                                         goto next_listen;
     891                 :            : 
     892         [ #  # ]:          0 :                                 if (inet_diag_dump_reqs(skb, sk, cb, r, bc) < 0) {
     893                 :            :                                         spin_unlock_bh(&ilb->lock);
     894                 :            :                                         goto done;
     895                 :            :                                 }
     896                 :            : 
     897                 :            : next_listen:
     898                 :          0 :                                 cb->args[3] = 0;
     899                 :          0 :                                 cb->args[4] = 0;
     900                 :          0 :                                 ++num;
     901                 :            :                         }
     902                 :            :                         spin_unlock_bh(&ilb->lock);
     903                 :            : 
     904                 :            :                         s_num = 0;
     905                 :          0 :                         cb->args[3] = 0;
     906                 :          0 :                         cb->args[4] = 0;
     907                 :            :                 }
     908                 :            : skip_listen_ht:
     909                 :          0 :                 cb->args[0] = 1;
     910                 :            :                 s_i = num = s_num = 0;
     911                 :            :         }
     912                 :            : 
     913         [ #  # ]:          0 :         if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV)))
     914                 :            :                 goto out;
     915                 :            : 
     916         [ #  # ]:          0 :         for (i = s_i; i <= hashinfo->ehash_mask; i++) {
     917                 :          0 :                 struct inet_ehash_bucket *head = &hashinfo->ehash[i];
     918                 :            :                 spinlock_t *lock = inet_ehash_lockp(hashinfo, i);
     919                 :            :                 struct sock *sk;
     920                 :            :                 struct hlist_nulls_node *node;
     921                 :            : 
     922                 :            :                 num = 0;
     923                 :            : 
     924         [ #  # ]:          0 :                 if (hlist_nulls_empty(&head->chain))
     925                 :          0 :                         continue;
     926                 :            : 
     927         [ #  # ]:          0 :                 if (i > s_i)
     928                 :            :                         s_num = 0;
     929                 :            : 
     930                 :            :                 spin_lock_bh(lock);
     931         [ #  # ]:          0 :                 sk_nulls_for_each(sk, node, &head->chain) {
     932                 :            :                         int res;
     933                 :            :                         int state;
     934                 :            : 
     935                 :            :                         if (!net_eq(sock_net(sk), net))
     936                 :            :                                 continue;
     937         [ #  # ]:          0 :                         if (num < s_num)
     938                 :            :                                 goto next_normal;
     939                 :          0 :                         state = (sk->sk_state == TCP_TIME_WAIT) ?
     940         [ #  # ]:          0 :                                 inet_twsk(sk)->tw_substate : sk->sk_state;
     941         [ #  # ]:          0 :                         if (!(r->idiag_states & (1 << state)))
     942                 :            :                                 goto next_normal;
     943 [ #  # ][ #  # ]:          0 :                         if (r->sdiag_family != AF_UNSPEC &&
     944                 :          0 :                             sk->sk_family != r->sdiag_family)
     945                 :            :                                 goto next_normal;
     946 [ #  # ][ #  # ]:          0 :                         if (r->id.idiag_sport != htons(sk->sk_num) &&
                 [ #  # ]
     947                 :            :                             r->id.idiag_sport)
     948                 :            :                                 goto next_normal;
     949 [ #  # ][ #  # ]:          0 :                         if (r->id.idiag_dport != sk->sk_dport &&
     950                 :            :                             r->id.idiag_dport)
     951                 :            :                                 goto next_normal;
     952         [ #  # ]:          0 :                         if (sk->sk_state == TCP_TIME_WAIT)
     953                 :          0 :                                 res = inet_twsk_diag_dump(sk, skb, cb, r, bc);
     954                 :            :                         else
     955                 :          0 :                                 res = inet_csk_diag_dump(sk, skb, cb, r, bc);
     956         [ #  # ]:          0 :                         if (res < 0) {
     957                 :            :                                 spin_unlock_bh(lock);
     958                 :            :                                 goto done;
     959                 :            :                         }
     960                 :            : next_normal:
     961                 :          0 :                         ++num;
     962                 :            :                 }
     963                 :            : 
     964                 :            :                 spin_unlock_bh(lock);
     965                 :            :         }
     966                 :            : 
     967                 :            : done:
     968                 :          0 :         cb->args[1] = i;
     969                 :          0 :         cb->args[2] = num;
     970                 :            : out:
     971                 :            :         ;
     972                 :          0 : }
     973                 :            : EXPORT_SYMBOL_GPL(inet_diag_dump_icsk);
     974                 :            : 
     975                 :          0 : static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
     976                 :            :                 struct inet_diag_req_v2 *r, struct nlattr *bc)
     977                 :            : {
     978                 :            :         const struct inet_diag_handler *handler;
     979                 :            :         int err = 0;
     980                 :            : 
     981                 :          0 :         handler = inet_diag_lock_handler(r->sdiag_protocol);
     982         [ #  # ]:          0 :         if (!IS_ERR(handler))
     983                 :          0 :                 handler->dump(skb, cb, r, bc);
     984                 :            :         else
     985                 :            :                 err = PTR_ERR(handler);
     986                 :            :         inet_diag_unlock_handler(handler);
     987                 :            : 
     988         [ #  # ]:          0 :         return err ? : skb->len;
     989                 :            : }
     990                 :            : 
     991                 :          0 : static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
     992                 :            : {
     993                 :            :         struct nlattr *bc = NULL;
     994                 :            :         int hdrlen = sizeof(struct inet_diag_req_v2);
     995                 :            : 
     996         [ #  # ]:          0 :         if (nlmsg_attrlen(cb->nlh, hdrlen))
     997                 :            :                 bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE);
     998                 :            : 
     999                 :          0 :         return __inet_diag_dump(skb, cb, nlmsg_data(cb->nlh), bc);
    1000                 :            : }
    1001                 :            : 
    1002                 :            : static inline int inet_diag_type2proto(int type)
    1003                 :            : {
    1004      [ #  #  # ]:          0 :         switch (type) {
              [ #  #  # ]
    1005                 :            :         case TCPDIAG_GETSOCK:
    1006                 :            :                 return IPPROTO_TCP;
    1007                 :            :         case DCCPDIAG_GETSOCK:
    1008                 :            :                 return IPPROTO_DCCP;
    1009                 :            :         default:
    1010                 :            :                 return 0;
    1011                 :            :         }
    1012                 :            : }
    1013                 :            : 
    1014                 :          0 : static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *cb)
    1015                 :            : {
    1016                 :          0 :         struct inet_diag_req *rc = nlmsg_data(cb->nlh);
    1017                 :            :         struct inet_diag_req_v2 req;
    1018                 :            :         struct nlattr *bc = NULL;
    1019                 :            :         int hdrlen = sizeof(struct inet_diag_req);
    1020                 :            : 
    1021                 :          0 :         req.sdiag_family = AF_UNSPEC; /* compatibility */
    1022                 :          0 :         req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type);
    1023                 :          0 :         req.idiag_ext = rc->idiag_ext;
    1024                 :          0 :         req.idiag_states = rc->idiag_states;
    1025                 :          0 :         req.id = rc->id;
    1026                 :            : 
    1027         [ #  # ]:          0 :         if (nlmsg_attrlen(cb->nlh, hdrlen))
    1028                 :            :                 bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE);
    1029                 :            : 
    1030                 :          0 :         return __inet_diag_dump(skb, cb, &req, bc);
    1031                 :            : }
    1032                 :            : 
    1033                 :          0 : static int inet_diag_get_exact_compat(struct sk_buff *in_skb,
    1034                 :            :                                const struct nlmsghdr *nlh)
    1035                 :            : {
    1036                 :            :         struct inet_diag_req *rc = nlmsg_data(nlh);
    1037                 :            :         struct inet_diag_req_v2 req;
    1038                 :            : 
    1039                 :          0 :         req.sdiag_family = rc->idiag_family;
    1040                 :          0 :         req.sdiag_protocol = inet_diag_type2proto(nlh->nlmsg_type);
    1041                 :          0 :         req.idiag_ext = rc->idiag_ext;
    1042                 :          0 :         req.idiag_states = rc->idiag_states;
    1043                 :          0 :         req.id = rc->id;
    1044                 :            : 
    1045                 :          0 :         return inet_diag_get_exact(in_skb, nlh, &req);
    1046                 :            : }
    1047                 :            : 
    1048                 :          0 : static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
    1049                 :            : {
    1050                 :            :         int hdrlen = sizeof(struct inet_diag_req);
    1051                 :            :         struct net *net = sock_net(skb->sk);
    1052                 :            : 
    1053 [ #  # ][ #  # ]:          0 :         if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX ||
    1054                 :            :             nlmsg_len(nlh) < hdrlen)
    1055                 :            :                 return -EINVAL;
    1056                 :            : 
    1057         [ #  # ]:          0 :         if (nlh->nlmsg_flags & NLM_F_DUMP) {
    1058         [ #  # ]:          0 :                 if (nlmsg_attrlen(nlh, hdrlen)) {
    1059                 :          0 :                         struct nlattr *attr;
    1060                 :            : 
    1061                 :            :                         attr = nlmsg_find_attr(nlh, hdrlen,
    1062                 :            :                                                INET_DIAG_REQ_BYTECODE);
    1063 [ #  # ][ #  # ]:          0 :                         if (attr == NULL ||
    1064         [ #  # ]:          0 :                             nla_len(attr) < sizeof(struct inet_diag_bc_op) ||
    1065                 :          0 :                             inet_diag_bc_audit(nla_data(attr), nla_len(attr)))
    1066                 :            :                                 return -EINVAL;
    1067                 :            :                 }
    1068                 :            :                 {
    1069                 :          0 :                         struct netlink_dump_control c = {
    1070                 :            :                                 .dump = inet_diag_dump_compat,
    1071                 :            :                         };
    1072                 :          0 :                         return netlink_dump_start(net->diag_nlsk, skb, nlh, &c);
    1073                 :            :                 }
    1074                 :            :         }
    1075                 :            : 
    1076                 :          0 :         return inet_diag_get_exact_compat(skb, nlh);
    1077                 :            : }
    1078                 :            : 
    1079                 :          0 : static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
    1080                 :            : {
    1081                 :            :         int hdrlen = sizeof(struct inet_diag_req_v2);
    1082                 :            :         struct net *net = sock_net(skb->sk);
    1083                 :            : 
    1084         [ #  # ]:          0 :         if (nlmsg_len(h) < hdrlen)
    1085                 :            :                 return -EINVAL;
    1086                 :            : 
    1087         [ #  # ]:          0 :         if (h->nlmsg_flags & NLM_F_DUMP) {
    1088         [ #  # ]:          0 :                 if (nlmsg_attrlen(h, hdrlen)) {
    1089                 :          0 :                         struct nlattr *attr;
    1090                 :            :                         attr = nlmsg_find_attr(h, hdrlen,
    1091                 :            :                                                INET_DIAG_REQ_BYTECODE);
    1092 [ #  # ][ #  # ]:          0 :                         if (attr == NULL ||
    1093         [ #  # ]:          0 :                             nla_len(attr) < sizeof(struct inet_diag_bc_op) ||
    1094                 :          0 :                             inet_diag_bc_audit(nla_data(attr), nla_len(attr)))
    1095                 :            :                                 return -EINVAL;
    1096                 :            :                 }
    1097                 :            :                 {
    1098                 :          0 :                         struct netlink_dump_control c = {
    1099                 :            :                                 .dump = inet_diag_dump,
    1100                 :            :                         };
    1101                 :          0 :                         return netlink_dump_start(net->diag_nlsk, skb, h, &c);
    1102                 :            :                 }
    1103                 :            :         }
    1104                 :            : 
    1105                 :          0 :         return inet_diag_get_exact(skb, h, nlmsg_data(h));
    1106                 :            : }
    1107                 :            : 
    1108                 :            : static const struct sock_diag_handler inet_diag_handler = {
    1109                 :            :         .family = AF_INET,
    1110                 :            :         .dump = inet_diag_handler_dump,
    1111                 :            : };
    1112                 :            : 
    1113                 :            : static const struct sock_diag_handler inet6_diag_handler = {
    1114                 :            :         .family = AF_INET6,
    1115                 :            :         .dump = inet_diag_handler_dump,
    1116                 :            : };
    1117                 :            : 
    1118                 :          0 : int inet_diag_register(const struct inet_diag_handler *h)
    1119                 :            : {
    1120                 :          0 :         const __u16 type = h->idiag_type;
    1121                 :            :         int err = -EINVAL;
    1122                 :            : 
    1123         [ #  # ]:          0 :         if (type >= IPPROTO_MAX)
    1124                 :            :                 goto out;
    1125                 :            : 
    1126                 :          0 :         mutex_lock(&inet_diag_table_mutex);
    1127                 :            :         err = -EEXIST;
    1128         [ #  # ]:          0 :         if (inet_diag_table[type] == NULL) {
    1129                 :          0 :                 inet_diag_table[type] = h;
    1130                 :            :                 err = 0;
    1131                 :            :         }
    1132                 :          0 :         mutex_unlock(&inet_diag_table_mutex);
    1133                 :            : out:
    1134                 :          0 :         return err;
    1135                 :            : }
    1136                 :            : EXPORT_SYMBOL_GPL(inet_diag_register);
    1137                 :            : 
    1138                 :          0 : void inet_diag_unregister(const struct inet_diag_handler *h)
    1139                 :            : {
    1140                 :          0 :         const __u16 type = h->idiag_type;
    1141                 :            : 
    1142         [ #  # ]:          0 :         if (type >= IPPROTO_MAX)
    1143                 :          0 :                 return;
    1144                 :            : 
    1145                 :          0 :         mutex_lock(&inet_diag_table_mutex);
    1146                 :          0 :         inet_diag_table[type] = NULL;
    1147                 :          0 :         mutex_unlock(&inet_diag_table_mutex);
    1148                 :            : }
    1149                 :            : EXPORT_SYMBOL_GPL(inet_diag_unregister);
    1150                 :            : 
    1151                 :          0 : static int __init inet_diag_init(void)
    1152                 :            : {
    1153                 :            :         const int inet_diag_table_size = (IPPROTO_MAX *
    1154                 :            :                                           sizeof(struct inet_diag_handler *));
    1155                 :            :         int err = -ENOMEM;
    1156                 :            : 
    1157                 :          0 :         inet_diag_table = kzalloc(inet_diag_table_size, GFP_KERNEL);
    1158         [ #  # ]:          0 :         if (!inet_diag_table)
    1159                 :            :                 goto out;
    1160                 :            : 
    1161                 :          0 :         err = sock_diag_register(&inet_diag_handler);
    1162         [ #  # ]:          0 :         if (err)
    1163                 :            :                 goto out_free_nl;
    1164                 :            : 
    1165                 :          0 :         err = sock_diag_register(&inet6_diag_handler);
    1166         [ #  # ]:          0 :         if (err)
    1167                 :            :                 goto out_free_inet;
    1168                 :            : 
    1169                 :          0 :         sock_diag_register_inet_compat(inet_diag_rcv_msg_compat);
    1170                 :            : out:
    1171                 :          0 :         return err;
    1172                 :            : 
    1173                 :            : out_free_inet:
    1174                 :          0 :         sock_diag_unregister(&inet_diag_handler);
    1175                 :            : out_free_nl:
    1176                 :          0 :         kfree(inet_diag_table);
    1177                 :          0 :         goto out;
    1178                 :            : }
    1179                 :            : 
    1180                 :          0 : static void __exit inet_diag_exit(void)
    1181                 :            : {
    1182                 :          0 :         sock_diag_unregister(&inet6_diag_handler);
    1183                 :          0 :         sock_diag_unregister(&inet_diag_handler);
    1184                 :          0 :         sock_diag_unregister_inet_compat(inet_diag_rcv_msg_compat);
    1185                 :          0 :         kfree(inet_diag_table);
    1186                 :          0 : }
    1187                 :            : 
    1188                 :            : module_init(inet_diag_init);
    1189                 :            : module_exit(inet_diag_exit);
    1190                 :            : MODULE_LICENSE("GPL");
    1191                 :            : MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2 /* AF_INET */);
    1192                 :            : MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10 /* AF_INET6 */);

Generated by: LCOV version 1.9