LCOV - code coverage report
Current view: top level - strace_git - pathtrace.c (source / functions) Hit Total Coverage
Test: strace-4.16.0.69.f1ea-dirty Code Coverage Lines: 44 104 42.3 %
Date: 2017-03-18 00:38:52 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 27 106 25.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2011, Comtrol Corp.
       3                 :            :  * All rights reserved.
       4                 :            :  *
       5                 :            :  * Redistribution and use in source and binary forms, with or without
       6                 :            :  * modification, are permitted provided that the following conditions
       7                 :            :  * are met:
       8                 :            :  * 1. Redistributions of source code must retain the above copyright
       9                 :            :  *    notice, this list of conditions and the following disclaimer.
      10                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      11                 :            :  *    notice, this list of conditions and the following disclaimer in the
      12                 :            :  *    documentation and/or other materials provided with the distribution.
      13                 :            :  * 3. The name of the author may not be used to endorse or promote products
      14                 :            :  *    derived from this software without specific prior written permission.
      15                 :            :  *
      16                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      17                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      18                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      19                 :            :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      20                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      21                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      22                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      23                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      24                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      25                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26                 :            :  *
      27                 :            :  */
      28                 :            : 
      29                 :            : #include "defs.h"
      30                 :            : #include <sys/param.h>
      31                 :            : #include <poll.h>
      32                 :            : 
      33                 :            : #include "syscall.h"
      34                 :            : 
      35                 :            : const char **paths_selected = NULL;
      36                 :            : static unsigned num_selected = 0;
      37                 :            : 
      38                 :            : /*
      39                 :            :  * Return true if specified path matches one that we're tracing.
      40                 :            :  */
      41                 :            : static int
      42                 :      16062 : pathmatch(const char *path)
      43                 :            : {
      44                 :            :         unsigned i;
      45                 :            : 
      46         [ +  + ]:      70773 :         for (i = 0; i < num_selected; ++i) {
      47         [ +  + ]:      55738 :                 if (strcmp(path, paths_selected[i]) == 0)
      48                 :       1027 :                         return 1;
      49                 :            :         }
      50                 :      15035 :         return 0;
      51                 :            : }
      52                 :            : 
      53                 :            : /*
      54                 :            :  * Return true if specified path (in user-space) matches.
      55                 :            :  */
      56                 :            : static int
      57                 :       1556 : upathmatch(struct tcb *const tcp, const kernel_ulong_t upath)
      58                 :            : {
      59                 :            :         char path[PATH_MAX + 1];
      60                 :            : 
      61   [ +  -  +  + ]:       3112 :         return umovestr(tcp, upath, sizeof path, path) > 0 &&
      62                 :       1556 :                 pathmatch(path);
      63                 :            : }
      64                 :            : 
      65                 :            : /*
      66                 :            :  * Return true if specified fd maps to a path we're tracing.
      67                 :            :  */
      68                 :            : static int
      69                 :      14421 : fdmatch(struct tcb *tcp, int fd)
      70                 :            : {
      71                 :            :         char path[PATH_MAX + 1];
      72                 :      14421 :         int n = getfdpath(tcp, fd, path, sizeof(path));
      73                 :            : 
      74 [ +  + ][ +  + ]:      14421 :         return n >= 0 && pathmatch(path);
      75                 :            : }
      76                 :            : 
      77                 :            : /*
      78                 :            :  * Add a path to the set we're tracing.
      79                 :            :  * Specifying NULL will delete all paths.
      80                 :            :  */
      81                 :            : static void
      82                 :        136 : storepath(const char *path)
      83                 :            : {
      84                 :            :         unsigned i;
      85                 :            : 
      86         [ -  + ]:        136 :         if (pathmatch(path))
      87                 :          0 :                 return; /* already in table */
      88                 :            : 
      89                 :        136 :         i = num_selected++;
      90                 :        136 :         paths_selected = xreallocarray(paths_selected, num_selected,
      91                 :            :                                        sizeof(paths_selected[0]));
      92                 :        136 :         paths_selected[i] = path;
      93                 :            : }
      94                 :            : 
      95                 :            : /*
      96                 :            :  * Get path associated with fd.
      97                 :            :  */
      98                 :            : int
      99                 :      14979 : getfdpath(struct tcb *tcp, int fd, char *buf, unsigned bufsize)
     100                 :            : {
     101                 :            :         char linkpath[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
     102                 :            :         ssize_t n;
     103                 :            : 
     104         [ +  + ]:      14979 :         if (fd < 0)
     105                 :         51 :                 return -1;
     106                 :            : 
     107                 :      14928 :         sprintf(linkpath, "/proc/%u/fd/%u", tcp->pid, fd);
     108                 :      14928 :         n = readlink(linkpath, buf, bufsize - 1);
     109                 :            :         /*
     110                 :            :          * NB: if buf is too small, readlink doesn't fail,
     111                 :            :          * it returns truncated result (IOW: n == bufsize - 1).
     112                 :            :          */
     113         [ +  - ]:      14928 :         if (n >= 0)
     114                 :      14928 :                 buf[n] = '\0';
     115                 :      14979 :         return n;
     116                 :            : }
     117                 :            : 
     118                 :            : /*
     119                 :            :  * Add a path to the set we're tracing.  Also add the canonicalized
     120                 :            :  * version of the path.  Secifying NULL will delete all paths.
     121                 :            :  */
     122                 :            : void
     123                 :        116 : pathtrace_select(const char *path)
     124                 :            : {
     125                 :            :         char *rpath;
     126                 :            : 
     127                 :        116 :         storepath(path);
     128                 :            : 
     129                 :        116 :         rpath = realpath(path, NULL);
     130                 :            : 
     131         [ +  + ]:        116 :         if (rpath == NULL)
     132                 :         45 :                 return;
     133                 :            : 
     134                 :            :         /* if realpath and specified path are same, we're done */
     135         [ +  + ]:         71 :         if (strcmp(path, rpath) == 0) {
     136                 :         51 :                 free(rpath);
     137                 :         51 :                 return;
     138                 :            :         }
     139                 :            : 
     140                 :         20 :         error_msg("Requested path '%s' resolved into '%s'", path, rpath);
     141                 :         20 :         storepath(rpath);
     142                 :            : }
     143                 :            : 
     144                 :            : /*
     145                 :            :  * Return true if syscall accesses a selected path
     146                 :            :  * (or if no paths have been specified for tracing).
     147                 :            :  */
     148                 :            : int
     149                 :      15926 : pathtrace_match(struct tcb *tcp)
     150                 :            : {
     151                 :            :         const struct_sysent *s;
     152                 :            : 
     153                 :      15926 :         s = tcp->s_ent;
     154                 :            : 
     155         [ -  + ]:      15926 :         if (!(s->sys_flags & (TRACE_FILE | TRACE_DESC | TRACE_NETWORK)))
     156                 :          0 :                 return 0;
     157                 :            : 
     158                 :            :         /*
     159                 :            :          * Check for special cases where we need to do something
     160                 :            :          * other than test arg[0].
     161                 :            :          */
     162                 :            : 
     163   [ -  +  -  -  :      15926 :         switch (s->sen) {
          -  -  -  -  -  
             -  -  -  -  
                      + ]
     164                 :            :         case SEN_dup2:
     165                 :            :         case SEN_dup3:
     166                 :            :         case SEN_kexec_file_load:
     167                 :            :         case SEN_sendfile:
     168                 :            :         case SEN_sendfile64:
     169                 :            :         case SEN_tee:
     170                 :            :                 /* fd, fd */
     171   [ #  #  #  # ]:          0 :                 return fdmatch(tcp, tcp->u_arg[0]) ||
     172                 :          0 :                         fdmatch(tcp, tcp->u_arg[1]);
     173                 :            : 
     174                 :            :         case SEN_faccessat:
     175                 :            :         case SEN_fchmodat:
     176                 :            :         case SEN_fchownat:
     177                 :            :         case SEN_fstatat64:
     178                 :            :         case SEN_futimesat:
     179                 :            :         case SEN_inotify_add_watch:
     180                 :            :         case SEN_mkdirat:
     181                 :            :         case SEN_mknodat:
     182                 :            :         case SEN_name_to_handle_at:
     183                 :            :         case SEN_newfstatat:
     184                 :            :         case SEN_openat:
     185                 :            :         case SEN_readlinkat:
     186                 :            :         case SEN_statx:
     187                 :            :         case SEN_unlinkat:
     188                 :            :         case SEN_utimensat:
     189                 :            :                 /* fd, path */
     190   [ +  -  +  - ]:        102 :                 return fdmatch(tcp, tcp->u_arg[0]) ||
     191                 :         51 :                         upathmatch(tcp, tcp->u_arg[1]);
     192                 :            : 
     193                 :            :         case SEN_link:
     194                 :            :         case SEN_mount:
     195                 :            :         case SEN_pivotroot:
     196                 :            :                 /* path, path */
     197   [ #  #  #  # ]:          0 :                 return upathmatch(tcp, tcp->u_arg[0]) ||
     198                 :          0 :                         upathmatch(tcp, tcp->u_arg[1]);
     199                 :            : 
     200                 :            :         case SEN_quotactl:
     201                 :            :                 /* x, path */
     202                 :          0 :                 return upathmatch(tcp, tcp->u_arg[1]);
     203                 :            : 
     204                 :            :         case SEN_linkat:
     205                 :            :         case SEN_renameat2:
     206                 :            :         case SEN_renameat:
     207                 :            :                 /* fd, path, fd, path */
     208         [ #  # ]:          0 :                 return fdmatch(tcp, tcp->u_arg[0]) ||
     209         [ #  # ]:          0 :                         fdmatch(tcp, tcp->u_arg[2]) ||
     210 [ #  # ][ #  # ]:          0 :                         upathmatch(tcp, tcp->u_arg[1]) ||
     211                 :          0 :                         upathmatch(tcp, tcp->u_arg[3]);
     212                 :            : 
     213                 :            :         case SEN_old_mmap:
     214                 :            : #if defined(S390)
     215                 :            :         case SEN_old_mmap_pgoff:
     216                 :            : #endif
     217                 :            :         case SEN_mmap:
     218                 :            :         case SEN_mmap_4koff:
     219                 :            :         case SEN_mmap_pgoff:
     220                 :            :         case SEN_ARCH_mmap:
     221                 :            :                 /* x, x, x, x, fd */
     222                 :          0 :                 return fdmatch(tcp, tcp->u_arg[4]);
     223                 :            : 
     224                 :            :         case SEN_symlinkat:
     225                 :            :                 /* path, fd, path */
     226         [ #  # ]:          0 :                 return fdmatch(tcp, tcp->u_arg[1]) ||
     227 [ #  # ][ #  # ]:          0 :                         upathmatch(tcp, tcp->u_arg[0]) ||
     228                 :          0 :                         upathmatch(tcp, tcp->u_arg[2]);
     229                 :            : 
     230                 :            :         case SEN_copy_file_range:
     231                 :            :         case SEN_splice:
     232                 :            :                 /* fd, x, fd, x, x, x */
     233   [ #  #  #  # ]:          0 :                 return fdmatch(tcp, tcp->u_arg[0]) ||
     234                 :          0 :                         fdmatch(tcp, tcp->u_arg[2]);
     235                 :            : 
     236                 :            :         case SEN_epoll_ctl:
     237                 :            :                 /* x, x, fd, x */
     238                 :          0 :                 return fdmatch(tcp, tcp->u_arg[2]);
     239                 :            : 
     240                 :            : 
     241                 :            :         case SEN_fanotify_mark:
     242                 :            :                 /* x, x, x, fd, path */
     243   [ #  #  #  # ]:          0 :                 return fdmatch(tcp, tcp->u_arg[3]) ||
     244                 :          0 :                         upathmatch(tcp, tcp->u_arg[4]);
     245                 :            : 
     246                 :            :         case SEN_oldselect:
     247                 :            :         case SEN_pselect6:
     248                 :            :         case SEN_select:
     249                 :            :         {
     250                 :            :                 int     i, j;
     251                 :            :                 int     nfds;
     252                 :            :                 kernel_ulong_t *args;
     253                 :            :                 kernel_ulong_t select_args[5];
     254                 :            :                 unsigned int oldselect_args[5];
     255                 :            :                 unsigned int fdsize;
     256                 :            :                 fd_set *fds;
     257                 :            : 
     258         [ #  # ]:          0 :                 if (SEN_oldselect == s->sen) {
     259                 :            :                         if (sizeof(*select_args) == sizeof(*oldselect_args)) {
     260                 :            :                                 if (umove(tcp, tcp->u_arg[0], &select_args)) {
     261                 :            :                                         return 0;
     262                 :            :                                 }
     263                 :            :                         } else {
     264                 :            :                                 unsigned int n;
     265                 :            : 
     266         [ #  # ]:          0 :                                 if (umove(tcp, tcp->u_arg[0], &oldselect_args)) {
     267                 :          0 :                                         return 0;
     268                 :            :                                 }
     269                 :            : 
     270         [ #  # ]:          0 :                                 for (n = 0; n < 5; ++n) {
     271                 :          0 :                                         select_args[n] = oldselect_args[n];
     272                 :            :                                 }
     273                 :            :                         }
     274                 :          0 :                         args = select_args;
     275                 :            :                 } else {
     276                 :          0 :                         args = tcp->u_arg;
     277                 :            :                 }
     278                 :            : 
     279                 :            :                 /* Kernel truncates arg[0] to int, we do the same. */
     280                 :          0 :                 nfds = (int) args[0];
     281                 :            :                 /* Kernel rejects negative nfds, so we don't parse it either. */
     282         [ #  # ]:          0 :                 if (nfds <= 0)
     283                 :          0 :                         return 0;
     284                 :            :                 /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */
     285         [ #  # ]:          0 :                 if (nfds > 1024*1024)
     286                 :          0 :                         nfds = 1024*1024;
     287                 :          0 :                 fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;
     288                 :          0 :                 fds = xmalloc(fdsize);
     289                 :            : 
     290         [ #  # ]:          0 :                 for (i = 1; i <= 3; ++i) {
     291         [ #  # ]:          0 :                         if (args[i] == 0)
     292                 :          0 :                                 continue;
     293         [ #  # ]:          0 :                         if (umoven(tcp, args[i], fdsize, fds) < 0) {
     294                 :          0 :                                 continue;
     295                 :            :                         }
     296                 :          0 :                         for (j = 0;; j++) {
     297                 :          0 :                                 j = next_set_bit(fds, j, nfds);
     298         [ #  # ]:          0 :                                 if (j < 0)
     299                 :          0 :                                         break;
     300         [ #  # ]:          0 :                                 if (fdmatch(tcp, j)) {
     301                 :          0 :                                         free(fds);
     302                 :          0 :                                         return 1;
     303                 :            :                                 }
     304                 :            :                         }
     305                 :            :                 }
     306                 :          0 :                 free(fds);
     307                 :          0 :                 return 0;
     308                 :            :         }
     309                 :            : 
     310                 :            :         case SEN_poll:
     311                 :            :         case SEN_ppoll:
     312                 :            :         {
     313                 :            :                 struct pollfd fds;
     314                 :            :                 unsigned nfds;
     315                 :            :                 kernel_ulong_t start, cur, end;
     316                 :            : 
     317                 :          0 :                 start = tcp->u_arg[0];
     318                 :          0 :                 nfds = tcp->u_arg[1];
     319                 :            : 
     320                 :          0 :                 end = start + sizeof(fds) * nfds;
     321                 :            : 
     322 [ #  # ][ #  # ]:          0 :                 if (nfds == 0 || end < start)
     323                 :          0 :                         return 0;
     324                 :            : 
     325         [ #  # ]:          0 :                 for (cur = start; cur < end; cur += sizeof(fds))
     326         [ #  # ]:          0 :                         if ((umove(tcp, cur, &fds) == 0)
     327         [ #  # ]:          0 :                             && fdmatch(tcp, fds.fd))
     328                 :          0 :                                 return 1;
     329                 :            : 
     330                 :          0 :                 return 0;
     331                 :            :         }
     332                 :            : 
     333                 :            :         case SEN_bpf:
     334                 :            :         case SEN_epoll_create:
     335                 :            :         case SEN_epoll_create1:
     336                 :            :         case SEN_eventfd2:
     337                 :            :         case SEN_eventfd:
     338                 :            :         case SEN_fanotify_init:
     339                 :            :         case SEN_inotify_init1:
     340                 :            :         case SEN_memfd_create:
     341                 :            :         case SEN_perf_event_open:
     342                 :            :         case SEN_pipe:
     343                 :            :         case SEN_pipe2:
     344                 :            :         case SEN_printargs:
     345                 :            :         case SEN_socket:
     346                 :            :         case SEN_socketpair:
     347                 :            :         case SEN_timerfd_create:
     348                 :            :         case SEN_timerfd_gettime:
     349                 :            :         case SEN_timerfd_settime:
     350                 :            :         case SEN_userfaultfd:
     351                 :            :                 /*
     352                 :            :                  * These have TRACE_FILE or TRACE_DESCRIPTOR or TRACE_NETWORK set,
     353                 :            :                  * but they don't have any file descriptor or path args to test.
     354                 :            :                  */
     355                 :          0 :                 return 0;
     356                 :            :         }
     357                 :            : 
     358                 :            :         /*
     359                 :            :          * Our fallback position for calls that haven't already
     360                 :            :          * been handled is to just check arg[0].
     361                 :            :          */
     362                 :            : 
     363         [ +  + ]:      15875 :         if (s->sys_flags & TRACE_FILE)
     364                 :       1505 :                 return upathmatch(tcp, tcp->u_arg[0]);
     365                 :            : 
     366         [ +  - ]:      14370 :         if (s->sys_flags & (TRACE_DESC | TRACE_NETWORK))
     367                 :      14370 :                 return fdmatch(tcp, tcp->u_arg[0]);
     368                 :            : 
     369                 :          0 :         return 0;
     370                 :            : }

Generated by: LCOV version 1.12