Re: man-pages-3.37 is released

From: Denys Vlasenko
Date: Fri Mar 16 2012 - 20:16:14 EST


On Friday 09 March 2012 18:27, Michael Kerrisk (man-pages) wrote:
> ptrace.2
> Denys Vlasenko [Oleg Nesterov, Tejun Heo]
> add extended description of various ptrace quirks

Pulled current git and spotted a few broken places.

The following kinds of ptrace-stops exist: signal-delivery-stops,
group-stop, PTRACE_EVENT stops, syscall-stops PTRACE_SINGLESTEP,
PTRACE_SYSEMU, and They all are reported by waitpid(2) with WIF-
STOPPED(status) true.

The text is broken after "syscall-stops" word. Corresponding source is:

group-stop, PTRACE_EVENT stops, syscall-stops
.BR PTRACE_SINGLESTEP ,
.BR PTRACE_SYSEMU ,
and
.BE PTRACE_SYSEMU_SINGLESTEP .



Signal-delivery-stop is observed by the tracer as waitpid(2) returning
with WIFSTOPPED(status) true, with the stopping signal returned by
WSTOPSIG(status). If the stopping signal is SIGTRAP, this may be a
different kind of ptrace-stop; ...

The two instances of word "stopping" above are wrong and need to be deleted:
ANY signal is reported this way, not only four signals which stop processes.
This is an especially bad disinformation because in the sentences below
we again use word "stopping":

... see the "Syscall-stops" and "execve"
sections below for details. If WSTOPSIG(status) returns a stopping
signal, this may be a group-stop; see below.

but here, we do mean "stopping" = "SIGSTOP/TSTP/TTIN/TTOU".



Note that a suppressed signal still causes system calls to return
prematurely. Restartable system calls will be restarted (the tracer
will observe the tracee to execute restart_syscall(2) if the tracer
uses PTRACE_SYSCALL); non-restartable system calls may fail with EINTR
even though no observable signal is injected to the tracee.

I learned more about this mechanism and the above text is wrong.
A better text would be:

Note that a suppressed signal still causes system calls to return pre-
maturely. In this case system calls will be restarted: the tracer will
observe the tracee to re-execute interrupted system call (or
restart_syscall(2) system call for a few syscalls which use a different
mechanism for restarting) if the tracer uses PTRACE_SYSCALL. Even sys-
tem calls (such as poll(2)) which are not restartable after signal are
restarted after signal is suppressed; however, kernel bugs exist which
cause some syscalls to fail with EINTR even though no observable signal
is injected to the tracee.



* All other threads stop in PTRACE_EVENT_EXIT stop, if the
PTRACE_O_TRACEEXIT option was turned on. Then all other threads
except the thread group leader report death as if they exited via
_exit(2) with exit code 0.

* Then a PTRACE_EVENT_EXEC stop happens, if the PTRACE_O_TRACEEXEC
option was turned on.

* The execing tracee changes its thread ID while it is in the
execve(2). (Remember, under ptrace, the "pid" returned from wait-
pid(2), or fed into ptrace calls, is the tracee's thread ID.) That
is, the tracee's thread ID is reset to be the same as its process
ID, which is the same as the thread group leader's thread ID.

Above, bullet points 2 and 3 need to be swapped: thread ID change happens
before PTRACE_EVENT_EXEC.


* If the thread group leader has reported its death by this time, it
appears to the tracer that the dead thread leader "reappears from
nowhere".

Thread group leader does not report its death until there is
at least one other live thread.



The PTRACE_O_TRACEEXEC option is the recommended tool for dealing with
this situation. It enables PTRACE_EVENT_EXEC stop, which occurs before
execve(2) returns. First, it enables PTRACE_EVENT_EXEC-stop, which
occurs before execve(2) returns.

Duplicate sentence.

Currently, there is no way to retrieve the former thread ID of the
execing tracee. If the tracer doesn't keep track of its tracees'
thread group relations, it may be unable to know which tracee execed
and therefore no longer exists under the old thread ID due to a thread
ID change.

Two paragraphs above, we just said "In this stop, the tracer can use
PTRACE_GETEVENTMSG to retrieve the tracee's former thread ID. (This
feature was introduced in Linux 3.0)."
So it is no longer true.



Also, I propose the following additon to BUGS:

Some syscalls return with EINTR if a signal was sent to a tracee, but
delivery was suppressed by the tracer. (This is very typical operation:
it is usually done by debuggers on every attach, in order to not intro-
duce a bogus SIGSTOP). As of Linux-3.2, the following syscalls are
affected: epoll_wait(2), read(2) from inotify file descriptor. The list
is likely incomplete.


The patch against current git is below.
--
vda



diff --git a/man2/ptrace.2 b/man2/ptrace.2
index 37c4dff..7f3c219 100644
--- a/man2/ptrace.2
+++ b/man2/ptrace.2
@@ -722,11 +722,7 @@ Example:
.\" describe how wait notifications queue (or not queue)
.LP
The following kinds of ptrace-stops exist: signal-delivery-stops,
-group-stop, PTRACE_EVENT stops, syscall-stops
-.BR PTRACE_SINGLESTEP ,
-.BR PTRACE_SYSEMU ,
-and
-.BE PTRACE_SYSEMU_SINGLESTEP .
+group-stop, PTRACE_EVENT stops, syscall-stops.
They all are reported by
.BR waitpid (2)
with
@@ -766,9 +762,9 @@ Signal-delivery-stop is observed by the tracer as
.BR waitpid (2)
returning with
.I WIFSTOPPED(status)
-true, with the stopping signal returned by
+true, with the signal returned by
.IR WSTOPSIG(status) .
-If the stopping signal is
+If the signal is
.BR SIGTRAP ,
this may be a different kind of ptrace-stop;
see the "Syscall-stops" and "execve" sections below for details.
@@ -802,12 +798,17 @@ value: the tracer can cause a different signal to be injected.
.LP
Note that a suppressed signal still causes system calls to return
prematurely.
-Restartable system calls will be restarted (the tracer will
-observe the tracee to execute
+In this case system calls will be restarted: the tracer will
+observe the tracee to re-execute interrupted system call (or
.BR restart_syscall(2)
-if the tracer uses
-.BR PTRACE_SYSCALL );
-non-restartable system calls may fail with
+system call for a few syscalls which use a different mechanism
+for restarting) if the tracer uses
+.BR PTRACE_SYSCALL .
+Even system calls (such as
+.BR poll(2) )
+which are not restartable after signal are restarted after
+signal is suppressed; however, kernel bugs exist which cause
+some syscalls to fail with
.B EINTR
even though no observable signal is injected to the tracee.
.LP
@@ -1406,12 +1407,6 @@ death as if they exited via
.BR _exit (2)
with exit code 0.
.IP *
-Then a
-.B PTRACE_EVENT_EXEC
-stop happens, if the
-.BR PTRACE_O_TRACEEXEC
-option was turned on.
-.IP *
The execing tracee changes its thread ID while it is in the
.BR execve (2).
(Remember, under ptrace, the "pid" returned from
@@ -1420,9 +1415,22 @@ or fed into ptrace calls, is the tracee's thread ID.)
That is, the tracee's thread ID is reset to be the same as its process ID,
which is the same as the thread group leader's thread ID.
.IP *
-If the thread group leader has reported its death by this time,
+Then a
+.B PTRACE_EVENT_EXEC
+stop happens, if the
+.BR PTRACE_O_TRACEEXEC
+option was turned on.
+.IP *
+If the thread group leader has reported its
+.B PTRACE_EVENT_EXIT
+stop by this time,
it appears to the tracer that
the dead thread leader "reappears from nowhere".
+(Note: thread group leader does not report death via
+.I WIFEXITED(status)
+until there is at least one other live thread.
+This eliminates possibility that tracer will see
+it dying and then reappearing.)
If the thread group leader was still alive,
for the tracer this may look as if thread group leader
returns from a different system call than it entered,
@@ -1440,11 +1448,6 @@ the thread ID change in the tracee.
The
.B PTRACE_O_TRACEEXEC
option is the recommended tool for dealing with this situation.
-It enables
-.B PTRACE_EVENT_EXEC
-stop, which occurs before
-.BR execve (2)
-returns.
First, it enables
.BR PTRACE_EVENT_EXEC -stop,
which occurs before
@@ -1475,13 +1478,7 @@ data structures describing the threads of this process,
and retain only one data structure\(emone which
describes the single still running tracee, with

- thread ID == thread group ID == process id.
-.LP
-Currently, there is no way to retrieve the former
-thread ID of the execing tracee.
-If the tracer doesn't keep track of its tracees' thread group relations,
-it may be unable to know which tracee execed and therefore no longer
-exists under the old thread ID due to a thread ID change.
+ thread ID == thread group ID == process ID.
.LP
Example: two threads call
.BR execve (2)
@@ -1499,10 +1496,6 @@ PID2 execve("/bin/bar", "bar" <unfinished ...>
PID0 <... execve resumed> ) = 0
.fi
.LP
-In this situation, there is no way to know which
-.BR execve (2)
-succeeded.
-.LP
If the
.B PTRACE_O_TRACEEXEC
option is
@@ -1713,6 +1706,17 @@ This may be changed in the future;
.B SIGKILL
is meant to always immediately kill tasks even under ptrace.
Last confirmed on 2.6.38.6.
+.LP
+Some syscalls return with
+.B EINTR
+if a signal was sent to a tracee, but delivery was suppressed
+by the tracer. (This is very typical operation: it is usually
+done by debuggers on every attach, in order to not introduce
+a bogus SIGSTOP).
+As of linux 3.2.9, the following syscalls are affected:
+.BR epoll_wait (2),
+.BR read (2)
+from inotify file descriptor. The list is likely incomplete.
.SH "SEE ALSO"
.BR gdb (1),
.BR strace (1),
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/