LCOV - code coverage report
Current view: top level - home/snorch/criu - sk-netlink.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 75 95 78.9 %
Date: 2014-04-22 Functions: 5 5 100.0 %
Branches: 35 58 60.3 %

           Branch data     Line data    Source code
       1                 :            : #include <unistd.h>
       2                 :            : #include <linux/netlink.h>
       3                 :            : #include <linux/rtnetlink.h>
       4                 :            : #include <poll.h>
       5                 :            : 
       6                 :            : #include "fdset.h"
       7                 :            : #include "files.h"
       8                 :            : #include "sockets.h"
       9                 :            : #include "util.h"
      10                 :            : 
      11                 :            : #include "protobuf.h"
      12                 :            : #include "protobuf/sk-netlink.pb-c.h"
      13                 :            : #include "netlink_diag.h"
      14                 :            : #include "libnetlink.h"
      15                 :            : 
      16                 :            : struct netlink_sk_desc {
      17                 :            :         struct socket_desc      sd;
      18                 :            :         u32                     portid;
      19                 :            :         u32                     *groups;
      20                 :            :         u32                     gsize;
      21                 :            :         u32                     dst_portid;
      22                 :            :         u32                     dst_group;
      23                 :            :         u8                      state;
      24                 :            :         u8                      protocol;
      25                 :            : };
      26                 :            : 
      27                 :      17652 : int netlink_receive_one(struct nlmsghdr *hdr, void *arg)
      28                 :            : {
      29                 :            :         struct rtattr *tb[NETLINK_DIAG_MAX+1];
      30                 :            :         struct netlink_diag_msg *m;
      31                 :            :         struct netlink_sk_desc *sd;
      32                 :            :         unsigned long *groups;
      33                 :            : 
      34                 :            :         m = NLMSG_DATA(hdr);
      35                 :      17652 :         pr_info("Collect netlink sock 0x%x\n", m->ndiag_ino);
      36                 :            : 
      37         [ -  + ]:      17652 :         sd = xmalloc(sizeof(*sd));
      38         [ +  - ]:      17652 :         if (!sd)
      39                 :            :                 return -1;
      40                 :            : 
      41                 :      17652 :         sd->protocol = m->ndiag_protocol;
      42                 :      17652 :         sd->portid = m->ndiag_portid;
      43                 :      17652 :         sd->dst_portid = m->ndiag_dst_portid;
      44                 :      17652 :         sd->dst_group = m->ndiag_dst_group;
      45                 :      17652 :         sd->state = m->ndiag_state;
      46                 :            : 
      47                 :      17652 :         parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr *)(m + 1),
      48                 :      17652 :                      hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
      49                 :            : 
      50         [ +  + ]:      17652 :         if (tb[NETLINK_DIAG_GROUPS]) {
      51                 :      12984 :                 sd->gsize = RTA_PAYLOAD(tb[NETLINK_DIAG_GROUPS]);
      52                 :      12984 :                 groups = RTA_DATA(tb[NETLINK_DIAG_GROUPS]);
      53                 :            : 
      54         [ -  + ]:      12984 :                 sd->groups = xmalloc(sd->gsize);
      55         [ -  + ]:      12984 :                 if (!sd->groups) {
      56         [ #  # ]:          0 :                         xfree(sd);
      57                 :            :                         return -1;
      58                 :            :                 }
      59                 :      12984 :                 memcpy(sd->groups, groups, sd->gsize);
      60                 :            :         } else {
      61                 :       4668 :                 sd->groups = NULL;
      62                 :       4668 :                 sd->gsize = 0;
      63                 :            :         }
      64                 :            : 
      65                 :      17652 :         return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd);
      66                 :            : }
      67                 :            : 
      68                 :         16 : static bool can_dump_netlink_sk(int lfd)
      69                 :            : {
      70                 :         16 :         struct pollfd pfd = {lfd, POLLIN, 0};
      71                 :            :         int ret;
      72                 :            : 
      73                 :            :         ret = poll(&pfd, 1, 0);
      74         [ -  + ]:         16 :         if (ret < 0) {
      75                 :          0 :                 pr_perror("poll() failed");
      76         [ -  + ]:         16 :         } else if (ret == 1)
      77                 :          0 :                 pr_err("The socket has data to read\n");
      78                 :            : 
      79                 :         16 :         return ret == 0;
      80                 :            : }
      81                 :            : 
      82                 :         16 : static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
      83                 :            : {
      84                 :            :         struct netlink_sk_desc *sk;
      85                 :         16 :         NetlinkSkEntry ne = NETLINK_SK_ENTRY__INIT;
      86                 :         16 :         SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
      87                 :            : 
      88                 :         16 :         sk = (struct netlink_sk_desc *)lookup_socket(p->stat.st_ino, PF_NETLINK, 0);
      89         [ +  - ]:         16 :         if (IS_ERR(sk))
      90                 :            :                 goto err;
      91                 :            : 
      92                 :         16 :         ne.id = id;
      93                 :         16 :         ne.ino = p->stat.st_ino;
      94                 :            : 
      95         [ +  - ]:         16 :         if (!can_dump_netlink_sk(lfd))
      96                 :            :                 goto err;
      97                 :            : 
      98         [ +  + ]:         16 :         if (sk) {
      99         [ -  + ]:         12 :                 BUG_ON(sk->sd.already_dumped);
     100                 :            : 
     101                 :         12 :                 ne.protocol = sk->protocol;
     102                 :         12 :                 ne.portid = sk->portid;
     103                 :         12 :                 ne.groups = sk->groups;
     104                 :            : 
     105                 :            : 
     106                 :         12 :                 ne.n_groups = sk->gsize / sizeof(ne.groups[0]);
     107                 :            :                 /*
     108                 :            :                  * On 64-bit sk->gsize is multiple to 8 bytes (sizeof(long)),
     109                 :            :                  * so remove the last 4 bytes if they are empty.
     110                 :            :                  */
     111 [ +  + ][ +  - ]:         12 :                 if (ne.n_groups && sk->groups[ne.n_groups - 1] == 0)
     112                 :          4 :                         ne.n_groups -= 1;
     113                 :            : 
     114         [ -  + ]:         12 :                 if (ne.n_groups > 1) {
     115                 :          0 :                         pr_err("%d %x\n", sk->gsize, sk->groups[1]);
     116                 :          0 :                         pr_err("The netlink socket 0x%x has more than 32 groups\n", ne.ino);
     117                 :          0 :                         return -1;
     118                 :            :                 }
     119 [ +  + ][ -  + ]:         12 :                 if (sk->groups && !sk->portid) {
     120                 :          0 :                         pr_err("The netlink socket 0x%x is bound to groups but not to portid\n", ne.ino);
     121                 :          0 :                         return -1;
     122                 :            :                 }
     123                 :         12 :                 ne.state = sk->state;
     124                 :         12 :                 ne.dst_portid = sk->dst_portid;
     125                 :         12 :                 ne.dst_group = sk->dst_group;
     126                 :            :         } else { /* unconnected and unbound socket */
     127                 :            :                 int val;
     128                 :          4 :                 socklen_t aux = sizeof(val);
     129                 :            : 
     130         [ -  + ]:          4 :                 if (getsockopt(lfd, SOL_SOCKET, SO_PROTOCOL, &val, &aux) < 0) {
     131                 :          0 :                         pr_perror("Unable to get protocol for netlink socket");
     132                 :          0 :                         goto err;
     133                 :            :                 }
     134                 :            : 
     135                 :          4 :                 ne.protocol = val;
     136                 :            :         }
     137                 :            : 
     138                 :         16 :         ne.fown = (FownEntry *)&p->fown;
     139                 :         16 :         ne.opts = &skopts;
     140                 :            : 
     141         [ +  - ]:         16 :         if (dump_socket_opts(lfd, &skopts))
     142                 :            :                 goto err;
     143                 :            : 
     144         [ -  + ]:         16 :         if (pb_write_one(fdset_fd(glob_fdset, CR_FD_NETLINK_SK), &ne, PB_NETLINK_SK))
     145                 :            :                 goto err;
     146                 :            : 
     147                 :            :         return 0;
     148                 :            : err:
     149                 :            :         return -1;
     150                 :            : }
     151                 :            : 
     152                 :            : const struct fdtype_ops netlink_dump_ops = {
     153                 :            :         .type           = FD_TYPES__NETLINKSK,
     154                 :            :         .dump           = dump_one_netlink_fd,
     155                 :            : };
     156                 :            : 
     157                 :            : struct netlink_sock_info {
     158                 :            :         NetlinkSkEntry *nse;
     159                 :            :         struct file_desc d;
     160                 :            : };
     161                 :            : 
     162                 :          8 : static int open_netlink_sk(struct file_desc *d)
     163                 :            : {
     164                 :            :         struct netlink_sock_info *nsi;
     165                 :            :         NetlinkSkEntry *nse;
     166                 :            :         struct sockaddr_nl addr;
     167                 :            :         int sk = -1;
     168                 :            : 
     169                 :            :         nsi = container_of(d, struct netlink_sock_info, d);
     170                 :          8 :         nse = nsi->nse;
     171                 :            : 
     172                 :          8 :         pr_info("Opening netlink socket id %#x\n", nse->id);
     173                 :            : 
     174                 :          8 :         sk = socket(PF_NETLINK, SOCK_RAW, nse->protocol);
     175         [ -  + ]:          8 :         if (sk < 0) {
     176                 :          0 :                 pr_perror("Can't create netlink sock");
     177                 :          0 :                 goto err;
     178                 :            :         }
     179                 :            : 
     180         [ +  + ]:          8 :         if (nse->portid) {
     181                 :            :                 memset(&addr, 0, sizeof(addr));
     182                 :          6 :                 addr.nl_family = AF_NETLINK;
     183         [ -  + ]:          6 :                 if (nse->n_groups > 1) {
     184                 :          0 :                         pr_err("Groups above 32 are not supported yet\n");
     185                 :          0 :                         goto err;
     186                 :            :                 }
     187         [ +  + ]:          6 :                 if (nse->n_groups)
     188                 :          2 :                         addr.nl_groups = nse->groups[0];
     189                 :          6 :                 addr.nl_pid = nse->portid;
     190                 :            : 
     191         [ -  + ]:          6 :                 if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
     192                 :          0 :                         pr_perror("Can't bind netlink socket");
     193                 :          0 :                         goto err;
     194                 :            :                 }
     195                 :            :         }
     196                 :            : 
     197         [ +  + ]:          8 :         if (nse->state == NETLINK_CONNECTED) {
     198                 :          2 :                 addr.nl_family = AF_NETLINK;
     199                 :          2 :                 addr.nl_groups = 1 << (nse->dst_group - 1);
     200                 :          2 :                 addr.nl_pid = nse->dst_portid;
     201         [ -  + ]:          2 :                 if (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
     202                 :          0 :                         pr_perror("Can't connect netlink socket");
     203                 :          0 :                         goto err;
     204                 :            :                 }
     205                 :            :         }
     206                 :            : 
     207         [ +  - ]:          8 :         if (rst_file_params(sk, nse->fown, nse->flags))
     208                 :            :                 goto err;
     209                 :            : 
     210         [ -  + ]:          8 :         if (restore_socket_opts(sk, nse->opts))
     211                 :            :                 goto err;
     212                 :            : 
     213                 :            :         return sk;
     214                 :            : err:
     215                 :          0 :         close(sk);
     216                 :          0 :         return -1;
     217                 :            : }
     218                 :            : 
     219                 :            : static struct file_desc_ops netlink_sock_desc_ops = {
     220                 :            :         .type = FD_TYPES__NETLINKSK,
     221                 :            :         .open = open_netlink_sk,
     222                 :            : };
     223                 :            : 
     224                 :          8 : static int collect_one_netlink_sk(void *o, ProtobufCMessage *base)
     225                 :            : {
     226                 :            :         struct netlink_sock_info *si = o;
     227                 :            : 
     228                 :          8 :         si->nse = pb_msg(base, NetlinkSkEntry);
     229                 :          8 :         return file_desc_add(&si->d, si->nse->id, &netlink_sock_desc_ops);
     230                 :            : }
     231                 :            : 
     232                 :            : struct collect_image_info netlink_sk_cinfo = {
     233                 :            :         .fd_type = CR_FD_NETLINK_SK,
     234                 :            :         .pb_type = PB_NETLINK_SK,
     235                 :            :         .priv_size = sizeof(struct netlink_sock_info),
     236                 :            :         .collect = collect_one_netlink_sk,
     237                 :            :         .flags = COLLECT_OPTIONAL,
     238                 :            : };

Generated by: LCOV version 1.9