Search code examples
pythonlinuxsubprocesssudokill

Killing sudo-started subprocess in python


I am running with a user that can make root-level calls without having to supply a password. My user currently does something like this

pr = subprocess.Popen("sudo sleep 100".split())
sleep(5)
pr.kill()

but that leads to this error because the user isn't root so it can't kill a root process

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 1572, in kill
    self.send_signal(signal.SIGKILL)
  File "/usr/lib/python2.7/subprocess.py", line 1562, in send_signal
    os.kill(self.pid, sig)
OSError: [Errno 1] Operation not permitted

so I try to do something like this

pr = subprocess.Popen("sudo sleep 100".split())
sleep(5)
kill_pr = subprocess.Popen("sudo kill {}".format(pr.pid))

but that doesn't kill the process in question. For example, if

>> subprocess.Popen("sudo sleep 100".split()).pid
5000

but

$ pgrep sleep
5001

so it seems that the pid returned from subprocess.Popen("..").pid is one higher than the actual pid of the process running the command that I want to kill

I'm assuming that the pid returned from the Popen call is the parent process, so I try doing something like

sudo kill -- -$PID, where $PID is the one returned from Popen, but that just gives me

kill: sending signal to -2100 failed: No such process

why doesn't the process exist?

Essentially, I just need a way to run a command with sudo using python's subprocess, then be able to kill it when I need to. I'm assuming I need to run some type of sudo kill command with the pid of the process I'm trying to kill or something like that but I'm unable to determine exactly how to do this.


Solution

  • I think I figured it out, the issue was that if I did this

    import subprocess, os
    pr = subprocess.Popen(["sudo", "sleep", "100"])
    print("Process spawned with PID: %s" % pr.pid)
    pgid = os.getpgid(pr.pid)
    subprocess.check_output("sudo kill {}".format(pgid))
    

    it would kill the process that started the python interpreter

    >>> Terminated
    

    so instead, I set the preexec_fn to os.setpgrp

    import subprocess, os
    pr = subprocess.Popen(["sudo", "sleep", "100"], preexec_fn=os.setpgrp)
    print("Process spawned with PID: %s" % pr.pid)
    pgid = os.getpgid(pr.pid)
    subprocess.check_output("sudo kill {}".format(pgid))
    

    in another shell, if I check

    pgrep sleep
    

    nothing shows up, so it is actually killed.