LCOV - code coverage report
Current view: top level - strace - pathtrace.c (source / functions) Hit Total Coverage
Test: strace-4.18.0.129.97bbb Code Coverage Lines: 41 93 44.1 %
Date: 2017-07-31 03:46:08 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 27 104 26.0 %

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

Generated by: LCOV version 1.11