2015-12-17 18 views
5

我剛剛更新到Ubuntu 15.10,突然在Python 2.7,我不能終止當我創建了一個過程。 例如,這不會終止的tcpdump:不能終止與Python創建一個sudo的過程中,在Ubuntu 15.10

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() 

發生了什麼?它適用於以前的版本。

+3

如果你在做root時運行這個,爲什麼你需要調用sudo?你想做什麼? –

+0

好的,好點。沒有'sudo'它似乎工作。但爲什麼它可以在以前的所有版本上運行? –

+0

我不知道爲什麼,最可能的情況是,當您升級到15.10時,您的sudoer或與其相關的特權或其組的更改的配置會發生變化。也許你在沒有root權限的情況下運行你的python並且它不能殺死提升的shell(導致sudo) –

回答

8

TL; DRsudo不轉發通過的過程中sudo 1.8.11釋放的命令的進程組since 28 May 2014 commit在發送的信號 - 蟒處理(須藤的父)和tcpdump的處理(孫)是相同的處理組中的因此sudo不會將.terminate()發送的SIGTERM信號轉發到tcpdump進程。


運行的代碼時,同時root用戶,並同時作爲一個普通用戶+ sudo的

運行作爲一個普通用戶它顯示了相同的行爲提出了對.terminate()OSError: [Errno 1] Operation not permitted異常(如預期)。

運行爲root重現問題:sudotcpdump進程沒有殺害.terminate()和代碼粘貼在.communicate()在Ubuntu 15.10。

相同的代碼會殺死Ubuntu 12.04上的兩個進程。

tcpdump_process名稱是誤導,因爲該變量是指sudo進程(子進程),不tcpdump(孫):

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

由於@Mr.E pointed out in the comments,你不需要sudo在這裏:你是根已經(儘管你不應該 - 你可以sniff the network without root)。如果你放棄sudo; .terminate()作品。

一般而言,.terminate()不會以遞歸方式終止整個進程樹,因此預計孫子進程會存活。雖然sudo是一個特例,from sudo(8) man page

當運行命令爲sudo過程的孩子,sudo繼電器信號它接收到的命令。 重點是我

sudo應該中繼SIGTERMtcpdumptcpdump should stop capturing packets on SIGTERM, from tcpdump(8) man page

tcpdump的意志,...,繼續捕獲數據包直到它被一個SIGINT信號中斷(例如,通過鍵入您的 中斷字符,通常爲control-C)或SIGTERM信號 (通常使用kill(1)命令生成)中斷爲 ;

預期的行爲是tcpdump_process.terminate()發送SIGTERM到sudo哪個中繼信號到tcpdump應停止捕獲和兩個過程退出和返回.communicate()tcpdump的stderr輸出到Python腳本。

注:原則上該命令可以在沒有創建子進程,from the same sudo(8) man page運行:

作爲一個特殊的情況下,如果政策插件沒有定義密切 功能,並沒有PTY是必需的,sudo將直接執行命令 代替調用叉(2)第一

,因此.terminate()可以發送SIGTERM直接在tcpdump過程 - 儘管它不是解釋:在我的測試中,在Ubuntu 12.04和15.10上創建了兩個進程。

如果我在shell中運行sudo tcpdump -w example.pcap -i eth0 -n icmp,則kill -SIGTERM終止這兩個進程。它看起來不像Python問題(Python 2.7.3(在Ubuntu 12.04上使用)在Ubuntu 15.10上表現相同,Python 3在這裏也失敗了)。

據處理組(job control)相關:通過preexec_fn=os.setpgrpsubprocess.Popen()使sudo將在它的領導者作爲外殼使得在這種情況下tcpdump_process.terminate()工作的新進程組(作業)。

發生了什麼事?它適用於以前的版本。

的解釋是在the sudo's source code

做的過程中命令的發送過程不轉發信號 組,不轉發它,因爲我們不希望孩子間接殺死了 本身。例如,在某些版本的重啓 中會發生這種情況,該版本調用kill(-1,SIGTERM)來終止所有其他進程。 強調的是礦

preexec_fn=os.setpgrp改變sudo的處理組。 sudo的後代如tcpdump進程繼承了該組。 pythontcpdump不再處於同一個進程組中,因此.terminate()發送的信號被sudo中繼到tcpdump並退出。

Ubuntu 15.04使用Sudo version 1.8.9p5問題的代碼按原樣運行。

Ubuntu 15.10使用Sudo version 1.8.12其中包含the commit

sudo(8) man page in wily (15.10)仍然只談論關於孩子過程本身 - 沒有提及處理組:

作爲一個特殊的情況下,須藤將不再轉發即是由它運行 命令發出的信號。

它應該是代替:

作爲特例,須藤將不再轉發該通過的過程正在運行的命令的處理組中發送的信號。

您可以在Ubuntu's bug tracker和/或the upstream bug tracker上打開文檔問題。