Linux でのプロセス間重複

Linux でのプロセス間重複

Linux上の無関係なプロセスで実行されているファイル記述子を複製したいのですが、送信メッセージ(2)およびSCM_RIGHTS(例:https://stackoverflow.com/questions/4489433/sending-file-descriptor-over-unix-domain-socket-and-select) ですが、これは他のプロセスが協力している場合にのみ機能します。他のプロセスからの積極的な協力を必要としないソリューションが必要です。また、最初にファイル記述子を作成し、コピーを保持してから他のプロセスを作成することもできますが、他のプロセスが独自のファイル記述子を作成するソリューションが必要です。

ファイル記述子を確認できます:

$ ls -l /proc/13115/fd/3
lrwx------ 1 pts pts 64 2013-05-04 13:15 /proc/13115/fd/3 -> socket:[19445454]

ただし、open("/proc/13115/fd/3", O_RDWR)別のプロセスで実行するとエラーが返されますそのようなデバイスまたはアドレスはありません他に何かいい方法はありますか?おそらくptrace?

答え1

これは設計によるものです。他のプロセスとのファイル記述子の共有は明示的です。デフォルトでは、ファイル記述子はプロセス自身のメモリと同じようにプライベートです。

いつものように、あなたが権利を持っているならptraceプロセスでは、 を呼び出すことを含め、何でも好きなことができますsendmsg。従来、 を呼び出すにはptrace同じユーザー ID で実行する必要がありますが、SELinux、機能、jail などのセキュリティ制限により、さらに制限が厳しくなる場合があります。たとえば、Ubuntu のデフォルトの構成では、非ルート プロセスは、(AppArmor を通じて) 自分の子孫に対してptraceのみ を呼び出すことができます。ptrace

堅牢な使用はptrace少し難しいです。正しいデータを挿入し、何も上書きしないようにし、後始末をしなければなりません。そのため、回りくどい方法でコードを挿入し、既存のツールでそのコードをトリガーすることをお勧めします。

コードを含む小さな共有ライブラリを作成しsendmsgLD_PRELOADそれを他のプロセスに渡します。ここにいくつかあります未テストエラーチェックが欠落しているスケルトン コード。

int pts_gift_fd (char *path, int fd) {
    int sock;
    struct sockaddr_un addr = {0};
    struct msghdr msg = {0};
    struct iovec iov = {0};
    addr.sun_family = AF_UNIX;
    strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
    /* Populate msg, iov as in the code you've already found */
    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    connect(sock, (struct sockaddr*)&addr, sizeof(addr));
    sendmsg(sock, &msg, 0);
    close(sock);
}

次に、コードをトリガーするには、 を実行してgdb -n -pid 13115 -batch -x /dev/stdinpopen次のように入力します (%dは取得する fd で、 は%s以前に作成してリッスンしている Unix ソケットへのパスです)。

call pts_gift_fd("%s", %d)
detach
quit

答え2

これは、関係のないプロセスのメモリにアクセスできないのと同じ理由で、ファイル記述子が他のプロセスのメモリの一部です。このような情報が存在する唯一の理由は、/procカーネルがそこに提供し、読み取り専用であるためです(したがって、コピープロセス メモリの)。

それがファイルに関係するものであれば、もちろんファイルにアクセスしてみることができます。ソケットの場合は、次のようにして覗き見することができます。libpcapまたはそこから派生したもの。

状況は基本的に次のようになります。ファイル記述子は(再び)プロセスのメモリの一部です。記述子にはカーネル空間に存在する基礎バッファがあります。プロセスが記述子を読み書きするときは、このバッファに書き込みます。送信データについては、カーネルはバッファを適切にフラッシュします(ハードウェアに)。受信データについては、プロセスがバッファを空にすると、カーネルはバッファを(ハードウェアから)補充します。私の知る限り、これらのバッファは他のプロセスからはアクセスできませんが、いくつかの手段(例:libpcap)があります。読むproc インターフェイスがプロセスのユーザー空間メモリからデータを提供できるのと同様に、特定のカーネル インターフェイスによって決定される何らかの形式のデータ。

関連情報