2015-12-17 12 views
5

ich gerade aktualisiert Ubuntu 15.10 und plötzlich in Python 2.7 Ich bin nicht in der Lage beenden einen Prozess, den ich erstellt beenden, wenn root zu sein. Zum Beispiel diese nicht beendet tcpdump:kann keinen sudo Prozess mit Python erstellt, in 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() 

Was ist passiert? Es funktioniert auf früheren Versionen.

+3

Wenn Sie dies ausführen, während Sie root sind, warum müssen Sie Sudo aufrufen? Was versuchst du zu machen? –

+0

Ok, guter Punkt. Ohne 'Sudo' scheint es zu funktionieren. Aber warum hat es bei allen früheren Versionen funktioniert? –

+0

Ich weiß nicht, warum, das wahrscheinlichste Szenario ist, dass wenn Sie auf 15.10 aktualisiert einige Konfiguration über Ihre sudoer oder die damit verbundenen Privilegien oder ihre Gruppe geändert. Vielleicht hast du deinen Python ohne Root-Privilegien ausgeführt und kann keine erhöhte Shell töten (sudo) –

Antwort

8

TL; DR: sudo keine Signale, die durch einen Prozess in der Prozessgruppe des Befehls gesendet weiterleiten since 28 May 2014 commit in sudo 1.8.11 freigegeben - der Python-Prozess (Sudo der Eltern) und den tcpdump Prozess (Enkel) ist in der gleichen Prozeßgruppe standardmäßig und daher sudo nicht weiterleiten SIGTERM Signal von .terminate() an die tcpdump Prozess gesendet.


Es zeigt das gleiche Verhalten, wenn dieser Code ausgeführt wird, während der Benutzer root und mehr, während ein normaler Benutzer + sudo sein

als normaler Benutzer laufen wirft OSError: [Errno 1] Operation not permitted Ausnahme auf .terminate() (wie erwartet).

als root Lauf reproduziert das Problem: sudo und tcpdump Prozesse nicht getötet auf .terminate() und der Code auf .communicate() auf Ubuntu 15.10 steckt.

Der gleiche Code tötet beide Prozesse auf Ubuntu 12.04.

tcpdump_process Name ist irreführend, weil die Variable auf den sudo Prozess bezieht (das Kind Prozess), nicht tcpdump (Enkel):

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

Als @Mr.E pointed out in the comments, brauchen Sie nicht sudo hier: Sie sind root schon (obwohl du nicht sein solltest - du kannst sniff the network without root). Wenn Sie sudo löschen; .terminate() funktioniert.

Im Allgemeinen führt .terminate() nicht den gesamten Prozessbaum rekursiv ab und daher wird erwartet, dass ein Enkelprozess überlebt. Obwohl sudo ein Sonderfall ist, from sudo(8) man page:

Wenn der Befehl als Kind des sudo Prozess ausgeführt wird, sudo wird Relais Signale es auf den Befehl empfängt. Schwerpunkt ist mein

heißt sudoSIGTERM-tcpdump Relais sollte und tcpdump should stop capturing packets on SIGTERM, from tcpdump(8) man page:

Tcpdump wird, ..., weiterhin die Erfassung von Paketen, bis sie unterbrochen wird durch ein Signal SIGINT (generiert z. B. durch Eingabe Ihres Interrupt-Zeichens, typischerweise control-C) oder eines SIGTERM-Signals (normalerweise generiert mit dem Befehl kill (1));

heißt das erwartete Verhalten ist: tcpdump_process.terminate() sendet SIGTERM an sudo, die das Signal zu tcpdump Relais, die die Erfassung stoppen sollten und beide Prozesse verlassen und .communicate() kehrt tcpdump ‚s stderr Ausgabe an das Python-Skript.

Hinweis: Grundsätzlich kann der Befehl, ohne ein Kind-Prozess ausgeführt werden, from the same sudo(8) man page:

Als Sonderfall, wenn die Politik Plugin nicht eine enge Funktion definieren ist und keine pty erforderlich ist, sudo den Befehl direkt anstelle Gabel des Aufrufs (2) erste

und daher .terminate() kann SIGTERM an den tcpdump Prozess direkt senden auszuführen - wenn es nicht die Erklärung ist: sudo tcpdump erstellt zwei Prozesse auf beiden Ubuntu 12.04 und 15.10 in meinen Tests. Wenn ich sudo tcpdump -w example.pcap -i eth0 -n icmp in der Shell ausführen, beendet kill -SIGTERM beide Prozesse. Es sieht nicht wie Python aus (Python 2.7.3 (unter Ubuntu 12.04) verhält sich unter Ubuntu 15.10 genauso. Python 3 schlägt hier auch fehl).

Es wird in Verbindung stehende Gruppen zu verarbeiten (job control): passing preexec_fn=os.setpgrp-subprocess.Popen() so dass sudo in einer neuen Prozessgruppe sein wird (Job), wo es der Führer ist wie in der Schale tcpdump_process.terminate() Arbeit in diesem Fall macht.

Was ist passiert? Es funktioniert auf früheren Versionen.

Die Erklärung ist in the sudo's source code:

nicht vorwärts Signale Sie durch einen Prozess in dem Befehl des Prozesses gesendet Gruppe, leite es nicht, wie wir das Kind nicht wollen indirekt töten selbst. Dies kann zum Beispiel bei einigen Versionen von reboot auftreten, die kill (-1, SIGTERM) aufrufen, um alle anderen Prozesse zu beenden. Schwerpunkt ist mein

preexec_fn=os.setpgrp ändert sudo ‚s Prozessgruppe. sudo 's Nachkommen wie tcpdump Prozess erben die Gruppe. python und tcpdump sind nicht mehr in derselben Prozessgruppe und daher wird das von .terminate() gesendete Signal von sudo an tcpdump weitergeleitet und es wird beendet.

Ubuntu 15.04 verwendet Sudo version 1.8.9p5 wo der Code aus der Frage funktioniert, wie es ist.

Ubuntu 15.10 verwendet Sudo version 1.8.12, das the commit enthält.

sudo(8) man page in wily (15.10) nur noch über das Kind Prozess spricht selbst - keinen Hinweis auf der Prozessgruppe:

Als Sonderfall, sudo wird keine Signale weiterleiten, die von dem Befehl gesendet wurde er ausgeführt wird.

Es sollte stattdessen sein:

Als Sonderfall, sudo werden keine Signale weiterleiten, die von einem Prozess in der Prozessgruppe des Befehls gesendet wurden er ausgeführt wird.

Sie könnten eine Dokumentation Ausgabe öffnen auf Ubuntu's bug tracker und/oder auf the upstream bug tracker.

Verwandte Themen