在Ubuntu 15.10中无法终止使用python创建的sudo进程

前端之家收集整理的这篇文章主要介绍了在Ubuntu 15.10中无法终止使用python创建的sudo进程前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我刚刚更新到Ubuntu 15.10并突然在 Python 2.7中我无法终止我在创建root时创建的进程.
例如,这不会终止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; DR:sudo不转发由sudo 1.8.11中发布的命令进程组 since 28 May 2014 commit中的进程发送的信号 – python进程(sudo的父进程)和tcpdump进程(grandchild)默认位于同一进程组中因此,sudo不会将.terminate()发送的SIGTERM信号转发到tcpdump进程.

It shows the same behavIoUr when running that code while being the root user and while being a regular user + sudo

以普通用户身份运行会引发OSError:[Errno 1] .terminate()上的操作不允许异常(如预期的那样).

以root身份运行会重现问题:sudo和tcpdump进程不会在.terminate()上被杀死,代码会在Ubuntu 15.10上停留在.communicate()上.

相同的代码会杀死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:你已经是root(虽然你不应该 – 你可以sniff the network without root).如果你放弃sudo; .terminate()有效.

通常,.terminate()不会递归地终止整个进程树,因此预期孙进程会幸存.虽然sudo是一个特例,from sudo(8) man page

When the command is run as a child of the sudo process,sudo will
relay signals@H_403_37@ it receives to the command.emphasis is mine

即,sudo应该将SIGTERM中继到tcpdump和tcpdump should stop capturing packets on SIGTERM,from tcpdump(8) man page

Tcpdump will,…,continue capturing packets until it is
interrupted by a SIGINT signal (generated,for example,by typing your
interrupt character,typically control-C) or a SIGTERM signal
(typically generated with the kill(1) command);

即,预期的行为是:tcpdump_process.terminate()将SIGTERM发送到sudo,它将信号中继到tcpdump,tcpdump应该停止捕获并且两个进程都退出并且.communicate()将tcpdump的stderr输出返回给python脚本.

注意:原则上,可以在不创建子进程的情况下运行命令,from the same sudo(8) man page

As a special case,if the policy plugin does not define a close
function and no pty is required,sudo will execute the command
directly instead of calling fork(2) first

因此.terminate()可以直接将SIGTERM发送到tcpdump进程 – 虽然不是解释:sudo 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.setpgrp传递给subprocess.Popen(),以便sudo将在一个新进程组(作业)中,它是shell中的领导者,使得tcpdump_process.terminate()在这种情况下工作.

What happened? It works on prevIoUs versions.

解释是在the sudo’s source code

Do not forward signals sent by a process in the command’s process
group@H_403_37@
,do not forward it as we don’t want the child to indirectly kill
itself. For example,this can happen with some versions of reboot
that call kill(-1,SIGTERM) to kill all other processes.emphasis is mine

preexec_fn = os.setpgrp更改了sudo的进程组. sudo的后代如tcpdump进程继承了该组. python和tcpdump不再位于同一进程组中,因此.terminate()发送的信号由sudo中继到tcpdump并退出.

Ubuntu 15.04使用Sudo版本1.8.9p5,问题中的代码按原样运行.

Ubuntu 15.10使用包含the commit的Sudo版本1.8.12.

sudo(8) man page in wily (15.10)仍然只讨论子进程本身 – 没有提到进程组:

As a special case,sudo will not relay signals that were sent by the
command it is running.

它应该是:

As a special case,sudo will not relay signals that were sent by a process in the process group of the command it is running.

您可以在Ubuntu’s bug tracker和/或the upstream bug tracker上打开文档问题.

猜你在找的Ubuntu相关文章