LCOV - code coverage report
Current view: top level - net/core - sock_diag.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 8 167 4.8 %
Date: 2021-04-22 12:43:58 Functions: 2 19 10.5 %

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

Generated by: LCOV version 1.14