ウィキペディアの「ptrace」記事に、Linux では、ptrace されたプロセス自体が別のプロセスを ptrace できないと主張する人が追加されました。私は、それが事実であるかどうか (また、そうである場合はその理由) を判断しようとしています。以下は、これをテストするために考案した簡単なプログラムです。私のプログラムは失敗します (サブサブプロセスが正しく実行されません) が、それは私のエラーであり、基本的なものではないと確信しています。
本質的に、最初のプロセスAはプロセスBを fork し、プロセス B はCを fork します。Aはその子Bを ptrace し、Bはその子Cを ptrace します。セットアップが完了すると、3 つのプロセスすべてが、 1 秒ごとに print A
、B
、またはstdout に書き込まれます。C
実際には、AとBは問題なく動作しますが、Cは 1 回しか印刷されず、スタックしてしまいます。で確認すると、 Cがカーネル関数でスタックしていることがps -eo pid,cmd,wchan
示されますが、残りは3 つすべてが期待される場所にあります。ptrace_stop
hrtimer_nanosleep
非常にまれに 3 つすべてが機能する (したがって、プログラムは A と B だけでなく C も出力します)。
何が間違っているかについての私の推測は次のとおりです。
- AがB
SIGCHLD
に関連するaを見て、 a がCへのシグナルと関係があることを確認し、 wait(2) が両方をBから来ていると報告している(ただし、両方の pid への PTRACE_CONT のハッキーな呼び出しは問題を解決しません)?SIGCHLD
- CはBによって ptrace されるべきです- Cは代わりにAによってptraceを継承しましたか?
誰かが私が間違っていることを理解できますか? ありがとう。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
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;
}