idleとは - ubuntu python 3.6 0



Ubuntu 15.10で、pythonで作成したsudoプロセスを終了できません (1)

私はUbuntu 15.10に更新しました。突然Python 2.7では、 ルートになったときに作成したプロセスを終了できません。 たとえば、これはtcpdumpを終了しません。

import subprocess, shlex, time
tcpdump_command = "sudo tcpdump -w example.pcap -i eth0 -n icmp"
tcpdump_process = subprocess.Popen(
                                shlex.split(tcpdump_command),
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
time.sleep(1)
tcpdump_process.terminate()
tcpdump_out, tcpdump_err = tcpdump_process.communicate()

何が起こった? 以前のバージョンでも動作します。


TL; DRsudoは、 2014年5月28日sudo 1.8.11リリースされたコミットからコマンドのプロセスグループ内のプロセスから送られたシグナルを転送しませんsudo 1.8.11 - pythonプロセス(sudoの親プロセス)とtcpdumpプロセス(孫プロセス) sudo.terminate()によって送信されたSIGTERM tcpdumpプロセスに転送しません。

これは、rootユーザーである間にそのコードを実行しているときと、通常のユーザーであるときに同じ動作を示します+ sudo

通常のユーザーとして実行すると、 OSError: [Errno 1] Operation not permittedが発生しOSError: [Errno 1] Operation not permitted .terminate() OSError: [Errno 1] Operation not permitted例外でOSError: [Errno 1] Operation not permitted (期待どおり)。

sudotcpdumpプロセスが.terminate().terminate() 、コードがUbuntu 15.10で.communicate()にスタックされています。

同じコードでUbuntu 12.04の両方のプロセスが終了します。

変数がtcpdump (孫)ではなくsudoプロセス(子プロセス)を参照しているため、 tcpdump_process nameは誤解を招きます。

python
└─ sudo tcpdump -w example.pcap -i eth0 -n icmp
   └─ tcpdump -w example.pcap -i eth0 -n icmp          

@ Mr.Eはコメント指摘したように 、ここではsudoは必要ありません。あなたはすでにrootになっています(ただし、root でなければ ネットワークを盗聴することはできません)。 あなたがsudoを落とすならば。 .terminate()動作します。

一般に、 .terminate()はプロセスツリー全体を再帰的に終了させないので、孫プロセスが存続することが期待されます。 sudoは特別なケースですが、 sudo(8)のマニュアルページから

コマンドがsudoプロセスの子として実行されると、 sudoは受信したシグナルを sudo中継します強調は私のものです

つまり、 sudoSIGTERMtcpdumpリレーし、 tcpdumpはtcpdump(8)のマニュアルページからSIGTERMでのパケットのキャプチャを停止する必要があります

Tcpdumpは、SIGINTシグナル(割り込み文字、通常はcontrol-Cを入力するなどして生成される)またはSIGTERMシグナル(通常はkill(1)コマンドで生成される)によって中断されるまで、 ;

つまり、 tcpdump_process.terminate()はシグナルをtcpdump中継するsudo SIGTERMを送信し、キャプチャを停止し、exitと.communicate()両方がpythonスクリプトにtcpdumpのstderr出力を返します。

注意:原則として、同じsudo(8)のマニュアルページから子プロセスを作成せずにコマンドを実行することができます

特殊なケースとして、ポリシープラグインがclose関数を定義せず、ptyが必要でない場合、 sudoは最初にfork(2)を呼び出す代わりに直接コマンドを実行します

.terminate()tcpdumpプロセスに直接SIGTERMを送るかもしれませんが、それは説明ではありません: sudo tcpdumpは私のテストでUbuntu 12.04と15.10の2つのプロセスを作成します。

シェルでsudo tcpdump -w example.pcap -i eth0 -n icmpを実行すると、 kill -SIGTERMは両方のプロセスを終了します。 Python 2.7.3(Ubuntu 12.04で使用)はUbuntu 15.10でも同じように動作しますが、Python 3でも失敗します。

これは、プロセスグループ( ジョブ制御 )に関連していますpreexec_fn=os.setpgrpsubprocess.Popen() preexec_fn=os.setpgrpて、 sudoが新しいプロセスグループ(ジョブ)になるようにします。シェルの場合と同様に、リーダーはtcpdump_process.terminate()はこの場合に機能します。

何が起こった? 以前のバージョンでも動作します。

説明はsudoのソースコードにあります

コマンドのプロセスグループ内のプロセスから送られたシグナルを転送しないでください 。子プロセスを間接的にkillしないように転送しないでください。 たとえば、kill(-1、SIGTERM)を呼び出して他のすべてのプロセスを強制終了する、いくつかのバージョンのリブートでこれが起こる可能性があります。 強調は私のものです

preexec_fn=os.setpgrpsudoのプロセスグループを変更します。 tcpdumpプロセスのようなsudoの子孫はグループを継承します。 pythontcpdumpは同じプロセスグループに属していないため、 .terminate()によって送信された信号はsudoによってtcpdump中継され、終了します。

Ubuntu 15.04はSudo version 1.8.9p5使用していますが、質問のコードはそのままです。

Ubuntu 15.10はコミットを含むSudo version 1.8.12を使用します。

wdo(15.10)のsudo(8)のマニュアルページでは、子プロセス自体についてしか話していません。プロセスグループについては言及していません。

特殊なケースとして、sudoは、実行しているコマンドによって送信されたシグナルを中継しません。

その代わりにする必要があります:

特殊なケースとして、sudoはプロセスが実行しているコマンドのプロセスグループ内のプロセスによって送信されたシグナルを中継しません。

Ubuntuのバグトラッカー上流のバグトラッカーでドキュメントの問題を開くことができます。





ubuntu-15.10