LCOV - code coverage report
Current view: top level - lib - socket-util-unix.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 91 145 62.8 %
Date: 2016-09-14 01:02:56 Functions: 11 13 84.6 %
Branches: 48 104 46.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2014 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #include "socket-util.h"
      19                 :            : #include <errno.h>
      20                 :            : #include <fcntl.h>
      21                 :            : #include <net/if.h>
      22                 :            : #include <sys/ioctl.h>
      23                 :            : #include <sys/types.h>
      24                 :            : #include <sys/stat.h>
      25                 :            : #include <sys/un.h>
      26                 :            : #include <sys/wait.h>
      27                 :            : #include <unistd.h>
      28                 :            : #include "fatal-signal.h"
      29                 :            : #include "random.h"
      30                 :            : #include "util.h"
      31                 :            : #include "openvswitch/vlog.h"
      32                 :            : 
      33                 :      53956 : VLOG_DEFINE_THIS_MODULE(socket_util_unix);
      34                 :            : 
      35                 :            : /* #ifdefs make it a pain to maintain code: you have to try to build both ways.
      36                 :            :  * Thus, this file compiles all of the code regardless of the target, by
      37                 :            :  * writing "if (LINUX)" instead of "#ifdef __linux__". */
      38                 :            : #ifdef __linux__
      39                 :            : #define LINUX 1
      40                 :            : #else
      41                 :            : #define LINUX 0
      42                 :            : #endif
      43                 :            : 
      44                 :            : #ifndef O_DIRECTORY
      45                 :            : #define O_DIRECTORY 0
      46                 :            : #endif
      47                 :            : 
      48                 :            : /* Maximum length of the sun_path member in a struct sockaddr_un, excluding
      49                 :            :  * space for a null terminator. */
      50                 :            : #define MAX_UN_LEN (sizeof(((struct sockaddr_un *) 0)->sun_path) - 1)
      51                 :            : 
      52                 :            : void
      53                 :      33061 : xpipe(int fds[2])
      54                 :            : {
      55         [ -  + ]:      33061 :     if (pipe(fds)) {
      56                 :          0 :         VLOG_FATAL("failed to create pipe (%s)", ovs_strerror(errno));
      57                 :            :     }
      58                 :      33061 : }
      59                 :            : 
      60                 :            : void
      61                 :      30912 : xpipe_nonblocking(int fds[2])
      62                 :            : {
      63                 :      30912 :     xpipe(fds);
      64                 :      30912 :     xset_nonblocking(fds[0]);
      65                 :      30912 :     xset_nonblocking(fds[1]);
      66                 :      30912 : }
      67                 :            : 
      68                 :            : /* Drain all the data currently in the receive queue of a datagram socket (and
      69                 :            :  * possibly additional data).  There is no way to know how many packets are in
      70                 :            :  * the receive queue, but we do know that the total number of bytes queued does
      71                 :            :  * not exceed the receive buffer size, so we pull packets until none are left
      72                 :            :  * or we've read that many bytes. */
      73                 :            : int
      74                 :          0 : drain_rcvbuf(int fd)
      75                 :            : {
      76                 :            :     int rcvbuf;
      77                 :            : 
      78                 :          0 :     rcvbuf = get_socket_rcvbuf(fd);
      79         [ #  # ]:          0 :     if (rcvbuf < 0) {
      80                 :          0 :         return -rcvbuf;
      81                 :            :     }
      82                 :            : 
      83         [ #  # ]:          0 :     while (rcvbuf > 0) {
      84                 :            :         /* In Linux, specifying MSG_TRUNC in the flags argument causes the
      85                 :            :          * datagram length to be returned, even if that is longer than the
      86                 :            :          * buffer provided.  Thus, we can use a 1-byte buffer to discard the
      87                 :            :          * incoming datagram and still be able to account how many bytes were
      88                 :            :          * removed from the receive buffer.
      89                 :            :          *
      90                 :            :          * On other Unix-like OSes, MSG_TRUNC has no effect in the flags
      91                 :            :          * argument. */
      92                 :            :         char buffer[LINUX ? 1 : 2048];
      93                 :          0 :         ssize_t n_bytes = recv(fd, buffer, sizeof buffer,
      94                 :            :                                MSG_TRUNC | MSG_DONTWAIT);
      95 [ #  # ][ #  # ]:          0 :         if (n_bytes <= 0 || n_bytes >= rcvbuf) {
      96                 :            :             break;
      97                 :            :         }
      98                 :          0 :         rcvbuf -= n_bytes;
      99                 :            :     }
     100                 :          0 :     return 0;
     101                 :            : }
     102                 :            : 
     103                 :            : /* Attempts to shorten 'name' by opening a file descriptor for the directory
     104                 :            :  * part of the name and indirecting through /proc/self/fd/<dirfd>/<basename>.
     105                 :            :  * On systems with Linux-like /proc, this works as long as <basename> isn't too
     106                 :            :  * long.
     107                 :            :  *
     108                 :            :  * On success, returns 0 and stores the short name in 'short_name' and a
     109                 :            :  * directory file descriptor to eventually be closed in '*dirfpd'. */
     110                 :            : static int
     111                 :       7950 : shorten_name_via_proc(const char *name, char short_name[MAX_UN_LEN + 1],
     112                 :            :                       int *dirfdp)
     113                 :            : {
     114                 :            :     char *dir, *base;
     115                 :            :     int dirfd;
     116                 :            :     int len;
     117                 :            : 
     118                 :            :     if (!LINUX) {
     119                 :            :         return ENAMETOOLONG;
     120                 :            :     }
     121                 :            : 
     122                 :       3975 :     dir = dir_name(name);
     123                 :       3975 :     dirfd = open(dir, O_DIRECTORY | O_RDONLY);
     124         [ -  + ]:       3975 :     if (dirfd < 0) {
     125                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
     126                 :          0 :         int error = errno;
     127                 :            : 
     128         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "%s: open failed (%s)", dir, ovs_strerror(error));
     129                 :          0 :         free(dir);
     130                 :            : 
     131                 :          0 :         return error;
     132                 :            :     }
     133                 :       3975 :     free(dir);
     134                 :            : 
     135                 :       3975 :     base = base_name(name);
     136                 :       3975 :     len = snprintf(short_name, MAX_UN_LEN + 1,
     137                 :            :                    "/proc/self/fd/%d/%s", dirfd, base);
     138                 :       3975 :     free(base);
     139                 :            : 
     140 [ +  - ][ +  - ]:       3975 :     if (len >= 0 && len <= MAX_UN_LEN) {
     141                 :       3975 :         *dirfdp = dirfd;
     142                 :       3975 :         return 0;
     143                 :            :     } else {
     144                 :          0 :         close(dirfd);
     145                 :          0 :         return ENAMETOOLONG;
     146                 :            :     }
     147                 :            : }
     148                 :            : 
     149                 :            : /* Attempts to shorten 'name' by creating a symlink for the directory part of
     150                 :            :  * the name and indirecting through <symlink>/<basename>.  This works on
     151                 :            :  * systems that support symlinks, as long as <basename> isn't too long.
     152                 :            :  *
     153                 :            :  * On success, returns 0 and stores the short name in 'short_name' and the
     154                 :            :  * symbolic link to eventually delete in 'linkname'. */
     155                 :            : static int
     156                 :          0 : shorten_name_via_symlink(const char *name, char short_name[MAX_UN_LEN + 1],
     157                 :            :                          char linkname[MAX_UN_LEN + 1])
     158                 :            : {
     159                 :            :     char *abs, *dir, *base;
     160                 :            :     const char *tmpdir;
     161                 :            :     int error;
     162                 :            :     int i;
     163                 :            : 
     164                 :          0 :     abs = abs_file_name(NULL, name);
     165                 :          0 :     dir = dir_name(abs);
     166                 :          0 :     base = base_name(abs);
     167                 :          0 :     free(abs);
     168                 :            : 
     169                 :          0 :     tmpdir = getenv("TMPDIR");
     170         [ #  # ]:          0 :     if (tmpdir == NULL) {
     171                 :          0 :         tmpdir = "/tmp";
     172                 :            :     }
     173                 :            : 
     174         [ #  # ]:          0 :     for (i = 0; i < 1000; i++) {
     175                 :            :         int len;
     176                 :            : 
     177                 :          0 :         len = snprintf(linkname, MAX_UN_LEN + 1,
     178                 :            :                        "%s/ovs-un-c-%"PRIu32, tmpdir, random_uint32());
     179         [ #  # ]:          0 :         error = (len < 0 || len > MAX_UN_LEN ? ENAMETOOLONG
     180         [ #  # ]:          0 :                  : symlink(dir, linkname) ? errno
     181         [ #  # ]:          0 :                  : 0);
     182         [ #  # ]:          0 :         if (error != EEXIST) {
     183                 :          0 :             break;
     184                 :            :         }
     185                 :            :     }
     186                 :            : 
     187         [ #  # ]:          0 :     if (!error) {
     188                 :            :         int len;
     189                 :            : 
     190                 :          0 :         fatal_signal_add_file_to_unlink(linkname);
     191                 :            : 
     192                 :          0 :         len = snprintf(short_name, MAX_UN_LEN + 1, "%s/%s", linkname, base);
     193 [ #  # ][ #  # ]:          0 :         if (len < 0 || len > MAX_UN_LEN) {
     194                 :          0 :             fatal_signal_unlink_file_now(linkname);
     195                 :          0 :             error = ENAMETOOLONG;
     196                 :            :         }
     197                 :            :     }
     198                 :            : 
     199         [ #  # ]:          0 :     if (error) {
     200                 :          0 :         linkname[0] = '\0';
     201                 :            :     }
     202                 :          0 :     free(dir);
     203                 :          0 :     free(base);
     204                 :            : 
     205                 :          0 :     return error;
     206                 :            : }
     207                 :            : 
     208                 :            : /* Stores in '*un' a sockaddr_un that refers to file 'name'.  Stores in
     209                 :            :  * '*un_len' the size of the sockaddr_un.
     210                 :            :  *
     211                 :            :  * Returns 0 on success, otherwise a positive errno value.
     212                 :            :  *
     213                 :            :  * Uses '*dirfdp' and 'linkname' to store references to data when the caller no
     214                 :            :  * longer needs to use 'un'.  On success, freeing these references with
     215                 :            :  * free_sockaddr_un() is mandatory to avoid a leak; on failure, freeing them is
     216                 :            :  * unnecessary but harmless. */
     217                 :            : static int
     218                 :      30675 : make_sockaddr_un(const char *name, struct sockaddr_un *un, socklen_t *un_len,
     219                 :            :                  int *dirfdp, char linkname[MAX_UN_LEN + 1])
     220                 :            : {
     221                 :            :     char short_name[MAX_UN_LEN + 1];
     222                 :            : 
     223                 :      30675 :     *dirfdp = -1;
     224                 :      30675 :     linkname[0] = '\0';
     225         [ +  + ]:      30675 :     if (strlen(name) > MAX_UN_LEN) {
     226                 :            :         /* 'name' is too long to fit in a sockaddr_un.  Try a workaround. */
     227                 :       3975 :         int error = shorten_name_via_proc(name, short_name, dirfdp);
     228         [ -  + ]:       3975 :         if (error == ENAMETOOLONG) {
     229                 :          0 :             error = shorten_name_via_symlink(name, short_name, linkname);
     230                 :            :         }
     231         [ -  + ]:       3975 :         if (error) {
     232                 :            :             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
     233                 :            : 
     234         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "Unix socket name %s is longer than maximum "
     235                 :            :                          "%"PRIuSIZE" bytes", name, MAX_UN_LEN);
     236                 :          0 :             return error;
     237                 :            :         }
     238                 :            : 
     239                 :       3975 :         name = short_name;
     240                 :            :     }
     241                 :            : 
     242                 :      30675 :     un->sun_family = AF_UNIX;
     243                 :      30675 :     ovs_strzcpy(un->sun_path, name, sizeof un->sun_path);
     244                 :      30675 :     *un_len = (offsetof(struct sockaddr_un, sun_path)
     245                 :      30675 :                 + strlen (un->sun_path) + 1);
     246                 :      30675 :     return 0;
     247                 :            : }
     248                 :            : 
     249                 :            : /* Clean up after make_sockaddr_un(). */
     250                 :            : static void
     251                 :      30675 : free_sockaddr_un(int dirfd, const char *linkname)
     252                 :            : {
     253         [ +  + ]:      30675 :     if (dirfd >= 0) {
     254                 :       3975 :         close(dirfd);
     255                 :            :     }
     256         [ -  + ]:      30675 :     if (linkname[0]) {
     257                 :          0 :         fatal_signal_unlink_file_now(linkname);
     258                 :            :     }
     259                 :      30675 : }
     260                 :            : 
     261                 :            : /* Binds Unix domain socket 'fd' to a file with permissions 0700. */
     262                 :       4916 : static int bind_unix_socket(int fd, struct sockaddr *sun, socklen_t sun_len)
     263                 :            : {
     264                 :       4916 :     const mode_t mode = 0770;    /* Allow both user and group access. */
     265                 :            : 
     266                 :            :     if (LINUX) {
     267                 :            :         /* On Linux, the fd's permissions become the file's permissions.
     268                 :            :          * fchmod() does not affect other files, like umask() does. */
     269         [ -  + ]:       4916 :         if (fchmod(fd, mode)) {
     270                 :          0 :             return errno;
     271                 :            :         }
     272                 :            : 
     273                 :            :         /* Must be after fchmod(). */
     274         [ +  + ]:       4916 :         if (bind(fd, sun, sun_len)) {
     275                 :          2 :             return errno;
     276                 :            :         }
     277                 :       4914 :         return 0;
     278                 :            :     } else {
     279                 :            :         /* On FreeBSD and NetBSD, only the umask affects permissions.  The
     280                 :            :          * umask is process-wide rather than thread-specific, so we have to use
     281                 :            :          * a subprocess for safety. */
     282                 :            :         pid_t pid = fork();
     283                 :            : 
     284                 :            :         if (!pid) {
     285                 :            :             umask(mode ^ 0777);
     286                 :            :             _exit(bind(fd, sun, sun_len) ? errno : 0);
     287                 :            :         } else if (pid > 0) {
     288                 :            :             int status;
     289                 :            :             int error;
     290                 :            : 
     291                 :            :             do {
     292                 :            :                 error = waitpid(pid, &status, 0) < 0 ? errno : 0;
     293                 :            :             } while (error == EINTR);
     294                 :            : 
     295                 :            :             return (error ? error
     296                 :            :                     : WIFEXITED(status) ? WEXITSTATUS(status)
     297                 :            :                     : WIFSIGNALED(status) ? EINTR
     298                 :            :                     : ECHILD /* WTF? */);
     299                 :            :         } else {
     300                 :            :             return errno;
     301                 :            :         }
     302                 :            :     }
     303                 :            : }
     304                 :            : 
     305                 :            : /* Creates a Unix domain socket in the given 'style' (either SOCK_DGRAM or
     306                 :            :  * SOCK_STREAM) that is bound to '*bind_path' (if 'bind_path' is non-null) and
     307                 :            :  * connected to '*connect_path' (if 'connect_path' is non-null).  If 'nonblock'
     308                 :            :  * is true, the socket is made non-blocking.
     309                 :            :  *
     310                 :            :  * Returns the socket's fd if successful, otherwise a negative errno value. */
     311                 :            : int
     312                 :      30675 : make_unix_socket(int style, bool nonblock,
     313                 :            :                  const char *bind_path, const char *connect_path)
     314                 :            : {
     315                 :            :     int error;
     316                 :            :     int fd;
     317                 :            : 
     318                 :      30675 :     fd = socket(PF_UNIX, style, 0);
     319         [ -  + ]:      30675 :     if (fd < 0) {
     320                 :          0 :         return -errno;
     321                 :            :     }
     322                 :            : 
     323                 :            :     /* Set nonblocking mode right away, if we want it.  This prevents blocking
     324                 :            :      * in connect(), if connect_path != NULL.  (In turn, that's a corner case:
     325                 :            :      * it will only happen if style is SOCK_STREAM or SOCK_SEQPACKET, and only
     326                 :            :      * if a backlog of un-accepted connections has built up in the kernel.)  */
     327         [ +  + ]:      30675 :     if (nonblock) {
     328                 :      30671 :         error = set_nonblocking(fd);
     329         [ -  + ]:      30671 :         if (error) {
     330                 :          0 :             goto error;
     331                 :            :         }
     332                 :            :     }
     333                 :            : 
     334         [ +  + ]:      30675 :     if (bind_path) {
     335                 :            :         char linkname[MAX_UN_LEN + 1];
     336                 :            :         struct sockaddr_un un;
     337                 :            :         socklen_t un_len;
     338                 :            :         int dirfd;
     339                 :            : 
     340 [ +  - ][ -  + ]:       4916 :         if (unlink(bind_path) && errno != ENOENT) {
     341         [ #  # ]:          0 :             VLOG_WARN("unlinking \"%s\": %s\n",
     342                 :            :                       bind_path, ovs_strerror(errno));
     343                 :            :         }
     344                 :       4916 :         fatal_signal_add_file_to_unlink(bind_path);
     345                 :            : 
     346                 :       4916 :         error = make_sockaddr_un(bind_path, &un, &un_len, &dirfd, linkname);
     347         [ +  - ]:       4916 :         if (!error) {
     348                 :       4916 :             error = bind_unix_socket(fd, (struct sockaddr *) &un, un_len);
     349                 :            :         }
     350                 :       4916 :         free_sockaddr_un(dirfd, linkname);
     351                 :            : 
     352         [ +  + ]:       4916 :         if (error) {
     353                 :       4916 :             goto error;
     354                 :            :         }
     355                 :            :     }
     356                 :            : 
     357         [ +  + ]:      30673 :     if (connect_path) {
     358                 :            :         char linkname[MAX_UN_LEN + 1];
     359                 :            :         struct sockaddr_un un;
     360                 :            :         socklen_t un_len;
     361                 :            :         int dirfd;
     362                 :            : 
     363                 :      25759 :         error = make_sockaddr_un(connect_path, &un, &un_len, &dirfd, linkname);
     364         [ +  - ]:      25759 :         if (!error
     365         [ +  + ]:      25759 :             && connect(fd, (struct sockaddr*) &un, un_len)
     366         [ +  - ]:       3410 :             && errno != EINPROGRESS) {
     367                 :       3410 :             error = errno;
     368                 :            :         }
     369                 :      25759 :         free_sockaddr_un(dirfd, linkname);
     370                 :            : 
     371         [ +  + ]:      25759 :         if (error) {
     372                 :      25759 :             goto error;
     373                 :            :         }
     374                 :            :     }
     375                 :            : 
     376                 :      27263 :     return fd;
     377                 :            : 
     378                 :            : error:
     379         [ -  + ]:       3412 :     if (error == EAGAIN) {
     380                 :          0 :         error = EPROTO;
     381                 :            :     }
     382         [ +  + ]:       3412 :     if (bind_path) {
     383                 :          2 :         fatal_signal_unlink_file_now(bind_path);
     384                 :            :     }
     385                 :       3412 :     close(fd);
     386                 :       3412 :     return -error;
     387                 :            : }
     388                 :            : 
     389                 :            : int
     390                 :      21868 : get_unix_name_len(const struct sockaddr_un *sun, socklen_t sun_len)
     391                 :            : {
     392 [ +  - ][ +  + ]:      21868 :     return (sun_len >= offsetof(struct sockaddr_un, sun_path) &&
     393                 :      21868 :             sun->sun_path[0] != 0
     394                 :            :             ? sun_len - offsetof(struct sockaddr_un, sun_path)
     395                 :            :             : 0);
     396                 :            : }
     397                 :            : 
     398                 :            : /* Calls ioctl() on an AF_INET sock, passing the specified 'command' and
     399                 :            :  * 'arg'.  Returns 0 if successful, otherwise a positive errno value. */
     400                 :            : int
     401                 :      30534 : af_inet_ioctl(unsigned long int command, const void *arg)
     402                 :            : {
     403                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
     404                 :            :     static int sock;
     405                 :            : 
     406         [ +  + ]:      30534 :     if (ovsthread_once_start(&once)) {
     407                 :        602 :         sock = socket(AF_INET, SOCK_DGRAM, 0);
     408         [ -  + ]:        602 :         if (sock < 0) {
     409                 :          0 :             int error = sock_errno();
     410         [ #  # ]:          0 :             VLOG_ERR("failed to create inet socket: %s", sock_strerror(error));
     411                 :          0 :             sock = -error;
     412                 :            :         }
     413                 :        602 :         ovsthread_once_done(&once);
     414                 :            :     }
     415                 :            : 
     416                 :      30534 :     return (sock < 0 ? -sock
     417         [ -  + ]:      61150 :             : ioctl(sock, command, arg) == -1 ? errno
     418         [ +  + ]:      30616 :             : 0);
     419                 :            : }
     420                 :            : 
     421                 :            : int
     422                 :      26067 : af_inet_ifreq_ioctl(const char *name, struct ifreq *ifr, unsigned long int cmd,
     423                 :            :                     const char *cmd_name)
     424                 :            : {
     425                 :            :     int error;
     426                 :            : 
     427                 :      26067 :     ovs_strzcpy(ifr->ifr_name, name, sizeof ifr->ifr_name);
     428                 :      26067 :     error = af_inet_ioctl(cmd, ifr);
     429         [ +  + ]:      26067 :     if (error) {
     430                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
     431         [ -  + ]:         78 :         VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name,
     432                 :            :                     ovs_strerror(error));
     433                 :            :     }
     434                 :      26067 :     return error;
     435                 :            : }

Generated by: LCOV version 1.12