straceはどのようにそれ自体を監視しますか?

straceはどのようにそれ自体を監視しますか?

仮想の状況があります。

  1. 互いを監視する2つのストレス処理S1及びS2があると仮定する。
    どうやってこれができますか?
    straceのコマンドラインオプションには-p PID必要なPIDを渡す方法があります。 strace ソースコードを変更できます。これは、-P 0ユーザーにPIDを要求することを意味します。たとえば、STDINのread()です。 2 つのシェル セッションで 2 つの strace プロセスを実行し、3 番目のシェルで PID を見つけることができる場合は、その入力を S1 と S2 に提供し、互いに監視することができます。
    S1とS2が詰まっていますか?それとも無限ループに入ったり、すぐにクラッシュしたり…?

  2. 繰り返しますが、別の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は、両方のプロセスが状態にあることを示していますtproc(5)マンページによると、これはトレースが停止したことを意味します。

これが発生するのは、SIGKILLトレーサがシステムコールに入るか出るたびに停止し、シグナル(例外)が転送されようとするためです。

プロセス5882がすでにプロセス5890を追跡していると仮定する。これにより、次の一連のイベントを推論できます。

  1. プロセス5890はptraceシステムコールを開始し、プロセス5882を追跡しようとする。プロセス5890がトレース停止に入る。
  2. プロセス5882は、追跡SIGCHLD中のプロセス5890が停止したことを知らせる。 (追跡された停止プロセスは「SIGTRAP」シグナルを受け取ったようです。)
  3. プロセス5882は、追跡対象がシステムコールを実行したことを確認し、プロセス5890が実行しようとしているシステムコールに関する情報およびパラメータを忠実に印刷する。これが最後の出力です。
  4. ptrace(PTRACE_SYSCALL, 5890, ...)プロセス5890が続くように5882呼び出しを処理します。
  5. プロセス5890はトレース停止を終了し、それを実行するptrace(PTRACE_SEIZE, 5882, ...)。後者が返されると、プロセス5890は追跡停止に入る。
  6. 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に印刷して無限ループとストップを生成すると結論付けることができます。

関連情報