From fa8c286d50d83ae86d2ca8df52f7aba8b6c5bae1 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Fri, 22 Jan 2016 14:37:14 +0000 Subject: [PATCH] Implement simultaneous use of -p option and tracing of a command * strace.c (init): Allow -p option along with a command. (startup_child): In -D mode, record the parent of the tracer process as strace_child. (startup_attach): Save trace_tracer_pid before -D mode fork. When tracing a command in -f mode, do not check for the command's threads as it has no threads at this moment. Never attach to the tracer process. In -D mode, never attach to the parent of the tracer process, terminate that process only once at the end of startup_attach, and reset strace_child. * strace.1: Document that -p option can be used along with tracing of a command. * NEWS: Mention it. * tests/attach-p-cmd-cmd.c: New file. * tests/attach-p-cmd-p.c: Likewise. * tests/attach-p-cmd.test: New test. * tests/.gitignore: Add attach-p-cmd-cmd and attach-p-cmd-p. * tests/Makefile.am (check_PROGRAMS): Likewise. (TESTS): Add attach-p-cmd.test. This fixes Debian bug #549942. --- NEWS | 2 ++ strace.1 | 9 ++++-- strace.c | 44 +++++++++++++++------------ tests/.gitignore | 2 ++ tests/Makefile.am | 3 ++ tests/attach-p-cmd-cmd.c | 44 +++++++++++++++++++++++++++ tests/attach-p-cmd-p.c | 65 ++++++++++++++++++++++++++++++++++++++++ tests/attach-p-cmd.test | 54 +++++++++++++++++++++++++++++++++ 8 files changed, 202 insertions(+), 21 deletions(-) create mode 100644 tests/attach-p-cmd-cmd.c create mode 100644 tests/attach-p-cmd-p.c create mode 100755 tests/attach-p-cmd.test diff --git a/NEWS b/NEWS index ceddf089..a7520d66 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ Noteworthy changes in release ?.?? (????-??-??) =============================================== * Improvements + * Implemented simultaneous use of -p option and tracing of a command. + (addresses Debian bug #549942). * Enhanced decoding of personality, sched_getaffinity, and sched_setaffinity syscalls. * Enhanced decoding of getxpid, getxuid, and getxgid syscalls on alpha. diff --git a/strace.1 b/strace.1 index 6d5bcbad..429cdfc6 100644 --- a/strace.1 +++ b/strace.1 @@ -530,8 +530,13 @@ will respond by detaching itself from the traced process(es) leaving it (them) to continue running. Multiple .B \-p -options can be used to attach to many processes. --p "`pidof PROG`" syntax is supported. +options can be used to attach to many processes in addition to +.I command +(which is optional if at least one +.B \-p +option is given). +.B \-p +"`pidof PROG`" syntax is supported. .TP .BI "\-P " path Trace only system calls accessing diff --git a/strace.c b/strace.c index 7792a5c8..614b85f9 100644 --- a/strace.c +++ b/strace.c @@ -973,6 +973,7 @@ process_opt_p_list(char *opt) static void startup_attach(void) { + pid_t parent_pid = strace_tracer_pid; unsigned int tcbi; struct tcb *tcp; @@ -1015,7 +1016,13 @@ startup_attach(void) if (tcp->flags & TCB_ATTACHED) continue; /* no, we already attached it */ - if (followfork && !daemonized_tracer) { + if (tcp->pid == parent_pid || tcp->pid == strace_tracer_pid) { + errno = EPERM; + perror_msg("attach: %d", tcp->pid); + droptcb(tcp); + continue; + } + if (followfork && tcp->pid != strace_child) { char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3]; DIR *dir; @@ -1092,18 +1099,19 @@ startup_attach(void) if (debug_flag) error_msg("attach to pid %d (main) succeeded", tcp->pid); - if (daemonized_tracer) { - /* - * Make parent go away. - * Also makes grandparent's wait() unblock. - */ - kill(getppid(), SIGKILL); - } - if (!qflag) error_msg("Process %u attached", tcp->pid); } /* for each tcbtab[] */ + if (daemonized_tracer) { + /* + * Make parent go away. + * Also makes grandparent's wait() unblock. + */ + kill(parent_pid, SIGKILL); + strace_child = 0; + } + ret: if (interactive) sigprocmask(SIG_SETMASK, &empty_set, NULL); @@ -1317,11 +1325,10 @@ startup_child(char **argv) newoutf(tcp); } else { - /* With -D, we are *child* here, IOW: different pid. Fetch it: */ + /* With -D, we are *child* here, the tracee is our parent. */ + strace_child = strace_tracer_pid; strace_tracer_pid = getpid(); - /* The tracee is our parent: */ - pid = getppid(); - alloctcb(pid); + alloctcb(strace_child); /* attaching will be done later, by startup_attach */ /* note: we don't do newoutf(tcp) here either! */ @@ -1619,13 +1626,12 @@ init(int argc, char *argv[]) memset(acolumn_spaces, ' ', acolumn); acolumn_spaces[acolumn] = '\0'; - /* Must have PROG [ARGS], or -p PID. Not both. */ - if (!argv[0] == !nprocs) { + if (!argv[0] && !nprocs) { error_msg_and_help("must have PROG [ARGS] or -p PID"); } - if (nprocs != 0 && daemonized_tracer) { - error_msg_and_help("-D and -p are mutually exclusive"); + if (!argv[0] && daemonized_tracer) { + error_msg_and_help("PROG [ARGS] must be specified with -D"); } if (!followfork) @@ -1722,9 +1728,9 @@ init(int argc, char *argv[]) opt_intr = INTR_WHILE_WAIT; /* argv[0] -pPID -oFILE Default interactive setting - * yes 0 0 INTR_WHILE_WAIT + * yes * 0 INTR_WHILE_WAIT * no 1 0 INTR_WHILE_WAIT - * yes 0 1 INTR_NEVER + * yes * 1 INTR_NEVER * no 1 1 INTR_WHILE_WAIT */ diff --git a/tests/.gitignore b/tests/.gitignore index 4f552d6b..207a9b2e 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -8,6 +8,8 @@ _newselect adjtimex aio +attach-p-cmd-cmd +attach-p-cmd-p bpf caps clock_nanosleep diff --git a/tests/Makefile.am b/tests/Makefile.am index 65350307..f6345836 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -56,6 +56,8 @@ check_PROGRAMS = \ _newselect \ adjtimex \ aio \ + attach-p-cmd-cmd \ + attach-p-cmd-p \ bpf \ caps \ clock_nanosleep \ @@ -299,6 +301,7 @@ TESTS = \ xettimeofday.test \ \ count.test \ + attach-p-cmd.test \ detach-sleeping.test \ detach-stopped.test \ detach-running.test \ diff --git a/tests/attach-p-cmd-cmd.c b/tests/attach-p-cmd-cmd.c new file mode 100644 index 00000000..28f5e359 --- /dev/null +++ b/tests/attach-p-cmd-cmd.c @@ -0,0 +1,44 @@ +/* + * This file is part of attach-p-cmd strace test. + * + * Copyright (c) 2016 Dmitry V. Levin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tests.h" +#include +#include +#include + +int +main(void) +{ + static const char text[] = "attach-p-cmd.test cmd"; + assert(chdir(text) == -1); + pid_t pid = getpid(); + printf("%-5d chdir(\"%s\") = -1 ENOENT (%m)\n" + "%-5d +++ exited with 0 +++\n", pid, text, pid); + return 0; +} diff --git a/tests/attach-p-cmd-p.c b/tests/attach-p-cmd-p.c new file mode 100644 index 00000000..528d35a9 --- /dev/null +++ b/tests/attach-p-cmd-p.c @@ -0,0 +1,65 @@ +/* + * This file is part of attach-p-cmd strace test. + * + * Copyright (c) 2016 Dmitry V. Levin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tests.h" +#include +#include +#include +#include +#include +#include + +static void +handler(int signo) +{ + _exit(!chdir("attach-p-cmd.test -p")); +} + +int +main(int ac, char **av) +{ + if (ac < 2) + error_msg_and_fail("missing operand"); + + if (ac > 2) + error_msg_and_fail("extra operand"); + + const sigset_t set = {}; + const struct sigaction act = { .sa_handler = handler }; + const struct itimerval itv = { .it_value.tv_sec = atoi(av[1]) }; + + assert(sigaction(SIGALRM, &act, NULL) == 0); + assert(sigprocmask(SIG_SETMASK, &set, NULL) == 0); + if (setitimer(ITIMER_REAL, &itv, NULL)) + perror_msg_and_skip("setitimer"); + + for (;;); + + return 0; +} diff --git a/tests/attach-p-cmd.test b/tests/attach-p-cmd.test new file mode 100755 index 00000000..de3f4cd8 --- /dev/null +++ b/tests/attach-p-cmd.test @@ -0,0 +1,54 @@ +#!/bin/sh +# +# Check that simultaneous use of -p option and tracing of a command works. +# +# Copyright (c) 2016 Dmitry V. Levin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +. "${srcdir=.}/init.sh" + +run_prog_skip_if_failed \ + kill -0 $$ +run_prog ./attach-p-cmd-cmd > /dev/null +run_prog ./attach-p-cmd-p 1 > /dev/null + +OUT="$LOG.out" +./set_ptracer_any ./attach-p-cmd-p 1 > "$OUT" & +tracee_pid=$! + +while ! [ -s "$OUT" ]; do + kill -0 $tracee_pid 2> /dev/null || + fail_ 'set_ptracer_any sleep failed' +done + +run_strace -a30 -echdir -p $tracee_pid ./attach-p-cmd-cmd > "$OUT" +{ +printf '%-5d --- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} ---\n' $tracee_pid +printf '%-5d chdir("attach-p-cmd.test -p") = -1 ENOENT (No such file or directory)\n' $tracee_pid +printf '%-5d +++ exited with 0 +++\n' $tracee_pid +} >> "$OUT" + +match_diff "$LOG" "$OUT" +rm -f "$OUT" -- 2.40.0