summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry V. Levin <ldv@altlinux.org>2006-12-13 21:45:31 +0000
committerDmitry V. Levin <ldv@altlinux.org>2006-12-13 21:45:31 +0000
commit10de62bb052b541af3d0566f05f3f870cce0e028 (patch)
treead48471f10880ae464f03d1f7929676b49b142db
parentd3cb392f8520cb1a6a3d6c93febe2a2424560574 (diff)
downloadstrace-10de62bb052b541af3d0566f05f3f870cce0e028.tar.gz
strace-10de62bb052b541af3d0566f05f3f870cce0e028.tar.bz2
strace-10de62bb052b541af3d0566f05f3f870cce0e028.tar.xz
2006-12-12 Dmitry V. Levin <ldv@altlinux.org>
Fix -ff -o behaviour. Fix piping trace output. * defs.h (newoutf): Remove. (alloctcb): Rename to alloc_tcb. Add alloctcb() macro wrapper around alloc_tcb(). * process.c [!USE_PROCFS] (internal_clone, internal_fork): Remove newoutf() call. * strace.c (set_cloexec_flag, strace_fopen, strace_popen, swap_uid): New functions. (popen_pid): New variable. (newoutf): Make static, use strace_fopen(). (main): Use strace_fopen() and strace_popen(), remove uids swapping. Do not open outfname when followfork > 1. Reinitialize tcp->outf properly. (alloctcb): Rename to alloc_tcb. Use newoutf(). (trace): Check popen_pid. Remove newoutf() call. [USE_PROCFS] (proc_open, proc_poll_open): Use set_cloexec_flag(). Fixes RH#204950, RH#218435.
-rw-r--r--ChangeLog20
-rw-r--r--defs.h5
-rw-r--r--process.c2
-rw-r--r--strace.c266
4 files changed, 195 insertions, 98 deletions
diff --git a/ChangeLog b/ChangeLog
index f5424f9..a2d4cce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2006-12-12 Dmitry V. Levin <ldv@altlinux.org>
+
+ Fix -ff -o behaviour. Fix piping trace output.
+ * defs.h (newoutf): Remove.
+ (alloctcb): Rename to alloc_tcb. Add alloctcb() macro wrapper
+ around alloc_tcb().
+ * process.c [!USE_PROCFS] (internal_clone, internal_fork):
+ Remove newoutf() call.
+ * strace.c (set_cloexec_flag, strace_fopen, strace_popen,
+ swap_uid): New functions.
+ (popen_pid): New variable.
+ (newoutf): Make static, use strace_fopen().
+ (main): Use strace_fopen() and strace_popen(), remove uids
+ swapping. Do not open outfname when followfork > 1.
+ Reinitialize tcp->outf properly.
+ (alloctcb): Rename to alloc_tcb. Use newoutf().
+ (trace): Check popen_pid. Remove newoutf() call.
+ [USE_PROCFS] (proc_open, proc_poll_open): Use set_cloexec_flag().
+ Fixes RH#204950, RH#218435.
+
2006-12-10 Dmitry V. Levin <ldv@altlinux.org>
Add biarch support for "struct sigevent".
diff --git a/defs.h b/defs.h
index 0396b11..8756908 100644
--- a/defs.h
+++ b/defs.h
@@ -425,15 +425,16 @@ enum bitness_t { BITNESS_CURRENT = 0, BITNESS_32 };
extern int set_personality P((int personality));
extern char *xlookup P((const struct xlat *, int));
-extern struct tcb *alloctcb P((int));
+extern struct tcb *alloc_tcb P((int, int));
extern struct tcb *pid2tcb P((int));
extern void droptcb P((struct tcb *));
extern int expand_tcbtab P((void));
+#define alloctcb(pid) alloc_tcb((pid), 1)
+
extern void set_sortby P((char *));
extern void set_overhead P((int));
extern void qualify P((char *));
-extern void newoutf P((struct tcb *));
extern int get_scno P((struct tcb *));
extern long known_scno P((struct tcb *));
extern int trace_syscall P((struct tcb *));
diff --git a/process.c b/process.c
index 06eb76e..8e25640 100644
--- a/process.c
+++ b/process.c
@@ -893,7 +893,6 @@ Process %u resumed (parent %d ready)\n",
pid, tcp->pid);
}
else {
- newoutf(tcpchild);
if (!qflag)
fprintf(stderr, "Process %d attached\n", pid);
}
@@ -1048,7 +1047,6 @@ struct tcb *tcp;
memcpy(tcpchild->inst, tcp->inst,
sizeof tcpchild->inst);
}
- newoutf(tcpchild);
tcpchild->parent = tcp;
tcp->nchildren++;
if (!qflag)
diff --git a/strace.c b/strace.c
index 7d5f86b..5e3b875 100644
--- a/strace.c
+++ b/strace.c
@@ -175,6 +175,150 @@ foobar()
#endif /* MIPS */
#endif /* SVR4 */
+static int
+set_cloexec_flag(int fd)
+{
+ int flags, newflags;
+
+ if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
+ {
+ fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
+ progname, strerror(errno));
+ return -1;
+ }
+
+ newflags = flags | FD_CLOEXEC;
+ if (flags == newflags)
+ return 0;
+
+ if (fcntl(fd, F_SETFD, newflags) < 0)
+ {
+ fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
+ progname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * When strace is setuid executable, we have to swap uids
+ * before and after filesystem and process management operations.
+ */
+static void
+swap_uid(void)
+{
+#ifndef SVR4
+ int euid = geteuid(), uid = getuid();
+
+ if (euid != uid && setreuid(euid, uid) < 0)
+ {
+ fprintf(stderr, "%s: setreuid: %s\n",
+ progname, strerror(errno));
+ exit(1);
+ }
+#endif
+}
+
+static FILE *
+strace_fopen(const char *path, const char *mode)
+{
+ FILE *fp;
+
+ swap_uid();
+ if ((fp = fopen(path, mode)) == NULL)
+ fprintf(stderr, "%s: can't fopen '%s': %s\n",
+ progname, path, strerror(errno));
+ swap_uid();
+ if (fp && set_cloexec_flag(fileno(fp)) < 0)
+ {
+ fclose(fp);
+ fp = NULL;
+ }
+ return fp;
+}
+
+static int popen_pid = -1;
+
+#ifndef _PATH_BSHELL
+# define _PATH_BSHELL "/bin/sh"
+#endif
+
+/*
+ * We cannot use standard popen(3) here because we have to distinguish
+ * popen child process from other processes we trace, and standard popen(3)
+ * does not export its child's pid.
+ */
+static FILE *
+strace_popen(const char *command)
+{
+ int fds[2];
+
+ swap_uid();
+ if (pipe(fds) < 0)
+ {
+ fprintf(stderr, "%s: pipe: %s\n",
+ progname, strerror(errno));
+ swap_uid();
+ return NULL;
+ }
+
+ if (set_cloexec_flag(fds[1]) < 0)
+ {
+ close(fds[0]);
+ close(fds[1]);
+ swap_uid();
+ return NULL;
+ }
+
+ if ((popen_pid = fork()) == -1)
+ {
+ fprintf(stderr, "%s: fork: %s\n",
+ progname, strerror(errno));
+ close(fds[0]);
+ close(fds[1]);
+ swap_uid();
+ return NULL;
+ }
+
+ if (popen_pid)
+ {
+ /* parent */
+ close(fds[0]);
+ swap_uid();
+ return fdopen(fds[1], "w");
+ } else
+ {
+ /* child */
+ close(fds[1]);
+ if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
+ {
+ fprintf(stderr, "%s: dup2: %s\n",
+ progname, strerror(errno));
+ _exit(1);
+ }
+ execl(_PATH_BSHELL, "sh", "-c", command, NULL);
+ fprintf(stderr, "%s: execl: %s: %s\n",
+ progname, _PATH_BSHELL, strerror(errno));
+ _exit(1);
+ }
+}
+
+static int
+newoutf(struct tcb *tcp)
+{
+ if (outfname && followfork > 1) {
+ char name[MAXPATHLEN];
+ FILE *fp;
+
+ sprintf(name, "%s.%u", outfname, tcp->pid);
+ if ((fp = strace_fopen(name, "w")) == NULL)
+ return -1;
+ tcp->outf = fp;
+ }
+ return 0;
+}
+
int
main(argc, argv)
int argc;
@@ -274,7 +418,7 @@ char *argv[];
fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
break;
}
- if ((tcp = alloctcb(pid)) == NULL) {
+ if ((tcp = alloc_tcb(pid, 0)) == NULL) {
fprintf(stderr, "%s: out of memory\n",
progname);
exit(1);
@@ -343,14 +487,8 @@ char *argv[];
run_gid = getgid();
}
-#ifndef SVR4
- setreuid(geteuid(), getuid());
-#endif
-
/* Check if they want to redirect the output. */
if (outfname) {
- long f;
-
/* See if they want to pipe the output. */
if (outfname[0] == '|' || outfname[0] == '!') {
/*
@@ -364,34 +502,14 @@ char *argv[];
exit(1);
}
- if ((outf = popen(outfname + 1, "w")) == NULL) {
- fprintf(stderr, "%s: can't popen '%s': %s\n",
- progname, outfname + 1,
- strerror(errno));
+ if ((outf = strace_popen(outfname + 1)) == NULL)
exit(1);
- }
- }
- else if ((outf = fopen(outfname, "w")) == NULL) {
- fprintf(stderr, "%s: can't fopen '%s': %s\n",
- progname, outfname, strerror(errno));
- exit(1);
}
-
- if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
- perror("failed to get flags for outputfile");
- exit(1);
- }
-
- if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
- perror("failed to set flags for outputfile");
+ else if (followfork <= 1 &&
+ (outf = strace_fopen(outfname, "w")) == NULL)
exit(1);
- }
}
-#ifndef SVR4
- setreuid(geteuid(), getuid());
-#endif
-
if (!outfname || outfname[0] == '|' || outfname[0] == '!')
setvbuf(outf, buf, _IOLBF, BUFSIZ);
if (outfname && optind < argc) {
@@ -401,10 +519,17 @@ char *argv[];
for (c = 0; c < tcbtabsize; c++) {
tcp = tcbtab[c];
- /* Reinitialize the output since it may have changed. */
- tcp->outf = outf;
if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
continue;
+#ifdef LINUX
+ if (tcp->flags & TCB_CLONE_THREAD)
+ continue;
+#endif
+ /* Reinitialize the output since it may have changed. */
+ tcp->outf = outf;
+ if (newoutf(tcp) < 0)
+ exit(1);
+
#ifdef USE_PROCFS
if (proc_open(tcp, 1) < 0) {
fprintf(stderr, "trouble opening proc file\n");
@@ -413,11 +538,10 @@ char *argv[];
}
#else /* !USE_PROCFS */
# ifdef LINUX
- if (tcp->flags & TCB_CLONE_THREAD)
- continue;
if (followfork) {
char procdir[MAXPATHLEN];
DIR *dir;
+
sprintf(procdir, "/proc/%d/task", tcp->pid);
dir = opendir(procdir);
if (dir != NULL) {
@@ -680,31 +804,6 @@ Process %u attached - interrupt to quit\n",
exit(0);
}
-void
-newoutf(tcp)
-struct tcb *tcp;
-{
- char name[MAXPATHLEN];
- FILE *fp;
-
- if (outfname && followfork > 1) {
- sprintf(name, "%s.%u", outfname, tcp->pid);
-#ifndef SVR4
- setreuid(geteuid(), getuid());
-#endif
- fp = fopen(name, "w");
-#ifndef SVR4
- setreuid(geteuid(), getuid());
-#endif
- if (fp == NULL) {
- perror("fopen");
- return;
- }
- tcp->outf = fp;
- }
- return;
-}
-
int
expand_tcbtab()
{
@@ -735,8 +834,7 @@ expand_tcbtab()
struct tcb *
-alloctcb(pid)
-int pid;
+alloc_tcb(int pid, int command_options_parsed)
{
int i;
struct tcb *tcp;
@@ -758,10 +856,12 @@ int pid;
tcp->stime.tv_usec = 0;
tcp->pfd = -1;
nprocs++;
+ if (command_options_parsed)
+ newoutf(tcp);
return tcp;
}
}
- fprintf(stderr, "%s: alloctcb: tcb table full\n", progname);
+ fprintf(stderr, "%s: alloc_tcb: tcb table full\n", progname);
return NULL;
}
@@ -790,12 +890,7 @@ int attaching;
perror("strace: open(\"/proc/...\", ...)");
return -1;
}
- if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
- perror("F_GETFD");
- return -1;
- }
- if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
- perror("F_SETFD");
+ if (set_cloexec_flag(tcp->pfd) < 0) {
return -1;
}
sprintf(proc, "/proc/%d/status", tcp->pid);
@@ -803,12 +898,7 @@ int attaching;
perror("strace: open(\"/proc/...\", ...)");
return -1;
}
- if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
- perror("F_GETFD");
- return -1;
- }
- if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
- perror("F_SETFD");
+ if (set_cloexec_flag(tcp->pfd_stat) < 0) {
return -1;
}
sprintf(proc, "/proc/%d/as", tcp->pid);
@@ -816,12 +906,7 @@ int attaching;
perror("strace: open(\"/proc/...\", ...)");
return -1;
}
- if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
- perror("F_GETFD");
- return -1;
- }
- if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
- perror("F_SETFD");
+ if (set_cloexec_flag(tcp->pfd_as) < 0) {
return -1;
}
#else
@@ -836,12 +921,7 @@ int attaching;
perror("strace: open(\"/proc/...\", ...)");
return -1;
}
- if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
- perror("F_GETFD");
- return -1;
- }
- if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
- perror("F_SETFD");
+ if (set_cloexec_flag(tcp->pfd) < 0) {
return -1;
}
#endif
@@ -1529,7 +1609,6 @@ rebuild_pollv()
static void
proc_poll_open()
{
- int arg;
int i;
if (pipe(proc_poll_pipe) < 0) {
@@ -1537,12 +1616,7 @@ proc_poll_open()
exit(1);
}
for (i = 0; i < 2; i++) {
- if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
- perror("F_GETFD");
- exit(1);
- }
- if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
- perror("F_SETFD");
+ if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
exit(1);
}
}
@@ -2087,6 +2161,11 @@ trace()
return -1;
}
}
+ if (pid == popen_pid) {
+ if (WIFEXITED(status) || WIFSIGNALED(status))
+ popen_pid = -1;
+ continue;
+ }
if (debug)
fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
@@ -2113,7 +2192,6 @@ trace()
return 0;
}
tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
- newoutf(tcp);
if (!qflag)
fprintf(stderr, "\
Process %d attached (waiting for parent)\n",