Home | History | Annotate | Download | only in strace
      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 const char **paths_selected;
     37 static unsigned int num_selected;
     38 
     39 /*
     40  * Return true if specified path matches one that we're tracing.
     41  */
     42 static int
     43 pathmatch(const char *path)
     44 {
     45 	unsigned i;
     46 
     47 	for (i = 0; i < num_selected; ++i) {
     48 		if (strcmp(path, paths_selected[i]) == 0)
     49 			return 1;
     50 	}
     51 	return 0;
     52 }
     53 
     54 /*
     55  * Return true if specified path (in user-space) matches.
     56  */
     57 static int
     58 upathmatch(struct tcb *const tcp, const kernel_ulong_t upath)
     59 {
     60 	char path[PATH_MAX + 1];
     61 
     62 	return umovestr(tcp, upath, sizeof(path), path) > 0 &&
     63 		pathmatch(path);
     64 }
     65 
     66 /*
     67  * Return true if specified fd maps to a path we're tracing.
     68  */
     69 static int
     70 fdmatch(struct tcb *tcp, int fd)
     71 {
     72 	char path[PATH_MAX + 1];
     73 	int n = getfdpath(tcp, fd, path, sizeof(path));
     74 
     75 	return n >= 0 && pathmatch(path);
     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 storepath(const char *path)
     84 {
     85 	unsigned i;
     86 
     87 	if (pathmatch(path))
     88 		return; /* already in table */
     89 
     90 	i = num_selected++;
     91 	paths_selected = xreallocarray(paths_selected, num_selected,
     92 				       sizeof(paths_selected[0]));
     93 	paths_selected[i] = path;
     94 }
     95 
     96 /*
     97  * Get path associated with fd.
     98  */
     99 int
    100 getfdpath(struct tcb *tcp, int fd, char *buf, unsigned bufsize)
    101 {
    102 	char linkpath[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
    103 	ssize_t n;
    104 
    105 	if (fd < 0)
    106 		return -1;
    107 
    108 	sprintf(linkpath, "/proc/%u/fd/%u", tcp->pid, fd);
    109 	n = readlink(linkpath, buf, bufsize - 1);
    110 	/*
    111 	 * NB: if buf is too small, readlink doesn't fail,
    112 	 * it returns truncated result (IOW: n == bufsize - 1).
    113 	 */
    114 	if (n >= 0)
    115 		buf[n] = '\0';
    116 	return n;
    117 }
    118 
    119 /*
    120  * Add a path to the set we're tracing.  Also add the canonicalized
    121  * version of the path.  Secifying NULL will delete all paths.
    122  */
    123 void
    124 pathtrace_select(const char *path)
    125 {
    126 	char *rpath;
    127 
    128 	storepath(path);
    129 
    130 	rpath = realpath(path, NULL);
    131 
    132 	if (rpath == NULL)
    133 		return;
    134 
    135 	/* if realpath and specified path are same, we're done */
    136 	if (strcmp(path, rpath) == 0) {
    137 		free(rpath);
    138 		return;
    139 	}
    140 
    141 	error_msg("Requested path '%s' resolved into '%s'", path, rpath);
    142 	storepath(rpath);
    143 }
    144 
    145 /*
    146  * Return true if syscall accesses a selected path
    147  * (or if no paths have been specified for tracing).
    148  */
    149 int
    150 pathtrace_match(struct tcb *tcp)
    151 {
    152 	const struct_sysent *s;
    153 
    154 	s = tcp->s_ent;
    155 
    156 	if (!(s->sys_flags & (TRACE_FILE | TRACE_DESC | TRACE_NETWORK)))
    157 		return 0;
    158 
    159 	/*
    160 	 * Check for special cases where we need to do something
    161 	 * other than test arg[0].
    162 	 */
    163 
    164 	switch (s->sen) {
    165 	case SEN_dup2:
    166 	case SEN_dup3:
    167 	case SEN_kexec_file_load:
    168 	case SEN_sendfile:
    169 	case SEN_sendfile64:
    170 	case SEN_tee:
    171 		/* fd, fd */
    172 		return fdmatch(tcp, tcp->u_arg[0]) ||
    173 			fdmatch(tcp, tcp->u_arg[1]);
    174 
    175 	case SEN_faccessat:
    176 	case SEN_fchmodat:
    177 	case SEN_fchownat:
    178 	case SEN_fstatat64:
    179 	case SEN_futimesat:
    180 	case SEN_inotify_add_watch:
    181 	case SEN_mkdirat:
    182 	case SEN_mknodat:
    183 	case SEN_name_to_handle_at:
    184 	case SEN_newfstatat:
    185 	case SEN_openat:
    186 	case SEN_readlinkat:
    187 	case SEN_statx:
    188 	case SEN_unlinkat:
    189 	case SEN_utimensat:
    190 		/* fd, path */
    191 		return fdmatch(tcp, tcp->u_arg[0]) ||
    192 			upathmatch(tcp, tcp->u_arg[1]);
    193 
    194 	case SEN_link:
    195 	case SEN_mount:
    196 	case SEN_pivotroot:
    197 		/* path, path */
    198 		return upathmatch(tcp, tcp->u_arg[0]) ||
    199 			upathmatch(tcp, tcp->u_arg[1]);
    200 
    201 	case SEN_quotactl:
    202 		/* x, path */
    203 		return upathmatch(tcp, tcp->u_arg[1]);
    204 
    205 	case SEN_linkat:
    206 	case SEN_renameat2:
    207 	case SEN_renameat:
    208 		/* fd, path, fd, path */
    209 		return fdmatch(tcp, tcp->u_arg[0]) ||
    210 			fdmatch(tcp, tcp->u_arg[2]) ||
    211 			upathmatch(tcp, tcp->u_arg[1]) ||
    212 			upathmatch(tcp, tcp->u_arg[3]);
    213 
    214 	case SEN_old_mmap:
    215 #if defined(S390)
    216 	case SEN_old_mmap_pgoff:
    217 #endif
    218 	case SEN_mmap:
    219 	case SEN_mmap_4koff:
    220 	case SEN_mmap_pgoff:
    221 	case SEN_ARCH_mmap:
    222 		/* x, x, x, x, fd */
    223 		return fdmatch(tcp, tcp->u_arg[4]);
    224 
    225 	case SEN_symlinkat:
    226 		/* path, fd, path */
    227 		return fdmatch(tcp, tcp->u_arg[1]) ||
    228 			upathmatch(tcp, tcp->u_arg[0]) ||
    229 			upathmatch(tcp, tcp->u_arg[2]);
    230 
    231 	case SEN_copy_file_range:
    232 	case SEN_splice:
    233 		/* fd, x, fd, x, x, x */
    234 		return fdmatch(tcp, tcp->u_arg[0]) ||
    235 			fdmatch(tcp, tcp->u_arg[2]);
    236 
    237 	case SEN_epoll_ctl:
    238 		/* x, x, fd, x */
    239 		return fdmatch(tcp, tcp->u_arg[2]);
    240 
    241 
    242 	case SEN_fanotify_mark:
    243 		/* x, x, x, fd, path */
    244 		return fdmatch(tcp, tcp->u_arg[3]) ||
    245 			upathmatch(tcp, tcp->u_arg[4]);
    246 
    247 	case SEN_oldselect:
    248 	case SEN_pselect6:
    249 	case SEN_select:
    250 	{
    251 		int     i, j;
    252 		int     nfds;
    253 		kernel_ulong_t *args;
    254 		kernel_ulong_t select_args[5];
    255 		unsigned int oldselect_args[5];
    256 		unsigned int fdsize;
    257 		fd_set *fds;
    258 
    259 		if (SEN_oldselect == s->sen) {
    260 			if (sizeof(*select_args) == sizeof(*oldselect_args)) {
    261 				if (umove(tcp, tcp->u_arg[0], &select_args)) {
    262 					return 0;
    263 				}
    264 			} else {
    265 				unsigned int n;
    266 
    267 				if (umove(tcp, tcp->u_arg[0], &oldselect_args)) {
    268 					return 0;
    269 				}
    270 
    271 				for (n = 0; n < 5; ++n) {
    272 					select_args[n] = oldselect_args[n];
    273 				}
    274 			}
    275 			args = select_args;
    276 		} else {
    277 			args = tcp->u_arg;
    278 		}
    279 
    280 		/* Kernel truncates arg[0] to int, we do the same. */
    281 		nfds = (int) args[0];
    282 		/* Kernel rejects negative nfds, so we don't parse it either. */
    283 		if (nfds <= 0)
    284 			return 0;
    285 		/* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */
    286 		if (nfds > 1024*1024)
    287 			nfds = 1024*1024;
    288 		fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;
    289 		fds = xmalloc(fdsize);
    290 
    291 		for (i = 1; i <= 3; ++i) {
    292 			if (args[i] == 0)
    293 				continue;
    294 			if (umoven(tcp, args[i], fdsize, fds) < 0) {
    295 				continue;
    296 			}
    297 			for (j = 0;; j++) {
    298 				j = next_set_bit(fds, j, nfds);
    299 				if (j < 0)
    300 					break;
    301 				if (fdmatch(tcp, j)) {
    302 					free(fds);
    303 					return 1;
    304 				}
    305 			}
    306 		}
    307 		free(fds);
    308 		return 0;
    309 	}
    310 
    311 	case SEN_poll:
    312 	case SEN_ppoll:
    313 	{
    314 		struct pollfd fds;
    315 		unsigned nfds;
    316 		kernel_ulong_t start, cur, end;
    317 
    318 		start = tcp->u_arg[0];
    319 		nfds = tcp->u_arg[1];
    320 
    321 		end = start + sizeof(fds) * nfds;
    322 
    323 		if (nfds == 0 || end < start)
    324 			return 0;
    325 
    326 		for (cur = start; cur < end; cur += sizeof(fds))
    327 			if ((umove(tcp, cur, &fds) == 0)
    328 			    && fdmatch(tcp, fds.fd))
    329 				return 1;
    330 
    331 		return 0;
    332 	}
    333 
    334 	case SEN_bpf:
    335 	case SEN_epoll_create:
    336 	case SEN_epoll_create1:
    337 	case SEN_eventfd2:
    338 	case SEN_eventfd:
    339 	case SEN_fanotify_init:
    340 	case SEN_inotify_init1:
    341 	case SEN_memfd_create:
    342 	case SEN_perf_event_open:
    343 	case SEN_pipe:
    344 	case SEN_pipe2:
    345 	case SEN_printargs:
    346 	case SEN_socket:
    347 	case SEN_socketpair:
    348 	case SEN_timerfd_create:
    349 	case SEN_timerfd_gettime:
    350 	case SEN_timerfd_settime:
    351 	case SEN_userfaultfd:
    352 		/*
    353 		 * These have TRACE_FILE or TRACE_DESCRIPTOR or TRACE_NETWORK set,
    354 		 * but they don't have any file descriptor or path args to test.
    355 		 */
    356 		return 0;
    357 	}
    358 
    359 	/*
    360 	 * Our fallback position for calls that haven't already
    361 	 * been handled is to just check arg[0].
    362 	 */
    363 
    364 	if (s->sys_flags & TRACE_FILE)
    365 		return upathmatch(tcp, tcp->u_arg[0]);
    366 
    367 	if (s->sys_flags & (TRACE_DESC | TRACE_NETWORK))
    368 		return fdmatch(tcp, tcp->u_arg[0]);
    369 
    370 	return 0;
    371 }
    372