X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=pathtrace.c;h=9fb99c42ff240d067180d2a6406edbee53a62d06;hb=7845a42b39e59e904d01e75e21f7bc7eb6462560;hp=5fa8be4c7b5d9326bf768020502415910c849492;hpb=bdec9cbcebd256dbebf8fd2f7e35dec55b8bd5ae;p=strace diff --git a/pathtrace.c b/pathtrace.c index 5fa8be4c..9fb99c42 100644 --- a/pathtrace.c +++ b/pathtrace.c @@ -27,21 +27,17 @@ */ #include "defs.h" - -#include #include - -#ifdef HAVE_POLL_H -#include -#endif -#ifdef HAVE_SYS_POLL_H -#include +#if defined HAVE_POLL_H +# include +#elif defined HAVE_SYS_POLL_H +# include #endif #include "syscall.h" -#define MAXSELECTED 256 /* max number of "selected" paths */ -static const char *selected[MAXSELECTED]; /* paths selected for tracing */ +const char **paths_selected = NULL; +static unsigned num_selected = 0; /* * Return true if specified path matches one that we're tracing. @@ -49,12 +45,10 @@ static const char *selected[MAXSELECTED]; /* paths selected for tracing */ static int pathmatch(const char *path) { - unsigned int i; + unsigned i; - for (i = 0; i < ARRAY_SIZE(selected); ++i) { - if (selected[i] == NULL) - return 0; - if (!strcmp(path, selected[i])) + for (i = 0; i < num_selected; ++i) { + if (strcmp(path, paths_selected[i]) == 0) return 1; } return 0; @@ -68,7 +62,7 @@ upathmatch(struct tcb *tcp, unsigned long upath) { char path[PATH_MAX + 1]; - return umovestr(tcp, upath, sizeof path, path) >= 0 && + return umovestr(tcp, upath, sizeof path, path) > 0 && pathmatch(path); } @@ -78,93 +72,79 @@ upathmatch(struct tcb *tcp, unsigned long upath) static int fdmatch(struct tcb *tcp, int fd) { - const char *path = getfdpath(tcp, fd); + char path[PATH_MAX + 1]; + int n = getfdpath(tcp, fd, path, sizeof(path)); - return path && pathmatch(path); + return n >= 0 && pathmatch(path); } /* * Add a path to the set we're tracing. - * Secifying NULL will delete all paths. + * Specifying NULL will delete all paths. */ -static int +static void storepath(const char *path) { - unsigned int i; - - if (path == NULL) { - for (i = 0; i < ARRAY_SIZE(selected); ++i) - if (selected[i]) { - free((char *) selected[i]); - selected[i] = NULL; - } - return 0; - } + unsigned i; - for (i = 0; i < ARRAY_SIZE(selected); ++i) - if (!selected[i]) { - selected[i] = path; - return 0; - } + if (pathmatch(path)) + return; /* already in table */ - fprintf(stderr, "Max trace paths exceeded, only using first %u\n", - (unsigned int) ARRAY_SIZE(selected)); - return -1; + i = num_selected++; + paths_selected = realloc(paths_selected, num_selected * sizeof(paths_selected[0])); + if (!paths_selected) + die_out_of_memory(); + paths_selected[i] = path; } /* * Get path associated with fd. */ -const char *getfdpath(struct tcb *tcp, int fd) +int +getfdpath(struct tcb *tcp, int fd, char *buf, unsigned bufsize) { -#ifdef LINUX - static char path[PATH_MAX+1]; - char linkpath[64]; + char linkpath[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3]; ssize_t n; if (fd < 0) - return NULL; - - snprintf(linkpath, sizeof linkpath, "/proc/%d/fd/%d", tcp->pid, fd); - n = readlink(linkpath, path, (sizeof path) - 1); - if (n <= 0) - return NULL; - path[n] = '\0'; - return path; -#else - return NULL; -#endif + return -1; + + sprintf(linkpath, "/proc/%u/fd/%u", tcp->pid, fd); + n = readlink(linkpath, buf, bufsize - 1); + /* + * NB: if buf is too small, readlink doesn't fail, + * it returns truncated result (IOW: n == bufsize - 1). + */ + if (n >= 0) + buf[n] = '\0'; + return n; } /* * Add a path to the set we're tracing. Also add the canonicalized * version of the path. Secifying NULL will delete all paths. */ -int +void pathtrace_select(const char *path) { - char *rpath; - - if (path == NULL) - return storepath(path); + char *rpath; - if (storepath(path)) - return -1; + storepath(path); rpath = realpath(path, NULL); if (rpath == NULL) - return 0; + return; /* if realpath and specified path are same, we're done */ - if (!strcmp(path, rpath)) { + if (strcmp(path, rpath) == 0) { free(rpath); - return 0; + return; } fprintf(stderr, "Requested path '%s' resolved into '%s'\n", path, rpath); - return storepath(rpath); + storepath(rpath); } /* @@ -174,17 +154,11 @@ pathtrace_select(const char *path) int pathtrace_match(struct tcb *tcp) { - const struct sysent *s; - - if (selected[0] == NULL) - return 1; - - if (!SCNO_IN_RANGE(tcp->scno)) - return 0; + const struct_sysent *s; - s = &sysent[tcp->scno]; + s = tcp->s_ent; - if (!(s->sys_flags & (TRACE_FILE | TRACE_DESC))) + if (!(s->sys_flags & (TRACE_FILE | TRACE_DESC | TRACE_NETWORK))) return 0; /* @@ -192,8 +166,6 @@ pathtrace_match(struct tcb *tcp) * other than test arg[0]. */ -#ifdef LINUX - if (s->sys_func == sys_dup2 || s->sys_func == sys_dup3 || s->sys_func == sys_sendfile || @@ -232,6 +204,12 @@ pathtrace_match(struct tcb *tcp) upathmatch(tcp, tcp->u_arg[1]); } + if (s->sys_func == sys_quotactl) + { + /* x, path */ + return upathmatch(tcp, tcp->u_arg[1]); + } + if (s->sys_func == sys_renameat || s->sys_func == sys_linkat) { @@ -242,7 +220,15 @@ pathtrace_match(struct tcb *tcp) upathmatch(tcp, tcp->u_arg[3]); } - if (s->sys_func == sys_old_mmap || s->sys_func == sys_mmap) { + if ( + s->sys_func == sys_old_mmap || +#if defined(S390) + s->sys_func == sys_old_mmap_pgoff || +#endif + s->sys_func == sys_mmap || + s->sys_func == sys_mmap_pgoff || + s->sys_func == sys_mmap_4koff + ) { /* x, x, x, x, fd */ return fdmatch(tcp, tcp->u_arg[4]); } @@ -265,16 +251,23 @@ pathtrace_match(struct tcb *tcp) return fdmatch(tcp, tcp->u_arg[2]); } + if (s->sys_func == sys_fanotify_mark) { + /* x, x, x, fd, path */ + return fdmatch(tcp, tcp->u_arg[3]) || + upathmatch(tcp, tcp->u_arg[4]); + } + if (s->sys_func == sys_select || s->sys_func == sys_oldselect || s->sys_func == sys_pselect6) { int i, j; - unsigned nfds; + int nfds; long *args, oldargs[5]; unsigned fdsize; fd_set *fds; + args = tcp->u_arg; if (s->sys_func == sys_oldselect) { if (umoven(tcp, tcp->u_arg[0], sizeof oldargs, (char*) oldargs) < 0) @@ -283,17 +276,17 @@ pathtrace_match(struct tcb *tcp) return 0; } args = oldargs; - } else - args = tcp->u_arg; + } - nfds = args[0]; + /* Kernel truncates arg[0] to int, we do the same. */ + nfds = (int) args[0]; + /* Kernel rejects negative nfds, so we don't parse it either. */ + if (nfds <= 0) + return 0; /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */ - if (args[0] > 1024*1024) + if (nfds > 1024*1024) nfds = 1024*1024; - if (args[0] < 0) - nfds = 0; - fdsize = ((((nfds + 7) / 8) + sizeof(long) - 1) - & -sizeof(long)); + fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize; fds = malloc(fdsize); if (!fds) die_out_of_memory(); @@ -301,17 +294,19 @@ pathtrace_match(struct tcb *tcp) for (i = 1; i <= 3; ++i) { if (args[i] == 0) continue; - if (umoven(tcp, args[i], fdsize, (char *) fds) < 0) { fprintf(stderr, "umoven() failed\n"); continue; } - - for (j = 0; j < nfds; ++j) - if (FD_ISSET(j, fds) && fdmatch(tcp, j)) { + for (j = 0;; j++) { + j = next_set_bit(fds, j, nfds); + if (j < 0) + break; + if (fdmatch(tcp, j)) { free(fds); return 1; } + } } free(fds); return 0; @@ -350,17 +345,16 @@ pathtrace_match(struct tcb *tcp) s->sys_func == sys_timerfd_settime || s->sys_func == sys_timerfd_gettime || s->sys_func == sys_epoll_create || - !strcmp(s->sys_name, "fanotify_init")) + s->sys_func == sys_socket || + s->sys_func == sys_socketpair || + s->sys_func == sys_fanotify_init) { /* - * These have TRACE_FILE or TRACE_DESCRIPTOR set, but they - * don't have any file descriptor or path args to test. + * These have TRACE_FILE or TRACE_DESCRIPTOR or TRACE_NETWORK set, + * but they don't have any file descriptor or path args to test. */ return 0; } -#else -#warning "path tracing only using arg[0]" -#endif /* * Our fallback position for calls that haven't already @@ -370,7 +364,7 @@ pathtrace_match(struct tcb *tcp) if (s->sys_flags & TRACE_FILE) return upathmatch(tcp, tcp->u_arg[0]); - if (s->sys_flags & TRACE_DESC) + if (s->sys_flags & (TRACE_DESC | TRACE_NETWORK)) return fdmatch(tcp, tcp->u_arg[0]); return 0;