仮想の状況があります。
互いを監視する2つのストレス処理S1及びS2があると仮定する。
どうやってこれができますか?
straceのコマンドラインオプションには-p PID
必要なPIDを渡す方法があります。 strace ソースコードを変更できます。これは、-P 0
ユーザーにPIDを要求することを意味します。たとえば、STDINのread()です。 2 つのシェル セッションで 2 つの strace プロセスを実行し、3 番目のシェルで PID を見つけることができる場合は、その入力を S1 と S2 に提供し、互いに監視することができます。
S1とS2が詰まっていますか?それとも無限ループに入ったり、すぐにクラッシュしたり…?繰り返しますが、別のstraceプロセスS3があると仮定し、
-p -1
それを使用してソースコードを変更してS3に自己監視を指示します。たとえば、STDINの代わりにgetpid()を使用します。 S3がクラッシュしますか?それとも追加の処理なしで中断されますか?どんなイベントが発生するのを待っていますが、待っているので何も起こりませんか?
straceのマニュアルページには、initプロセスを監視できないことが示されています。循環依存性や循環を避けるために strace やカーネルによって施行されるその他の制限はありますか?
いくつかの特別な場合:
S4はS5を監視し、S5はS6を監視し、S6はS4を監視します。
S7とS8は、S7がS8の上位になり、互いに監視します。
さらに特別な場合も可能です。
編集(@RalphRönnquistと@pfnueselのコメント後):
https://github.com/bnoordhuis/strace/blob/master/strace.c#L941
if (pid <= 0) {
error_msg_and_die("Invalid process id: '%s'", opt);
}
if (pid == strace_tracer_pid) {
error_msg_and_die("I'm sorry, I can't let you do that, Dave.");
}
strace.c
具体的にpid == strace_tracer_pid
検査が行われない場合やその他特別な事情がある場合はどうなりますか?プロセスモニタ自体に(カーネルに)技術的な制限がありますか? 2つ(または3つ以上)のプロセスグループが自分自身を監視するのはどうですか?システムがクラッシュしたりハングしたりしますか?
答え1
% sh -c 'exec strace -p $$'
strace: I'm sorry, I can't let you do that, Dave.
:-)
答え2
私はLinuxにのみ答えます。
驚くべきことに、最新のカーネルでは、ptrace
実際にトレースを実行するために使用されるシステムコールがinitプロセスを追跡することができます。strace
マニュアルページには次のように記載されています。
EPERM The specified process cannot be traced. This could be because
the tracer has insufficient privileges (the required capability
is CAP_SYS_PTRACE); unprivileged processes cannot trace pro‐
cesses that they cannot send signals to or those running set-
user-ID/set-group-ID programs, for obvious reasons. Alterna‐
tively, the process may already be being traced, or (on kernels
before 2.6.26) be init(8) (PID 1).
これは、バージョン2.6.26から追跡できることを意味しますinit
。もちろん、これを行うにはroot権限が必要です。私のシステムのバイナリをstrace
使ってそれを追跡し、init
実際にそれを使ってgdb
接続しinit
て終了することもできます。 (これを行うと、システムはすぐに停止します。)
ptrace
プロセスはそれを使用してそれ自身を追跡できないため、strace
選択しないと、自己追跡中に失敗し続けます。次の手順:
#include <sys/ptrace.h>
#include <stdio.h>
#include <unistd.h>
int main() {
if (ptrace(PTRACE_ATTACH, getpid(), 0, 0) == -1) {
perror(NULL);
}
}
印刷Operation not permitted
(つまり、)EPERM
。カーネルの実行今回の宿泊ptrace.c
:
retval = -EPERM;
if (unlikely(task->flags & PF_KTHREAD))
goto out;
if (same_thread_group(task, current)) // <-- this is the one
goto out;
これで、2つのstrace
プロセスが互いに追跡できます。カーネルはこれを防止せず、結果を直接観察できます。私の場合、最初のプロセス(PID = 5882)で最後に印刷された内容は次のstrace
とおりです。
ptrace(PTRACE_SEIZE, 5882, 0, 0x11
そして、2番目のstrace
プロセス(PID = 5890)はまったく何も印刷しません。ps
は、両方のプロセスが状態にあることを示していますt
。proc(5)
マンページによると、これはトレースが停止したことを意味します。
これが発生するのは、SIGKILL
トレーサがシステムコールに入るか出るたびに停止し、シグナル(例外)が転送されようとするためです。
プロセス5882がすでにプロセス5890を追跡していると仮定する。これにより、次の一連のイベントを推論できます。
- プロセス5890は
ptrace
システムコールを開始し、プロセス5882を追跡しようとする。プロセス5890がトレース停止に入る。 - プロセス5882は、追跡
SIGCHLD
中のプロセス5890が停止したことを知らせる。 (追跡された停止プロセスは「SIGTRAP」シグナルを受け取ったようです。) - プロセス5882は、追跡対象がシステムコールを実行したことを確認し、プロセス5890が実行しようとしているシステムコールに関する情報およびパラメータを忠実に印刷する。これが最後の出力です。
ptrace(PTRACE_SYSCALL, 5890, ...)
プロセス5890が続くように5882呼び出しを処理します。- プロセス5890はトレース停止を終了し、それを実行する
ptrace(PTRACE_SEIZE, 5882, ...)
。後者が返されると、プロセス5890は追跡停止に入る。 SIGCHLD
追跡対象が再び停止されたため、プロセス5882が送信されました。トレース中なので、信号を受信するとトレース停止状態に入ります。
今、両方のプロセスが停止しました。終わる。
この例に示すように、2つのプロセスが互いに追跡する状況は、カーネルに本質的な論理的な困難をもたらさない。これは、おそらくカーネルコードにこの状況を防ぐためのチェックが含まれていない理由です。お互いを追跡する2つのプロセスにはあまり役に立ちません。
答え3
システムを停止できる循環依存関係またはループの実際の例を示したいと思いました。
Xセッションとグラフィカル端末エミュレータで次のコマンドを実行してXorg.bin pidを取得します。
[xiaobai@xiaobai tmp]$ pgrep Xorg
1780
[xiaobai@xiaobai tmp]$
次に、次のようにします。
[xiaobai@xiaobai tmp]$ sudo strace -p 1780
数秒(〜5秒)後、Fedora 21 gnome 3.14.0ではデスクトップ全体が停止し、電源ボタンをオフにする必要があります。
sudo strace -p 1780
ただし、Ctrl-alt-F1 | 7または他のttyを介して実行しようとすると、sudo strace -p 1780 2>/tmp/strace.log
どちらも停止しません。
したがって、straceはXorgの出力を受け取り、それをXorgに印刷して無限ループとストップを生成すると結論付けることができます。