Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 156701 Details for
Bug 240986
Break by Ctrl-C before first syscall SIGSTOPs the traced process
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Bugfix update #2 according to the Roland's comments.
strace-interrupt-during-attach.patch (text/plain), 17.34 KB, created by
Jan Kratochvil
on 2007-06-11 12:09:10 UTC
(
hide
)
Description:
Bugfix update #2 according to the Roland's comments.
Filename:
MIME Type:
Creator:
Jan Kratochvil
Created:
2007-06-11 12:09:10 UTC
Size:
17.34 KB
patch
obsolete
>2007-06-11 Jan Kratochvil <jan.kratochvil@redhat.com> > > Never interrupt when the attached traced process would be left stopped. > * strace.c (main): `-p' attaching moved to ... > (startup_attach): ... a new function, renamed a variable C to TCBI. > Block interrupting signals since the first tracee has been attached. > New comment about INTERRUPTED in the nonthreaded case. > [LINUX] (startup_attach): Check INTERRUPTED after each attached thread. > (main): Command spawning moved to ... > (startup_child): ... a new function, replaced RETURN with EXIT. > [LINUX] (detach): New variable CATCH_SIGSTOP, do not signal > new SIGSTOP for processes still in TCB_STARTUP. > (main): Move signals and BLOCKED_SET init before the tracees attaching, > [SUNOS4] (trace): Removed fixvfork () call as a dead code, SIGSTOP must > have been already caught before clearing TCB_STARTUP. > (trace): Removed the `!WIFSTOPPED(status)' dead code. > Clear TCB_STARTUP only in the case the received signal was SIGSTOP. > New comment when `TCB_BPTSET && TCB_STARTUP' combination can be set. > Code advisory: Roland McGrath > Fixes RH#240986. > >Index: strace.c >=================================================================== >RCS file: /cvsroot/strace/strace/strace.c,v >retrieving revision 1.76 >diff -u -p -r1.76 strace.c >--- strace.c 2 Jun 2007 00:07:33 -0000 1.76 >+++ strace.c 11 Jun 2007 11:44:52 -0000 >@@ -334,6 +334,280 @@ newoutf(struct tcb *tcp) > return 0; > } > >+static void >+startup_attach(void) >+{ >+ int tcbi; >+ struct tcb *tcp; >+ >+ /* >+ * Block user interruptions as we would leave the traced >+ * process stopped (process state T) if we would terminate in >+ * between PTRACE_ATTACH and wait4 () on SIGSTOP. >+ * We rely on cleanup () from this point on. >+ */ >+ if (interactive) >+ sigprocmask(SIG_BLOCK, &blocked_set, NULL); >+ >+ for (tcbi = 0; tcbi < tcbtabsize; tcbi++) { >+ tcp = tcbtab[tcbi]; >+ 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"); >+ droptcb(tcp); >+ continue; >+ } >+#else /* !USE_PROCFS */ >+# ifdef LINUX >+ if (followfork) { >+ char procdir[MAXPATHLEN]; >+ DIR *dir; >+ >+ sprintf(procdir, "/proc/%d/task", tcp->pid); >+ dir = opendir(procdir); >+ if (dir != NULL) { >+ unsigned int ntid = 0, nerr = 0; >+ struct dirent *de; >+ int tid; >+ while ((de = readdir(dir)) != NULL) { >+ if (de->d_fileno == 0 || >+ de->d_name[0] == '.') >+ continue; >+ tid = atoi(de->d_name); >+ if (tid <= 0) >+ continue; >+ ++ntid; >+ if (ptrace(PTRACE_ATTACH, tid, >+ (char *) 1, 0) < 0) >+ ++nerr; >+ else if (tid != tcbtab[tcbi]->pid) { >+ if (nprocs == tcbtabsize && >+ expand_tcbtab()) >+ tcp = NULL; >+ else >+ tcp = alloctcb(tid); >+ if (tcp == NULL) >+ exit(1); >+ tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK; >+ tcbtab[tcbi]->nchildren++; >+ tcbtab[tcbi]->nclone_threads++; >+ tcbtab[tcbi]->nclone_detached++; >+ tcp->parent = tcbtab[tcbi]; >+ } >+ if (interactive) { >+ sigprocmask(SIG_SETMASK, &empty_set, NULL); >+ if (interrupted) >+ return; >+ sigprocmask(SIG_BLOCK, &blocked_set, NULL); >+ } >+ } >+ closedir(dir); >+ if (nerr == ntid) { >+ perror("attach: ptrace(PTRACE_ATTACH, ...)"); >+ droptcb(tcp); >+ continue; >+ } >+ if (!qflag) { >+ ntid -= nerr; >+ if (ntid > 1) >+ fprintf(stderr, "\ >+Process %u attached with %u threads - interrupt to quit\n", >+ tcp->pid, ntid); >+ else >+ fprintf(stderr, "\ >+Process %u attached - interrupt to quit\n", >+ tcp->pid); >+ } >+ continue; >+ } >+ } >+# endif >+ if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) { >+ perror("attach: ptrace(PTRACE_ATTACH, ...)"); >+ droptcb(tcp); >+ continue; >+ } >+ /* INTERRUPTED is going to be checked at the top of TRACE. */ >+#endif /* !USE_PROCFS */ >+ if (!qflag) >+ fprintf(stderr, >+ "Process %u attached - interrupt to quit\n", >+ tcp->pid); >+ } >+ >+ if (interactive) >+ sigprocmask(SIG_SETMASK, &empty_set, NULL); >+} >+ >+static void >+startup_child (char **argv) >+{ >+ struct stat statbuf; >+ const char *filename; >+ char pathname[MAXPATHLEN]; >+ int pid = 0; >+ struct tcb *tcp; >+ >+ filename = argv[0]; >+ if (strchr(filename, '/')) { >+ if (strlen(filename) > sizeof pathname - 1) { >+ errno = ENAMETOOLONG; >+ perror("strace: exec"); >+ exit(1); >+ } >+ strcpy(pathname, filename); >+ } >+#ifdef USE_DEBUGGING_EXEC >+ /* >+ * Debuggers customarily check the current directory >+ * first regardless of the path but doing that gives >+ * security geeks a panic attack. >+ */ >+ else if (stat(filename, &statbuf) == 0) >+ strcpy(pathname, filename); >+#endif /* USE_DEBUGGING_EXEC */ >+ else { >+ char *path; >+ int m, n, len; >+ >+ for (path = getenv("PATH"); path && *path; path += m) { >+ if (strchr(path, ':')) { >+ n = strchr(path, ':') - path; >+ m = n + 1; >+ } >+ else >+ m = n = strlen(path); >+ if (n == 0) { >+ if (!getcwd(pathname, MAXPATHLEN)) >+ continue; >+ len = strlen(pathname); >+ } >+ else if (n > sizeof pathname - 1) >+ continue; >+ else { >+ strncpy(pathname, path, n); >+ len = n; >+ } >+ if (len && pathname[len - 1] != '/') >+ pathname[len++] = '/'; >+ strcpy(pathname + len, filename); >+ if (stat(pathname, &statbuf) == 0 && >+ /* Accept only regular files >+ with some execute bits set. >+ XXX not perfect, might still fail */ >+ S_ISREG(statbuf.st_mode) && >+ (statbuf.st_mode & 0111)) >+ break; >+ } >+ } >+ if (stat(pathname, &statbuf) < 0) { >+ fprintf(stderr, "%s: %s: command not found\n", >+ progname, filename); >+ exit(1); >+ } >+ switch (pid = fork()) { >+ case -1: >+ perror("strace: fork"); >+ cleanup(); >+ exit(1); >+ break; >+ case 0: { >+#ifdef USE_PROCFS >+ if (outf != stderr) close (fileno (outf)); >+#ifdef MIPS >+ /* Kludge for SGI, see proc_open for details. */ >+ sa.sa_handler = foobar; >+ sa.sa_flags = 0; >+ sigemptyset(&sa.sa_mask); >+ sigaction(SIGINT, &sa, NULL); >+#endif /* MIPS */ >+#ifndef FREEBSD >+ pause(); >+#else /* FREEBSD */ >+ kill(getpid(), SIGSTOP); /* stop HERE */ >+#endif /* FREEBSD */ >+#else /* !USE_PROCFS */ >+ if (outf!=stderr) >+ close(fileno (outf)); >+ >+ if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) { >+ perror("strace: ptrace(PTRACE_TRACEME, ...)"); >+ exit(1); >+ } >+ if (debug) >+ kill(getpid(), SIGSTOP); >+ >+ if (username != NULL || geteuid() == 0) { >+ uid_t run_euid = run_uid; >+ gid_t run_egid = run_gid; >+ >+ if (statbuf.st_mode & S_ISUID) >+ run_euid = statbuf.st_uid; >+ if (statbuf.st_mode & S_ISGID) >+ run_egid = statbuf.st_gid; >+ >+ /* >+ * It is important to set groups before we >+ * lose privileges on setuid. >+ */ >+ if (username != NULL) { >+ if (initgroups(username, run_gid) < 0) { >+ perror("initgroups"); >+ exit(1); >+ } >+ if (setregid(run_gid, run_egid) < 0) { >+ perror("setregid"); >+ exit(1); >+ } >+ if (setreuid(run_uid, run_euid) < 0) { >+ perror("setreuid"); >+ exit(1); >+ } >+ } >+ } >+ else >+ setreuid(run_uid, run_uid); >+ >+ /* >+ * Induce an immediate stop so that the parent >+ * will resume us with PTRACE_SYSCALL and display >+ * this execve call normally. >+ */ >+ kill(getpid(), SIGSTOP); >+#endif /* !USE_PROCFS */ >+ >+ execv(pathname, argv); >+ perror("strace: exec"); >+ _exit(1); >+ break; >+ } >+ default: >+ if ((tcp = alloctcb(pid)) == NULL) { >+ cleanup(); >+ exit(1); >+ } >+#ifdef USE_PROCFS >+ if (proc_open(tcp, 0) < 0) { >+ fprintf(stderr, "trouble opening proc file\n"); >+ cleanup(); >+ exit(1); >+ } >+#endif /* USE_PROCFS */ >+ break; >+ } >+} >+ > int > main(argc, argv) > int argc; >@@ -532,250 +806,6 @@ char *argv[]; > qflag = 1; > } > >- for (c = 0; c < tcbtabsize; c++) { >- tcp = tcbtab[c]; >- 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"); >- droptcb(tcp); >- continue; >- } >-#else /* !USE_PROCFS */ >-# ifdef LINUX >- if (followfork) { >- char procdir[MAXPATHLEN]; >- DIR *dir; >- >- sprintf(procdir, "/proc/%d/task", tcp->pid); >- dir = opendir(procdir); >- if (dir != NULL) { >- unsigned int ntid = 0, nerr = 0; >- struct dirent *de; >- int tid; >- while ((de = readdir(dir)) != NULL) { >- if (de->d_fileno == 0 || >- de->d_name[0] == '.') >- continue; >- tid = atoi(de->d_name); >- if (tid <= 0) >- continue; >- ++ntid; >- if (ptrace(PTRACE_ATTACH, tid, >- (char *) 1, 0) < 0) >- ++nerr; >- else if (tid != tcbtab[c]->pid) { >- if (nprocs == tcbtabsize && >- expand_tcbtab()) >- tcp = NULL; >- else >- tcp = alloctcb(tid); >- if (tcp == NULL) >- exit(1); >- tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK; >- tcbtab[c]->nchildren++; >- tcbtab[c]->nclone_threads++; >- tcbtab[c]->nclone_detached++; >- tcp->parent = tcbtab[c]; >- } >- } >- closedir(dir); >- if (nerr == ntid) { >- perror("attach: ptrace(PTRACE_ATTACH, ...)"); >- droptcb(tcp); >- continue; >- } >- if (!qflag) { >- ntid -= nerr; >- if (ntid > 1) >- fprintf(stderr, "\ >-Process %u attached with %u threads - interrupt to quit\n", >- tcp->pid, ntid); >- else >- fprintf(stderr, "\ >-Process %u attached - interrupt to quit\n", >- tcp->pid); >- } >- continue; >- } >- } >-# endif >- if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) { >- perror("attach: ptrace(PTRACE_ATTACH, ...)"); >- droptcb(tcp); >- continue; >- } >-#endif /* !USE_PROCFS */ >- if (!qflag) >- fprintf(stderr, >- "Process %u attached - interrupt to quit\n", >- tcp->pid); >- } >- >- if (!pflag_seen) { >- struct stat statbuf; >- char *filename; >- char pathname[MAXPATHLEN]; >- >- filename = argv[optind]; >- if (strchr(filename, '/')) { >- if (strlen(filename) > sizeof pathname - 1) { >- errno = ENAMETOOLONG; >- perror("strace: exec"); >- exit(1); >- } >- strcpy(pathname, filename); >- } >-#ifdef USE_DEBUGGING_EXEC >- /* >- * Debuggers customarily check the current directory >- * first regardless of the path but doing that gives >- * security geeks a panic attack. >- */ >- else if (stat(filename, &statbuf) == 0) >- strcpy(pathname, filename); >-#endif /* USE_DEBUGGING_EXEC */ >- else { >- char *path; >- int m, n, len; >- >- for (path = getenv("PATH"); path && *path; path += m) { >- if (strchr(path, ':')) { >- n = strchr(path, ':') - path; >- m = n + 1; >- } >- else >- m = n = strlen(path); >- if (n == 0) { >- if (!getcwd(pathname, MAXPATHLEN)) >- continue; >- len = strlen(pathname); >- } >- else if (n > sizeof pathname - 1) >- continue; >- else { >- strncpy(pathname, path, n); >- len = n; >- } >- if (len && pathname[len - 1] != '/') >- pathname[len++] = '/'; >- strcpy(pathname + len, filename); >- if (stat(pathname, &statbuf) == 0 && >- /* Accept only regular files >- with some execute bits set. >- XXX not perfect, might still fail */ >- S_ISREG(statbuf.st_mode) && >- (statbuf.st_mode & 0111)) >- break; >- } >- } >- if (stat(pathname, &statbuf) < 0) { >- fprintf(stderr, "%s: %s: command not found\n", >- progname, filename); >- exit(1); >- } >- switch (pid = fork()) { >- case -1: >- perror("strace: fork"); >- cleanup(); >- exit(1); >- break; >- case 0: { >-#ifdef USE_PROCFS >- if (outf != stderr) close (fileno (outf)); >-#ifdef MIPS >- /* Kludge for SGI, see proc_open for details. */ >- sa.sa_handler = foobar; >- sa.sa_flags = 0; >- sigemptyset(&sa.sa_mask); >- sigaction(SIGINT, &sa, NULL); >-#endif /* MIPS */ >-#ifndef FREEBSD >- pause(); >-#else /* FREEBSD */ >- kill(getpid(), SIGSTOP); /* stop HERE */ >-#endif /* FREEBSD */ >-#else /* !USE_PROCFS */ >- if (outf!=stderr) >- close(fileno (outf)); >- >- if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) { >- perror("strace: ptrace(PTRACE_TRACEME, ...)"); >- return -1; >- } >- if (debug) >- kill(getpid(), SIGSTOP); >- >- if (username != NULL || geteuid() == 0) { >- uid_t run_euid = run_uid; >- gid_t run_egid = run_gid; >- >- if (statbuf.st_mode & S_ISUID) >- run_euid = statbuf.st_uid; >- if (statbuf.st_mode & S_ISGID) >- run_egid = statbuf.st_gid; >- >- /* >- * It is important to set groups before we >- * lose privileges on setuid. >- */ >- if (username != NULL) { >- if (initgroups(username, run_gid) < 0) { >- perror("initgroups"); >- exit(1); >- } >- if (setregid(run_gid, run_egid) < 0) { >- perror("setregid"); >- exit(1); >- } >- if (setreuid(run_uid, run_euid) < 0) { >- perror("setreuid"); >- exit(1); >- } >- } >- } >- else >- setreuid(run_uid, run_uid); >- >- /* >- * Induce an immediate stop so that the parent >- * will resume us with PTRACE_SYSCALL and display >- * this execve call normally. >- */ >- kill(getpid(), SIGSTOP); >-#endif /* !USE_PROCFS */ >- >- execv(pathname, &argv[optind]); >- perror("strace: exec"); >- _exit(1); >- break; >- } >- default: >- if ((tcp = alloctcb(pid)) == NULL) { >- cleanup(); >- exit(1); >- } >-#ifdef USE_PROCFS >- if (proc_open(tcp, 0) < 0) { >- fprintf(stderr, "trouble opening proc file\n"); >- cleanup(); >- exit(1); >- } >-#endif /* USE_PROCFS */ >- break; >- } >- } >- > sigemptyset(&empty_set); > sigemptyset(&blocked_set); > sa.sa_handler = SIG_IGN; >@@ -813,6 +843,11 @@ Process %u attached - interrupt to quit\ > sigaction(SIGCHLD, &sa, NULL); > #endif /* USE_PROCFS */ > >+ if (pflag_seen) >+ startup_attach(); >+ else >+ startup_child(&argv[optind]); >+ > if (trace() < 0) > exit(1); > cleanup(); >@@ -1306,7 +1341,7 @@ int sig; > { > int error = 0; > #ifdef LINUX >- int status, resumed; >+ int status, resumed, catch_sigstop; > struct tcb *zombie = NULL; > > /* If the group leader is lingering only because of this other >@@ -1330,6 +1365,12 @@ int sig; > #undef PTRACE_DETACH > #define PTRACE_DETACH PTRACE_SUNDETACH > #endif >+ /* >+ * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the >+ * expected SIGSTOP. We must catch exactly one as otherwise the >+ * detached process would be left stopped (process state T). >+ */ >+ catch_sigstop = (tcp->flags & TCB_STARTUP); > if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) { > /* On a clear day, you can see forever. */ > } >@@ -1343,13 +1384,15 @@ int sig; > if (errno != ESRCH) > perror("detach: checking sanity"); > } >- else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid >- : tcp->pid), >- tcp->pid, SIGSTOP) < 0) { >+ else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD >+ ? tcp->parent->pid : tcp->pid), >+ tcp->pid, SIGSTOP) < 0) { > if (errno != ESRCH) > perror("detach: stopping child"); > } >- else { >+ else >+ catch_sigstop = 1; >+ if (catch_sigstop) > for (;;) { > #ifdef __WALL > if (wait4(tcp->pid, &status, __WALL, NULL) < 0) { >@@ -1400,7 +1443,6 @@ int sig; > break; > } > } >- } > #endif /* LINUX */ > > #if defined(SUNOS4) >@@ -2121,6 +2163,8 @@ trace() > #endif /* LINUX */ > > while (nprocs != 0) { >+ if (interrupted) >+ return 0; > if (interactive) > sigprocmask(SIG_SETMASK, &empty_set, NULL); > #ifdef LINUX >@@ -2153,9 +2197,6 @@ trace() > if (interactive) > sigprocmask(SIG_BLOCK, &blocked_set, NULL); > >- if (interrupted) >- return 0; >- > if (pid == -1) { > switch (wait_errno) { > case EINTR: >@@ -2301,35 +2342,24 @@ Process %d attached (waiting for parent) > fprintf(stderr, "pid %u stopped, [%s]\n", > pid, signame(WSTOPSIG(status))); > >- if (tcp->flags & TCB_STARTUP) { >+ /* >+ * Interestingly, the process may stop >+ * with STOPSIG equal to some other signal >+ * than SIGSTOP if we happend to attach >+ * just before the process takes a signal. >+ */ >+ if ((tcp->flags & TCB_STARTUP) && WSTOPSIG(status) == SIGSTOP) { > /* > * This flag is there to keep us in sync. > * Next time this process stops it should > * really be entering a system call. > */ > tcp->flags &= ~TCB_STARTUP; >- if (tcp->flags & TCB_ATTACHED) { >+ if (tcp->flags & TCB_BPTSET) { > /* >- * Interestingly, the process may stop >- * with STOPSIG equal to some other signal >- * than SIGSTOP if we happend to attach >- * just before the process takes a signal. >+ * One example is a breakpoint inherited from >+ * parent through fork (). > */ >- if (!WIFSTOPPED(status)) { >- fprintf(stderr, >- "pid %u not stopped\n", pid); >- detach(tcp, WSTOPSIG(status)); >- continue; >- } >- } >- else { >-#ifdef SUNOS4 >- /* A child of us stopped at exec */ >- if (WSTOPSIG(status) == SIGTRAP && followvfork) >- fixvfork(tcp); >-#endif /* SUNOS4 */ >- } >- if (tcp->flags & TCB_BPTSET) { > if (clearbpt(tcp) < 0) /* Pretty fatal */ { > droptcb(tcp); > cleanup(); >@@ -2404,6 +2434,9 @@ Process %d attached (waiting for parent) > tcp->flags &= ~TCB_SUSPENDED; > continue; > } >+ /* we handled the STATUS, we are permitted to interrupt now. */ >+ if (interrupted) >+ return 0; > if (trace_syscall(tcp) < 0) { > if (tcp->flags & TCB_ATTACHED) > detach(tcp, 0);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 240986
:
155264
|
155446
|
155447
| 156701