Jemand hat dem Wikipedia-Artikel "ptrace" hinzugefügt, dass auf Linux ein durch ptrace überwachter Prozess keinen anderen Prozess ptracen kann. Ich versuche herauszufinden, ob das stimmt und falls ja, warum. Hier ist mein einfaches Programm, das ich erstellt habe, um das zu testen. Mein Programm schlägt fehl (der Unterunterprozess wird nicht ordnungsgemäß ausgeführt), aber ich bin ziemlich überzeugt, dass es mein Fehler ist und nicht etwas Grundlegendes.
Im Wesentlichen erzeugt der Ausgangsprozess A den Prozess B, der wiederum den Prozess C erzeugt. A überwacht sein Kind B, B überwacht sein Kind C. Sobald sie eingerichtet sind, sind alle drei Prozesse so geschrieben, dass sie einmal pro Sekunde einfach A
, B
oder C
auf stdout ausgeben.
In der Praxis ist es so, dass A und B funktionieren, aber C nur einmal druckt und dann stecken bleibt. Wenn ich mit ps -eo pid,cmd,wchan
überprüfe, zeigt sich, dass C in der Kernelfunktion ptrace_stop
stecken bleibt, während die anderen in hrtimer_nanosleep
sind, wo ich erwarten würde, dass alle drei sind.
Sehr selten funktionieren alle drei (das Programm druckt also auch Cs sowie As und Bs), was mich glauben lässt, dass es ein Rennzustand beim initialen Setup gibt.
Meine Vermutungen, was falsch sein könnte, sind:
- irgendetwas damit, dass A ein
SIGCHLD
sieht, das sich auf B bezieht, einSIGCHLD
das sich auf ein Signal an C bezieht, und wait(2) beide als von B kommend meldet (aber ein hacky Aufruf von PTRACE_CONT zu beiden pids behebt das Problem nicht)? - C sollte von B überwacht werden - hat C stattdessen das PTRACE von A geerbt (und der Aufruf von B zu ptrace hat weder einen Fehler erzeugt noch dies überschrieben)?
Kann jemand herausfinden, was ich falsch mache? Vielen Dank.
#include
#include
#include
#include
#include
#include
static void a(){
while(1){
printf ("A\n");
fflush(stdout);
sleep(1);
}
}
static void b(){
while(1){
printf ("B\n");
fflush(stdout);
sleep(1);
}
}
static void c(){
while(1){
printf ("C\n");
fflush(stdout);
sleep(1);
}
}
static void sigchld_handler(int sig){
int result;
pid_t child_pid = wait(NULL); // find who send us this SIGCHLD
printf("SIGCHLD on %d\n", child_pid);
result=ptrace(PTRACE_CONT, child_pid, sig, NULL);
if(result) {
perror("continuing after SIGCHLD");
}
}
int main(int argc,
char **argv){
pid_t mychild_pid;
int result;
printf("pidA = %d\n", getpid());
signal(SIGCHLD, sigchld_handler);
mychild_pid = fork();
if (mychild_pid) {
printf("pidB = %d\n", mychild_pid);
result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
if(result==-1){
perror("outer ptrace");
}
a();
}
else {
mychild_pid = fork();
if (mychild_pid) {
printf("pidC = %d\n", mychild_pid);
result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
if(result==-1){
perror("inner ptrace");
}
b();
}
else {
c();
}
}
return 0;
}