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

发布于 2021-01-29 16:22:20

我刚刚更新到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()

发生了什么?它适用于以前的版本。

关注者
0
被浏览
171
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    TL; DRsudo不命令的处理组中由过程向前发送信号自2014
    5月28日提交
    的释放sudo 1.8.11-蟒处理(须藤的父)和tcpdump的处理(孙子)是通过默认,因此相同的处理组中的sudo不将SIGTERM发送的信号转发.terminate()tcpdump进程。


    在以root用户和普通用户+ sudo身份运行该代码时,它显示出相同的行为

    以正常用户身份运行会引发OSError: [Errno 1] Operation not permitted异常.terminate()(如预期)。

    以as身份运行会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在评论中指出的那样,您不需要sudo在这里:您已经是root用户了(尽管您不应该是root用户-
    您可以在没有root用户的情况下嗅探网络)。如果你跌落sudo;
    .terminate()作品。

    通常,.terminate()不会递归杀死整个进程树,因此可以预期孙进程可以生存。虽然sudo是一种特殊情况,但从sudo(8)手册页中可以得出

    当命令作为sudo进程的子级运行时,sudo会将 收到的 信号中继 到命令。重点是我的

    即,sudo应该传达SIGTERMtcpdumptcpdump应该停止抓包SIGTERM,tcpdump的距离(8)手册页

    Tcpdump将继续捕获数据包,直到它被SIGINT信号(例如,通过键入您的中断字符,通常为control-
    C生成)或SIGTERM信号(通常由kill(1)命令生成)中断为止;

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

    注意:原则上,可以从同一sudo(8)手册页运行命令而无需创建子进程:

    在特殊情况下,如果策略插件未定义关闭函数且不需要pty,sudo则将直接执行命令,而不是先调用fork(2)

    因此.terminate()可能会tcpdump直接将SIGTERM发送给该进程-尽管不是解释原因:sudo tcpdump在我的测试中,同时在Ubuntu 12.04和15.10上创建了两个进程。

    如果我sudo tcpdump -w example.pcap -i eth0 -n icmp在外壳中运行,则将kill -SIGTERM终止两个进程。它看起来不像Python问题(Python 2.7.3(在Ubuntu 12.04上使用)在Ubuntu
    15.10上的行为相同。Python3也在此处失败)。

    它与流程组(作业控制)有关:传递preexec_fn=os.setpgrpsubprocess.Popen()这样,sudo它将进入一个新的流程组(作业),在该流程组中,它是领导者,如tcpdump_process.terminate()在这种情况下在shell中进行工作。

    发生了什么?它适用于以前的版本。

    解释在sudo的源代码中

    不要转发命令的进程组中某个进程发送的信号
    ,也不要转发该信号,因为我们不希望孩子间接杀死自己。例如,某些版本的重新引导会调用kill(-1,SIGTERM)杀死所有其他进程,这可能会发生。重点是我的

    preexec_fn=os.setpgrp更改sudo的流程组。sudo的子孙(例如tcpdumpprocess)继承了该组。python并且tcpdump不再位于同一个进程组中,因此发送的信号.terminate()被中继sudotcpdump并退出。

    Ubuntu 15.04使用问题Sudo version 1.8.9p5中的代码按原样工作。

    Ubuntu 15.10使用Sudo version 1.8.12包含提交的内容

    wily(15.10)中的sudo(8)手册页仍然只谈到子进程本身,而没有提及进程组:

    作为一种特殊情况,sudo不会中继正在运行的命令发送的信号。

    应该改为:

    作为特殊情况,sudo不会中继正在运行的命令的进程组中的某个进程发送的信号。

    您可以在Ubuntu的错误跟踪器和/或上游错误跟踪器上打开一个文档问题。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看