web-dev-qa-db-ja.com

非共有ベースの強制終了が--forkでのみ確実に機能するのはなぜですか?

この回答 から、_unshare -p_を介してLinuxPID名前空間を使用してプロセスサブツリー全体の信頼できる強制終了を実装できることを学びました。

ここに私が理解していない問題があります:

  • _-f_/_--fork_オプションを使用して共有を解除した場合にのみ機能します。

    _unshare -fp -- bash -c "watch /bin/sleep 10000 && echo hi"
    _

    これを実行し、_kill -9_そのbashのPIDを実行すると、必要に応じて、監視、スリープなどがすべて停止します。

  • しかし、_-f_なしで使用すると:

    _unshare -p -- bash -c "watch /bin/sleep 10000 && echo hi"
    _

    そして_kill -9_ bash PIDの場合、watchはPID1(systemdである私のUbuntu上)に親が変更されるため、すべての子を殺すという望ましい効果はありません。

質問:

  • 目的の効果を得るために_--fork_が必要なのはなぜですか? unshareがフォークなしでexec()を使用するだけでは不十分なのはなぜですか?
  • これに対する回避策はありますか? unshareを開始して作成されたPIDに_kill -9_を便利に送信して、その下のすべてを強制終了できればと思います。しかし、_--fork_を使用すると、unshareを開始したときに返されたpidを強制終了すると、unshareが強制終了され、bashがPID1に再ペアレント化されます。これは、unshareがPID名前空間にないためです。

_&& echo hi_にコマンドを1つだけ与えると、それがexec()になり、bashプロセスがなくなって(置き換えられ)、強制終了できないため、_bash -c_が必要であることに注意してください。そのPID。

3
nh2

説明したように この有用な回答で _-n_(unshare(CLONE_NEWPID))の効果は、フォークされた最初の子プロセスに対してのみ作用します。

特に、 man 2 unshare は_CLONE_NEWPID_について言っています:

PID名前空間の共有を解除して、呼び出し元のプロセスが、既存のプロセスと共有されていない子の新しいPID名前空間を持つようにします。

呼び出しプロセスは新しい名前空間に移動されません。

呼び出しプロセスによって作成された最初の子は、プロセスID 1を持ち、新しい名前空間でinit(1)の役割を引き受けます。


殺害が確実に機能するようにunshareにパッチを適用する

質問をしてから、ここ数時間で_util-linux_( ここにリクエストをプル )にパッチを作成し、unshareに_--kill-child_フラグを追加しました。 。

編集:これは、util-linux _v2.32_の一部としてマージおよびリリースされました。

次のように使用できます。

_unshare -fp --kill-child -- bash -c "watch /bin/sleep 10000 && echo hi"
_

unshareを強制終了すると、プロセスツリー全体が破壊されます。

rootなし

カーネルでユーザー名前空間が有効になっている場合(_CONFIG_USER_NS=y_)、_-U_フラグを渡すことにより、root権限なしで使用することもできます。

_unshare -Ufp --kill-child -- bash -c "watch /bin/sleep 10000 && echo hi"
_
2
nh2