LCOV - code coverage report
Current view: top level - crtools - sk-unix.c (source / functions) Hit Total Coverage
Test: crtools.info Lines: 288 328 87.8 %
Date: 2012-12-28 Functions: 19 20 95.0 %
Branches: 159 234 67.9 %

           Branch data     Line data    Source code
       1                 :            : #include <sys/socket.h>
       2                 :            : #include <linux/netlink.h>
       3                 :            : #include <linux/rtnetlink.h>
       4                 :            : #include <unistd.h>
       5                 :            : #include <netinet/tcp.h>
       6                 :            : #include <sys/stat.h>
       7                 :            : #include <fcntl.h>
       8                 :            : #include <sys/un.h>
       9                 :            : #include <stdlib.h>
      10                 :            : 
      11                 :            : #include "types.h"
      12                 :            : #include "libnetlink.h"
      13                 :            : #include "crtools.h"
      14                 :            : #include "unix_diag.h"
      15                 :            : #include "files.h"
      16                 :            : #include "file-ids.h"
      17                 :            : #include "image.h"
      18                 :            : #include "log.h"
      19                 :            : #include "util.h"
      20                 :            : #include "util-net.h"
      21                 :            : #include "sockets.h"
      22                 :            : #include "sk-queue.h"
      23                 :            : #include "mount.h"
      24                 :            : 
      25                 :            : #include "protobuf.h"
      26                 :            : #include "protobuf/sk-unix.pb-c.h"
      27                 :            : 
      28                 :            : struct unix_sk_desc {
      29                 :            :         struct socket_desc      sd;
      30                 :            :         unsigned int            type;
      31                 :            :         unsigned int            state;
      32                 :            :         unsigned int            peer_ino;
      33                 :            :         unsigned int            rqlen;
      34                 :            :         unsigned int            wqlen;
      35                 :            :         unsigned int            namelen;
      36                 :            :         char                    *name;
      37                 :            :         unsigned int            nr_icons;
      38                 :            :         unsigned int            *icons;
      39                 :            :         unsigned char           shutdown;
      40                 :            :         struct list_head        list;
      41                 :            : };
      42                 :            : 
      43                 :            : static LIST_HEAD(unix_sockets);
      44                 :            : 
      45                 :            : struct unix_sk_listen_icon {
      46                 :            :         unsigned int                    peer_ino;
      47                 :            :         struct unix_sk_desc             *sk_desc;
      48                 :            :         struct unix_sk_listen_icon      *next;
      49                 :            : };
      50                 :            : 
      51                 :            : #define SK_HASH_SIZE            32
      52                 :            : 
      53                 :            : static struct unix_sk_listen_icon *unix_listen_icons[SK_HASH_SIZE];
      54                 :            : 
      55                 :            : static struct unix_sk_listen_icon *lookup_unix_listen_icons(int peer_ino)
      56                 :            : {
      57                 :            :         struct unix_sk_listen_icon *ic;
      58                 :            : 
      59         [ +  - ]:          2 :         for (ic = unix_listen_icons[peer_ino % SK_HASH_SIZE];
      60                 :          0 :                         ic; ic = ic->next)
      61         [ -  + ]:          2 :                 if (ic->peer_ino == peer_ino)
      62                 :            :                         return ic;
      63                 :            :         return NULL;
      64                 :            : }
      65                 :            : 
      66                 :       5009 : static void show_one_unix(char *act, const struct unix_sk_desc *sk)
      67                 :            : {
      68                 :       5009 :         pr_debug("\t%s: ino %#x peer_ino %#x family %4d type %4d state %2d name %s\n",
      69                 :            :                 act, sk->sd.ino, sk->peer_ino, sk->sd.family, sk->type, sk->state, sk->name);
      70                 :            : 
      71         [ +  + ]:       5009 :         if (sk->nr_icons) {
      72                 :            :                 int i;
      73                 :            : 
      74         [ +  + ]:          8 :                 for (i = 0; i < sk->nr_icons; i++)
      75                 :          4 :                         pr_debug("\t\ticon: %4d\n", sk->icons[i]);
      76                 :            :         }
      77                 :       5009 : }
      78                 :            : 
      79                 :         58 : static void show_one_unix_img(const char *act, const UnixSkEntry *e)
      80                 :            : {
      81                 :         58 :         pr_info("\t%s: id %#x ino %#x peer %#x type %d state %d name %d bytes\n",
      82                 :            :                 act, e->id, e->ino, e->peer, e->type, e->state, (int)e->name.len);
      83                 :         58 : }
      84                 :            : 
      85                 :         57 : static int can_dump_unix_sk(const struct unix_sk_desc *sk)
      86                 :            : {
      87         [ -  + ]:         57 :         if (sk->type != SOCK_STREAM &&
      88                 :            :             sk->type != SOCK_DGRAM) {
      89                 :          0 :                 pr_err("Only stream/dgram sockets for now\n");
      90                 :            :                 return 0;
      91                 :            :         }
      92                 :            : 
      93         [ -  + ]:         57 :         switch (sk->state) {
      94                 :            :         case TCP_LISTEN:
      95                 :            :         case TCP_ESTABLISHED:
      96                 :            :         case TCP_CLOSE:
      97                 :            :                 break;
      98                 :            :         default:
      99                 :         57 :                 pr_err("Unknown state %d\n", sk->state);
     100                 :            :                 return 0;
     101                 :            :         }
     102                 :            : 
     103                 :            :         return 1;
     104                 :            : }
     105                 :            : 
     106                 :         57 : static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
     107                 :            : {
     108                 :            :         struct unix_sk_desc *sk;
     109                 :         57 :         UnixSkEntry ue = UNIX_SK_ENTRY__INIT;
     110                 :         57 :         SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
     111                 :            : 
     112                 :         57 :         sk = (struct unix_sk_desc *)lookup_socket(p->stat.st_ino, PF_UNIX);
     113         [ +  - ]:         57 :         if (!sk)
     114                 :            :                 goto err;
     115                 :            : 
     116         [ +  - ]:         57 :         if (!can_dump_unix_sk(sk))
     117                 :            :                 goto err;
     118                 :            : 
     119         [ -  + ]:         57 :         BUG_ON(sk->sd.already_dumped);
     120                 :            : 
     121                 :         57 :         ue.name.len     = (size_t)sk->namelen;
     122                 :         57 :         ue.name.data    = (void *)sk->name;
     123                 :            : 
     124                 :         57 :         ue.id           = id;
     125                 :         57 :         ue.ino          = sk->sd.ino;
     126                 :         57 :         ue.type         = sk->type;
     127                 :         57 :         ue.state        = sk->state;
     128                 :         57 :         ue.flags        = p->flags;
     129                 :         57 :         ue.backlog      = sk->wqlen;
     130                 :         57 :         ue.peer         = sk->peer_ino;
     131                 :         57 :         ue.fown         = (FownEntry *)&p->fown;
     132                 :         57 :         ue.opts         = &skopts;
     133                 :         57 :         ue.uflags       = 0;
     134                 :            : 
     135         [ +  + ]:         57 :         sk_encode_shutdown(&ue, sk->shutdown);
     136                 :            : 
     137         [ +  + ]:         57 :         if (ue.peer) {
     138                 :            :                 struct unix_sk_desc *peer;
     139                 :            : 
     140                 :         43 :                 peer = (struct unix_sk_desc *)lookup_socket(ue.peer, PF_UNIX);
     141         [ -  + ]:         43 :                 if (!peer) {
     142                 :          0 :                         pr_err("Unix socket %#x without peer %#x\n",
     143                 :            :                                         ue.ino, ue.peer);
     144                 :          0 :                         goto err;
     145                 :            :                 }
     146                 :            : 
     147                 :            :                 /*
     148                 :            :                  * Peer should have us as peer or have a name by which
     149                 :            :                  * we can access one.
     150                 :            :                  */
     151         [ +  + ]:         43 :                 if (peer->peer_ino != ue.ino) {
     152         [ -  + ]:          5 :                         if (!peer->name) {
     153                 :          0 :                                 pr_err("Unix socket %#x with unreachable peer %#x (%#x/%s)\n",
     154                 :            :                                        ue.ino, ue.peer, peer->peer_ino, peer->name);
     155                 :          0 :                                 goto err;
     156                 :            :                         }
     157                 :            : 
     158                 :            :                         /*
     159                 :            :                          * It can be external socket, so we defer dumping
     160                 :            :                          * until all sockets the program owns are processed.
     161                 :            :                          */
     162 [ +  - ][ +  + ]:          5 :                         if (!peer->sd.already_dumped && list_empty(&peer->list)) {
     163                 :          3 :                                 show_one_unix("Add a peer", peer);
     164                 :          3 :                                 list_add_tail(&peer->list, &unix_sockets);
     165                 :            :                         }
     166                 :            :                 }
     167                 :            : 
     168 [ +  + ][ +  + ]:         43 :                 if ((ue.type != SOCK_DGRAM) && (
     169         [ +  - ]:          2 :                                 ((ue.shutdown == SK_SHUTDOWN__READ)  &&
     170         [ +  + ]:         20 :                                  (peer->shutdown != SK_SHUTDOWN__WRITE)) ||
     171         [ +  - ]:          2 :                                 ((ue.shutdown == SK_SHUTDOWN__WRITE) &&
     172         [ +  + ]:         20 :                                  (peer->shutdown != SK_SHUTDOWN__READ))  ||
     173         [ -  + ]:          4 :                                 ((ue.shutdown == SK_SHUTDOWN__BOTH)  &&
     174                 :          4 :                                  (peer->shutdown != SK_SHUTDOWN__BOTH)) )) {
     175                 :            :                         /*
     176                 :            :                          * On restore we assume, that stream pairs must
     177                 :            :                          * be shut down from one end only
     178                 :            :                          */
     179                 :          0 :                         pr_err("Shutdown mismatch %u:%d -> %u:%d\n",
     180                 :            :                                         ue.ino, ue.shutdown, peer->sd.ino, peer->shutdown);
     181                 :          0 :                         goto err;
     182                 :            :                 }
     183         [ +  + ]:         14 :         } else if (ue.state == TCP_ESTABLISHED) {
     184                 :            :                 const struct unix_sk_listen_icon *e;
     185                 :            : 
     186                 :            :                 /*
     187                 :            :                  * If this is in-flight connection we need to figure
     188                 :            :                  * out where to connect it on restore. Thus, tune up peer
     189                 :            :                  * id by searching an existing listening socket.
     190                 :            :                  *
     191                 :            :                  * Note the socket name will be found at restore stage,
     192                 :            :                  * not now, just to reduce size of dump files.
     193                 :            :                  */
     194                 :            : 
     195                 :          4 :                 e = lookup_unix_listen_icons(ue.ino);
     196         [ -  + ]:          2 :                 if (!e) {
     197                 :          0 :                         pr_err("Dangling in-flight connection %d\n", ue.ino);
     198                 :          0 :                         goto err;
     199                 :            :                 }
     200                 :            : 
     201                 :            :                 /* e->sk_desc is _never_ NULL */
     202         [ -  + ]:          2 :                 if (e->sk_desc->state != TCP_LISTEN) {
     203                 :          0 :                         pr_err("In-flight connection on "
     204                 :            :                                 "non-listening socket %d\n", ue.ino);
     205                 :          0 :                         goto err;
     206                 :            :                 }
     207                 :            : 
     208                 :          2 :                 ue.peer = e->sk_desc->sd.ino;
     209                 :            : 
     210                 :          2 :                 pr_debug("\t\tFixed inflight socket %#x peer %#x)\n",
     211                 :            :                                 ue.ino, ue.peer);
     212                 :            :         }
     213                 :            : 
     214         [ +  - ]:         57 :         if (dump_socket_opts(lfd, &skopts))
     215                 :            :                 goto err;
     216                 :            : 
     217         [ +  - ]:         57 :         if (pb_write_one(fdset_fd(glob_fdset, CR_FD_UNIXSK), &ue, PB_UNIXSK))
     218                 :            :                 goto err;
     219                 :            : 
     220 [ +  + ][ +  + ]:         57 :         if (sk->rqlen != 0 && !(sk->type == SOCK_STREAM &&
     221                 :            :                                 sk->state == TCP_LISTEN))
     222         [ +  - ]:         10 :                 if (dump_sk_queue(lfd, ue.id))
     223                 :            :                         goto err;
     224                 :            : 
     225                 :         57 :         pr_info("Dumping unix socket at %d\n", p->fd);
     226                 :         57 :         show_one_unix("Dumping", sk);
     227                 :         57 :         show_one_unix_img("Dumped", &ue);
     228                 :         57 :         release_skopts(&skopts);
     229                 :            : 
     230                 :         57 :         list_del_init(&sk->list);
     231                 :         57 :         sk->sd.already_dumped = 1;
     232                 :            : 
     233                 :            :         return 0;
     234                 :            : 
     235                 :            : err:
     236                 :         57 :         release_skopts(&skopts);
     237                 :            :         return -1;
     238                 :            : }
     239                 :            : 
     240                 :            : static const struct fdtype_ops unix_dump_ops = {
     241                 :            :         .type           = FD_TYPES__UNIXSK,
     242                 :            :         .dump           = dump_one_unix_fd,
     243                 :            : };
     244                 :            : 
     245                 :         57 : int dump_one_unix(struct fd_parms *p, int lfd, const struct cr_fdset *set)
     246                 :            : {
     247                 :         57 :         return do_dump_gen_file(p, lfd, &unix_dump_ops, set);
     248                 :            : }
     249                 :            : 
     250                 :       4972 : static int unix_collect_one(const struct unix_diag_msg *m,
     251                 :            :                 struct rtattr **tb)
     252                 :            : {
     253                 :            :         struct unix_sk_desc *d;
     254                 :       4972 :         char *name = NULL;
     255                 :       4972 :         int ret = 0;
     256                 :            : 
     257         [ -  + ]:       4972 :         d = xzalloc(sizeof(*d));
     258         [ +  - ]:       4972 :         if (!d)
     259                 :            :                 return -1;
     260                 :            : 
     261                 :       4972 :         d->type       = m->udiag_type;
     262                 :       4972 :         d->state = m->udiag_state;
     263                 :       4972 :         INIT_LIST_HEAD(&d->list);
     264                 :            : 
     265         [ +  - ]:       4972 :         if (tb[UNIX_DIAG_SHUTDOWN])
     266                 :       4972 :                 d->shutdown = *(u8 *)RTA_DATA(tb[UNIX_DIAG_SHUTDOWN]);
     267                 :            :         else
     268         [ #  # ]:          0 :                 pr_err_once("No socket shutdown info\n");
     269                 :            : 
     270         [ +  + ]:       4972 :         if (tb[UNIX_DIAG_PEER])
     271                 :       3867 :                 d->peer_ino = *(int *)RTA_DATA(tb[UNIX_DIAG_PEER]);
     272                 :            : 
     273         [ +  + ]:       4972 :         if (tb[UNIX_DIAG_NAME]) {
     274                 :       2197 :                 int len         = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
     275                 :            : 
     276         [ -  + ]:       2197 :                 name = xmalloc(len + 1);
     277         [ +  - ]:       2197 :                 if (!name)
     278                 :            :                         goto err;
     279                 :            : 
     280                 :       2197 :                 memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
     281                 :       2197 :                 name[len] = '\0';
     282                 :            : 
     283         [ +  + ]:       2197 :                 if (name[0] != '\0') {
     284                 :            :                         struct unix_diag_vfs *uv;
     285                 :            :                         struct stat st;
     286                 :            :                         char rpath[PATH_MAX];
     287                 :            : 
     288         [ -  + ]:       2195 :                         if (name[0] != '/') {
     289                 :          0 :                                 pr_warn("Relative bind path '%s' "
     290                 :            :                                         "unsupported\n", name);
     291                 :            :                                 goto skip;
     292                 :            :                         }
     293                 :            : 
     294         [ -  + ]:       2195 :                         if (!tb[UNIX_DIAG_VFS]) {
     295                 :          0 :                                 pr_err("Bound socket w/o inode %d\n",
     296                 :            :                                                 m->udiag_ino);
     297                 :            :                                 goto skip;
     298                 :            :                         }
     299                 :            : 
     300                 :       2195 :                         uv = RTA_DATA(tb[UNIX_DIAG_VFS]);
     301                 :       2195 :                         snprintf(rpath, sizeof(rpath), ".%s", name);
     302         [ +  + ]:       2195 :                         if (fstatat(mntns_root, rpath, &st, 0)) {
     303                 :         24 :                                 pr_perror("Can't stat socket %d(%s)",
     304                 :            :                                                 m->udiag_ino, rpath);
     305                 :            :                                 goto skip;
     306                 :            :                         }
     307                 :            : 
     308 [ +  + ][ -  + ]:       2171 :                         if ((st.st_ino != uv->udiag_vfs_ino) ||
     309                 :       2081 :                             (st.st_dev != kdev_to_odev(uv->udiag_vfs_dev))) {
     310                 :         90 :                                 pr_info("unix: Dropping path for "
     311                 :            :                                                 "unlinked bound "
     312                 :            :                                                 "sk %#x.%#x real %#x.%#x\n",
     313                 :            :                                                 (int)st.st_dev,
     314                 :            :                                                 (int)st.st_ino,
     315                 :            :                                                 (int)uv->udiag_vfs_dev,
     316                 :            :                                                 (int)uv->udiag_vfs_ino);
     317                 :            :                                 /*
     318                 :            :                                  * When a socket is bound to unlinked file, we
     319                 :            :                                  * just drop his name, since noone will access
     320                 :            :                                  * it via one.
     321                 :            :                                  */
     322         [ +  - ]:       2195 :                                 xfree(name);
     323                 :            :                                 len = 0;
     324                 :            :                                 name = NULL;
     325                 :            :                         }
     326                 :            :                 }
     327                 :            : 
     328                 :       2173 :                 d->namelen = len;
     329                 :       2173 :                 d->name = name;
     330                 :            :         }
     331                 :            : 
     332         [ +  + ]:       4948 :         if (tb[UNIX_DIAG_ICONS]) {
     333                 :        632 :                 int len = RTA_PAYLOAD(tb[UNIX_DIAG_ICONS]);
     334                 :            :                 int i;
     335                 :            : 
     336         [ -  + ]:        632 :                 d->icons = xmalloc(len);
     337         [ +  - ]:        632 :                 if (!d->icons)
     338                 :            :                         goto err;
     339                 :            : 
     340                 :        632 :                 memcpy(d->icons, RTA_DATA(tb[UNIX_DIAG_ICONS]), len);
     341                 :        632 :                 d->nr_icons = len / sizeof(u32);
     342                 :            : 
     343                 :            :                 /*
     344                 :            :                  * Remember these sockets, we will need them
     345                 :            :                  * to fix up in-flight sockets peers.
     346                 :            :                  */
     347         [ +  + ]:        634 :                 for (i = 0; i < d->nr_icons; i++) {
     348                 :            :                         struct unix_sk_listen_icon *e, **chain;
     349                 :            :                         int n;
     350                 :            : 
     351         [ -  + ]:          2 :                         e = xzalloc(sizeof(*e));
     352         [ +  - ]:          2 :                         if (!e)
     353                 :            :                                 goto err;
     354                 :            : 
     355                 :          2 :                         n = d->icons[i];
     356                 :          2 :                         chain = &unix_listen_icons[n % SK_HASH_SIZE];
     357                 :          2 :                         e->next = *chain;
     358                 :          2 :                         *chain = e;
     359                 :            : 
     360                 :          2 :                         pr_debug("\t\tCollected icon %d\n", d->icons[i]);
     361                 :            : 
     362                 :          2 :                         e->peer_ino  = n;
     363                 :          2 :                         e->sk_desc   = d;
     364                 :            :                 }
     365                 :            : 
     366                 :            : 
     367                 :            :         }
     368                 :            : 
     369         [ +  - ]:       4948 :         if (tb[UNIX_DIAG_RQLEN]) {
     370                 :            :                 struct unix_diag_rqlen *rq;
     371                 :            : 
     372                 :       4948 :                 rq = (struct unix_diag_rqlen *)RTA_DATA(tb[UNIX_DIAG_RQLEN]);
     373                 :       4948 :                 d->rqlen = rq->udiag_rqueue;
     374                 :       4948 :                 d->wqlen = rq->udiag_wqueue;
     375                 :            :         }
     376                 :            : 
     377                 :       4948 :         sk_collect_one(m->udiag_ino, AF_UNIX, &d->sd);
     378                 :       4948 :         show_one_unix("Collected", d);
     379                 :            : 
     380                 :       4948 :         return 0;
     381                 :            : err:
     382                 :            :         ret = -1;
     383                 :            : skip:
     384         [ -  + ]:         24 :         xfree(d->icons);
     385         [ +  - ]:         24 :         xfree(name);
     386         [ +  - ]:         24 :         xfree(d);
     387                 :       4972 :         return ret;
     388                 :            : }
     389                 :            : 
     390                 :       4972 : int unix_receive_one(struct nlmsghdr *h, void *arg)
     391                 :            : {
     392                 :       4972 :         struct unix_diag_msg *m = NLMSG_DATA(h);
     393                 :            :         struct rtattr *tb[UNIX_DIAG_MAX+1];
     394                 :            : 
     395                 :       4972 :         parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr *)(m + 1),
     396                 :       4972 :                      h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
     397                 :            : 
     398                 :       4972 :         return unix_collect_one(m, tb);
     399                 :            : }
     400                 :            : 
     401                 :        166 : int fix_external_unix_sockets(void)
     402                 :            : {
     403                 :            :         struct unix_sk_desc *sk;
     404                 :            : 
     405                 :        166 :         pr_debug("Dumping external sockets\n");
     406                 :            : 
     407         [ +  + ]:        167 :         list_for_each_entry(sk, &unix_sockets, list) {
     408                 :          1 :                 UnixSkEntry e = UNIX_SK_ENTRY__INIT;
     409                 :          1 :                 FownEntry fown = FOWN_ENTRY__INIT;
     410                 :          1 :                 SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
     411                 :            : 
     412                 :          1 :                 show_one_unix("Dumping extern", sk);
     413                 :            : 
     414         [ -  + ]:          1 :                 BUG_ON(sk->sd.already_dumped);
     415                 :            : 
     416         [ -  + ]:          1 :                 if (!opts.ext_unix_sk) {
     417                 :          0 :                         show_one_unix("Runaway socket", sk);
     418                 :            :                         goto err;
     419                 :            :                 }
     420                 :            : 
     421         [ -  + ]:          1 :                 if (sk->type != SOCK_DGRAM) {
     422                 :          0 :                         show_one_unix("Ext stream not supported", sk);
     423                 :            :                         goto err;
     424                 :            :                 }
     425                 :            : 
     426                 :          1 :                 e.id            = fd_id_generate_special();
     427                 :          1 :                 e.ino           = sk->sd.ino;
     428                 :          1 :                 e.type          = SOCK_DGRAM;
     429                 :          1 :                 e.state         = TCP_LISTEN;
     430                 :          1 :                 e.name.data     = (void *)sk->name;
     431                 :          1 :                 e.name.len      = (size_t)sk->namelen;
     432                 :          1 :                 e.uflags        = USK_EXTERN;
     433                 :          1 :                 e.peer          = 0;
     434                 :          1 :                 e.fown          = &fown;
     435                 :          1 :                 e.opts          = &skopts;
     436                 :            : 
     437         [ +  - ]:          1 :                 if (pb_write_one(fdset_fd(glob_fdset, CR_FD_UNIXSK), &e, PB_UNIXSK))
     438                 :            :                         goto err;
     439                 :            : 
     440                 :          1 :                 show_one_unix_img("Dumped extern", &e);
     441                 :            :         }
     442                 :            : 
     443                 :            :         return 0;
     444                 :            : err:
     445                 :          0 :         return -1;
     446                 :            : }
     447                 :            : 
     448                 :            : struct unix_sk_info {
     449                 :            :         UnixSkEntry *ue;
     450                 :            :         struct list_head list;
     451                 :            :         char *name;
     452                 :            :         unsigned flags;
     453                 :            :         struct unix_sk_info *peer;
     454                 :            :         struct file_desc d;
     455                 :            :         futex_t bound;
     456                 :            : };
     457                 :            : 
     458                 :            : #define USK_PAIR_MASTER         0x1
     459                 :            : #define USK_PAIR_SLAVE          0x2
     460                 :            : 
     461                 :            : static struct unix_sk_info *find_unix_sk_by_ino(int ino)
     462                 :            : {
     463                 :            :         struct unix_sk_info *ui;
     464                 :            : 
     465         [ +  - ]:        179 :         list_for_each_entry(ui, &unix_sockets, list) {
     466         [ +  + ]:        179 :                 if (ui->ue->ino == ino)
     467                 :            :                         return ui;
     468                 :            :         }
     469                 :            : 
     470                 :            :         return NULL;
     471                 :            : }
     472                 :            : 
     473                 :          0 : void show_unixsk(int fd, struct cr_options *o)
     474                 :            : {
     475                 :          0 :         pb_show_plain_pretty(fd, PB_UNIXSK, "1:%#x 2:%#x 3:%d 4:%d 5:%d 6:%d 7:%d 8:%#x 11:S");
     476                 :          0 : }
     477                 :            : 
     478                 :         35 : static int shutdown_unix_sk(int sk, struct unix_sk_info *ui)
     479                 :            : {
     480                 :            :         int how;
     481                 :         35 :         UnixSkEntry *ue = ui->ue;
     482                 :            : 
     483 [ +  + ][ +  - ]:         35 :         if (!ue->has_shutdown || ue->shutdown == SK_SHUTDOWN__NONE)
     484                 :            :                 return 0;
     485                 :            : 
     486                 :         20 :         how = sk_decode_shutdown(ue->shutdown);
     487         [ -  + ]:         10 :         if (shutdown(sk, how)) {
     488                 :          0 :                 pr_perror("Can't shutdown unix socket");
     489                 :            :                 return -1;
     490                 :            :         }
     491                 :            : 
     492                 :         35 :         pr_debug("Socket %#x is shut down %d\n", ue->ino, how);
     493                 :            :         return 0;
     494                 :            : }
     495                 :            : 
     496                 :         57 : static int post_open_unix_sk(struct file_desc *d, int fd)
     497                 :            : {
     498                 :            :         struct unix_sk_info *ui;
     499                 :            :         struct unix_sk_info *peer;
     500                 :            :         struct sockaddr_un addr;
     501                 :            : 
     502                 :         57 :         ui = container_of(d, struct unix_sk_info, d);
     503         [ +  + ]:         57 :         if (ui->flags & (USK_PAIR_MASTER | USK_PAIR_SLAVE))
     504                 :            :                 return 0;
     505                 :            : 
     506                 :         21 :         peer = ui->peer;
     507                 :            : 
     508         [ +  + ]:         21 :         if (peer == NULL)
     509                 :            :                 return 0;
     510                 :            : 
     511                 :          9 :         pr_info("\tConnect %#x to %#x\n", ui->ue->ino, peer->ue->ino);
     512                 :            : 
     513                 :            :         /* Skip external sockets */
     514         [ +  + ]:          9 :         if (!list_empty(&peer->d.fd_info_head))
     515                 :          8 :                 futex_wait_while(&peer->bound, 0);
     516                 :            : 
     517                 :          9 :         memset(&addr, 0, sizeof(addr));
     518                 :          9 :         addr.sun_family = AF_UNIX;
     519                 :          9 :         memcpy(&addr.sun_path, peer->name, peer->ue->name.len);
     520                 :            : 
     521         [ -  + ]:          9 :         if (connect(fd, (struct sockaddr *)&addr,
     522                 :            :                                 sizeof(addr.sun_family) +
     523                 :          9 :                                 peer->ue->name.len) < 0) {
     524                 :          0 :                 pr_perror("Can't connect %#x socket", ui->ue->ino);
     525                 :            :                 return -1;
     526                 :            :         }
     527                 :            : 
     528         [ +  - ]:          9 :         if (restore_sk_queue(fd, peer->ue->id))
     529                 :            :                 return -1;
     530                 :            : 
     531         [ +  - ]:          9 :         if (rst_file_params(fd, ui->ue->fown, ui->ue->flags))
     532                 :            :                 return -1;
     533                 :            : 
     534         [ +  - ]:          9 :         if (restore_socket_opts(fd, ui->ue->opts))
     535                 :            :                 return -1;
     536                 :            : 
     537         [ +  - ]:         57 :         if (shutdown_unix_sk(fd, ui))
     538                 :            :                 return -1;
     539                 :            : 
     540                 :            :         return 0;
     541                 :            : }
     542                 :            : 
     543                 :         57 : static int bind_unix_sk(int sk, struct unix_sk_info *ui)
     544                 :            : {
     545                 :            :         struct sockaddr_un addr;
     546                 :            : 
     547         [ +  + ]:         57 :         if ((ui->ue->type == SOCK_STREAM) && (ui->ue->state == TCP_ESTABLISHED))
     548                 :            :                 /*
     549                 :            :                  * FIXME this can be done, but for doing this properly we
     550                 :            :                  * need to bind socket to its name, then rename one to
     551                 :            :                  * some temporary unique one and after all the sockets are
     552                 :            :                  * restored we should walk those temp names and rename
     553                 :            :                  * some of them back to real ones.
     554                 :            :                  */
     555                 :            :                 goto done;
     556                 :            : 
     557                 :         35 :         memset(&addr, 0, sizeof(addr));
     558                 :         35 :         addr.sun_family = AF_UNIX;
     559                 :         35 :         memcpy(&addr.sun_path, ui->name, ui->ue->name.len);
     560                 :            : 
     561         [ -  + ]:         35 :         if (bind(sk, (struct sockaddr *)&addr,
     562                 :         35 :                                 sizeof(addr.sun_family) + ui->ue->name.len)) {
     563                 :          0 :                 pr_perror("Can't bind socket");
     564                 :            :                 return -1;
     565                 :            :         }
     566                 :            : 
     567                 :         57 :         futex_set_and_wake(&ui->bound, 1);
     568                 :            : done:
     569                 :            :         return 0;
     570                 :            : }
     571                 :            : 
     572                 :         57 : static int unixsk_should_open_transport(FdinfoEntry *fe,
     573                 :            :                                 struct file_desc *d)
     574                 :            : {
     575                 :            :         struct unix_sk_info *ui;
     576                 :            : 
     577                 :         57 :         ui = container_of(d, struct unix_sk_info, d);
     578                 :         57 :         return ui->flags & USK_PAIR_SLAVE;
     579                 :            : }
     580                 :            : 
     581                 :         18 : static int open_unixsk_pair_master(struct unix_sk_info *ui)
     582                 :            : {
     583                 :            :         int sk[2], tsk;
     584                 :         18 :         struct unix_sk_info *peer = ui->peer;
     585                 :            :         struct fdinfo_list_entry *fle;
     586                 :            : 
     587                 :         18 :         pr_info("Opening pair master (id %#x ino %#x peer %#x)\n",
     588                 :            :                         ui->ue->id, ui->ue->ino, ui->ue->peer);
     589                 :            : 
     590         [ -  + ]:         18 :         if (socketpair(PF_UNIX, ui->ue->type, 0, sk) < 0) {
     591                 :          0 :                 pr_perror("Can't make socketpair");
     592                 :            :                 return -1;
     593                 :            :         }
     594                 :            : 
     595         [ +  - ]:         18 :         if (restore_sk_queue(sk[0], peer->ue->id))
     596                 :            :                 return -1;
     597         [ +  - ]:         18 :         if (restore_sk_queue(sk[1], ui->ue->id))
     598                 :            :                 return -1;
     599                 :            : 
     600         [ +  - ]:         18 :         if (bind_unix_sk(sk[0], ui))
     601                 :            :                 return -1;
     602                 :            : 
     603         [ +  - ]:         18 :         if (rst_file_params(sk[0], ui->ue->fown, ui->ue->flags))
     604                 :            :                 return -1;
     605                 :            : 
     606         [ +  - ]:         18 :         if (restore_socket_opts(sk[0], ui->ue->opts))
     607                 :            :                 return -1;
     608                 :            : 
     609         [ +  - ]:         18 :         if (shutdown_unix_sk(sk[0], ui))
     610                 :            :                 return -1;
     611                 :            : 
     612                 :         18 :         tsk = socket(PF_UNIX, SOCK_DGRAM, 0);
     613         [ -  + ]:         18 :         if (tsk < 0) {
     614                 :          0 :                 pr_perror("Can't make transport socket");
     615                 :            :                 return -1;
     616                 :            :         }
     617                 :            : 
     618                 :         18 :         fle = file_master(&peer->d);
     619         [ -  + ]:         18 :         if (send_fd_to_peer(sk[1], fle, tsk)) {
     620                 :          0 :                 pr_err("Can't send pair slave\n");
     621                 :            :                 return -1;
     622                 :            :         }
     623                 :            : 
     624                 :         18 :         close(tsk);
     625                 :         18 :         close(sk[1]);
     626                 :            : 
     627                 :         18 :         return sk[0];
     628                 :            : }
     629                 :            : 
     630                 :         18 : static int open_unixsk_pair_slave(struct unix_sk_info *ui)
     631                 :            : {
     632                 :            :         struct fdinfo_list_entry *fle;
     633                 :            :         int sk;
     634                 :            : 
     635                 :         18 :         fle = file_master(&ui->d);
     636                 :            : 
     637                 :         18 :         pr_info("Opening pair slave (id %#x ino %#x peer %#x) on %d\n",
     638                 :            :                         ui->ue->id, ui->ue->ino, ui->ue->peer, fle->fe->fd);
     639                 :            : 
     640                 :         18 :         sk = recv_fd(fle->fe->fd);
     641         [ -  + ]:         18 :         if (sk < 0) {
     642                 :          0 :                 pr_err("Can't recv pair slave");
     643                 :          0 :                 return -1;
     644                 :            :         }
     645                 :         18 :         close(fle->fe->fd);
     646                 :            : 
     647         [ +  - ]:         18 :         if (bind_unix_sk(sk, ui))
     648                 :            :                 return -1;
     649                 :            : 
     650         [ +  - ]:         18 :         if (rst_file_params(sk, ui->ue->fown, ui->ue->flags))
     651                 :            :                 return -1;
     652                 :            : 
     653         [ +  - ]:         18 :         if (restore_socket_opts(sk, ui->ue->opts))
     654                 :            :                 return -1;
     655                 :            : 
     656         [ +  + ]:         18 :         if (ui->ue->type == SOCK_DGRAM)
     657                 :            :                 /*
     658                 :            :                  * Stream socket's "slave" end will be shut down
     659                 :            :                  * together with master
     660                 :            :                  */
     661         [ +  - ]:          8 :                 if (shutdown_unix_sk(sk, ui))
     662                 :            :                         return -1;
     663                 :            : 
     664                 :         18 :         return sk;
     665                 :            : }
     666                 :            : 
     667                 :         21 : static int open_unixsk_standalone(struct unix_sk_info *ui)
     668                 :            : {
     669                 :            :         int sk;
     670                 :            : 
     671                 :         21 :         pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n",
     672                 :            :                         ui->ue->id, ui->ue->ino, ui->ue->peer);
     673                 :            : 
     674                 :         21 :         sk = socket(PF_UNIX, ui->ue->type, 0);
     675         [ -  + ]:         21 :         if (sk < 0) {
     676                 :          0 :                 pr_perror("Can't make unix socket");
     677                 :          0 :                 return -1;
     678                 :            :         }
     679                 :            : 
     680         [ +  - ]:         21 :         if (bind_unix_sk(sk, ui))
     681                 :            :                 return -1;
     682                 :            : 
     683         [ +  + ]:         21 :         if (ui->ue->state == TCP_LISTEN) {
     684                 :          2 :                 pr_info("\tPutting %#x into listen state\n", ui->ue->ino);
     685         [ -  + ]:          2 :                 if (listen(sk, ui->ue->backlog) < 0) {
     686                 :          0 :                         pr_perror("Can't make usk listen");
     687                 :          0 :                         return -1;
     688                 :            :                 }
     689                 :            :         }
     690                 :            : 
     691         [ +  - ]:         21 :         if (rst_file_params(sk, ui->ue->fown, ui->ue->flags))
     692                 :            :                 return -1;
     693                 :            : 
     694         [ +  - ]:         21 :         if (restore_socket_opts(sk, ui->ue->opts))
     695                 :            :                 return -1;
     696                 :            : 
     697                 :         21 :         return sk;
     698                 :            : }
     699                 :            : 
     700                 :         57 : static int open_unix_sk(struct file_desc *d)
     701                 :            : {
     702                 :            :         struct unix_sk_info *ui;
     703                 :            : 
     704                 :         57 :         ui = container_of(d, struct unix_sk_info, d);
     705         [ +  + ]:         57 :         if (ui->flags & USK_PAIR_MASTER)
     706                 :         18 :                 return open_unixsk_pair_master(ui);
     707         [ +  + ]:         39 :         else if (ui->flags & USK_PAIR_SLAVE)
     708                 :         18 :                 return open_unixsk_pair_slave(ui);
     709                 :            :         else
     710                 :         57 :                 return open_unixsk_standalone(ui);
     711                 :            : }
     712                 :            : 
     713                 :            : static struct file_desc_ops unix_desc_ops = {
     714                 :            :         .type = FD_TYPES__UNIXSK,
     715                 :            :         .open = open_unix_sk,
     716                 :            :         .post_open = post_open_unix_sk,
     717                 :            :         .want_transport = unixsk_should_open_transport,
     718                 :            : };
     719                 :            : 
     720                 :         86 : static int collect_one_unixsk(void *o, ProtobufCMessage *base)
     721                 :            : {
     722                 :         86 :         struct unix_sk_info *ui = o;
     723                 :            : 
     724                 :         86 :         ui->ue = pb_msg(base, UnixSkEntry);
     725                 :            : 
     726         [ +  + ]:         86 :         if (ui->ue->name.len) {
     727         [ -  + ]:         19 :                 if (ui->ue->name.len >= UNIX_PATH_MAX) {
     728                 :          0 :                         pr_err("Bad unix name len %d\n", (int)ui->ue->name.len);
     729                 :          0 :                         return -1;
     730                 :            :                 }
     731                 :            : 
     732                 :         19 :                 ui->name = (void *)ui->ue->name.data;
     733                 :            : 
     734                 :            :                 /*
     735                 :            :                  * Make FS clean from sockets we're about to
     736                 :            :                  * restore. See for how we bind them for details
     737                 :            :                  */
     738 [ +  + ][ +  + ]:         19 :                 if (ui->name[0] != '\0' &&
     739                 :         16 :                                 !(ui->ue->uflags & USK_EXTERN))
     740                 :         15 :                         unlink(ui->name);
     741                 :            :         } else
     742                 :         67 :                 ui->name = NULL;
     743                 :            : 
     744                 :         86 :         futex_init(&ui->bound);
     745                 :         86 :         ui->peer = NULL;
     746                 :         86 :         ui->flags = 0;
     747                 :         86 :         pr_info(" `- Got %#x peer %#x\n", ui->ue->ino, ui->ue->peer);
     748                 :         86 :         file_desc_add(&ui->d, ui->ue->id, &unix_desc_ops);
     749                 :         86 :         list_add_tail(&ui->list, &unix_sockets);
     750                 :            : 
     751                 :         86 :         return 0;
     752                 :            : }
     753                 :            : 
     754                 :        355 : int collect_unix_sockets(void)
     755                 :            : {
     756                 :            :         int ret;
     757                 :            : 
     758                 :        355 :         pr_info("Reading unix sockets in\n");
     759                 :            : 
     760                 :        355 :         ret = collect_image_sh(CR_FD_UNIXSK, PB_UNIXSK,
     761                 :            :                         sizeof(struct unix_sk_info), collect_one_unixsk);
     762         [ +  - ]:        355 :         if (!ret)
     763                 :        355 :                 ret = read_sk_queues();
     764                 :            : 
     765                 :        355 :         return 0;
     766                 :            : }
     767                 :            : 
     768                 :        355 : int resolve_unix_peers(void)
     769                 :            : {
     770                 :            :         struct unix_sk_info *ui, *peer;
     771                 :            :         struct fdinfo_list_entry *fle, *fle_peer;
     772                 :            : 
     773         [ +  + ]:        441 :         list_for_each_entry(ui, &unix_sockets, list) {
     774         [ +  + ]:         86 :                 if (ui->peer)
     775                 :         27 :                         continue;
     776         [ +  + ]:         59 :                 if (!ui->ue->peer)
     777                 :         19 :                         continue;
     778                 :            : 
     779                 :         80 :                 peer = find_unix_sk_by_ino(ui->ue->peer);
     780                 :            : 
     781                 :            :                 /*
     782                 :            :                  * Connect to external sockets requires
     783                 :            :                  * special option to be passed.
     784                 :            :                  */
     785 [ +  - ][ +  + ]:         40 :                 if (peer &&
     786         [ -  + ]:          1 :                     (peer->ue->uflags & USK_EXTERN) &&
     787                 :          1 :                     !(opts.ext_unix_sk))
     788                 :          0 :                         peer = NULL;
     789                 :            : 
     790         [ -  + ]:         40 :                 if (!peer) {
     791                 :          0 :                         pr_err("FATAL: Peer %#x unresolved for %#x\n",
     792                 :            :                                         ui->ue->peer, ui->ue->ino);
     793                 :          0 :                         return -1;
     794                 :            :                 }
     795                 :            : 
     796                 :         40 :                 ui->peer = peer;
     797         [ +  + ]:         40 :                 if (ui == peer)
     798                 :            :                         /* socket connected to self %) */
     799                 :          3 :                         continue;
     800         [ +  + ]:         37 :                 if (peer->ue->peer != ui->ue->ino)
     801                 :         10 :                         continue;
     802                 :            : 
     803                 :            :                 /* socketpair or interconnected sockets */
     804                 :         27 :                 peer->peer = ui;
     805                 :            : 
     806                 :            :                 /*
     807                 :            :                  * Select who will restore the pair. Check is identical to
     808                 :            :                  * the one in pipes.c and makes sure tasks wait for each other
     809                 :            :                  * in pids sorting order (ascending).
     810                 :            :                  */
     811                 :            : 
     812                 :         27 :                 fle = file_master(&ui->d);
     813                 :         27 :                 fle_peer = file_master(&peer->d);
     814                 :            : 
     815         [ +  - ]:         27 :                 if (fdinfo_rst_prio(fle, fle_peer)) {
     816                 :         27 :                         ui->flags |= USK_PAIR_MASTER;
     817                 :         27 :                         peer->flags |= USK_PAIR_SLAVE;
     818                 :            :                 } else {
     819                 :          0 :                         peer->flags |= USK_PAIR_MASTER;
     820                 :          0 :                         ui->flags |= USK_PAIR_SLAVE;
     821                 :            :                 }
     822                 :            :         }
     823                 :            : 
     824                 :        355 :         pr_info("Unix sockets:\n");
     825         [ +  + ]:        441 :         list_for_each_entry(ui, &unix_sockets, list) {
     826                 :            :                 struct fdinfo_list_entry *fle;
     827                 :            : 
     828         [ +  + ]:         86 :                 pr_info("\t%#x -> %#x (%#x) flags %#x\n", ui->ue->ino, ui->ue->peer,
     829                 :            :                                 ui->peer ? ui->peer->ue->ino : 0, ui->flags);
     830         [ +  + ]:        171 :                 list_for_each_entry(fle, &ui->d.fd_info_head, desc_list)
     831                 :         85 :                         pr_info("\t\tfd %d in pid %d\n",
     832                 :            :                                         fle->fe->fd, fle->pid);
     833                 :            : 
     834                 :            :         }
     835                 :            : 
     836                 :            :         return 0;
     837                 :        195 : }
     838                 :            : 

Generated by: LCOV version 1.9