微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在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 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
,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上打开文档问题.

原文地址:https://www.jb51.cc/ubuntu/347217.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐