0

I'm trying to launch a process with root privileges and kill it later on.

But for some reason, I can't get it to work.

Here is a small script to reproduce my problem (disclaimer: code is a bit dirty its only for bug reproduction):

import os
import time
import subprocess

command = ["sudo", "sleep", "25"]

process = subprocess.Popen(command,
                           bufsize=1,
                           stdin=open(os.devnull),
                           stderr=subprocess.PIPE,
                           stdout=subprocess.PIPE)

def kill():
    pid = process.pid
    cmd = "sudo kill %s" % pid
    print(cmd)
    print(os.system(cmd))

time.sleep(2)
kill()

stdout, stderr = process.communicate()
print("stdout: " + stdout)
print("stderr: " + stderr)
ret = process.wait()
print("ret: " + str(ret))

This code doesn't seem to be able to kill my subprocess, but when I launch os.system("sudo kill <pid>") in another python instance, it does work.

Nazim Kerimbekov
  • 4,712
  • 8
  • 34
  • 58
  • why not start the program using: `sudo python script` , it will run with the wanted privileges. Just use `os.kill( pid, sig)` in the script – hootnot Jul 09 '18 at 08:35
  • Yes, that would be a solution but if possible we don't want our script to run as root – chetyredva Jul 09 '18 at 09:02
  • then use sudo to run it as the non-root user you want: `sudo -u ...` – hootnot Jul 09 '18 at 09:12
  • The goal here is still to run the command as root (and not the script) – chetyredva Jul 09 '18 at 09:29
  • maybe add `print os.getuid() / is.geteuid()` to figure out if you have possible issues with the user – hootnot Jul 09 '18 at 09:35
  • Where and why I should do that? have you been able to reproduce the problem with my script? – chetyredva Jul 09 '18 at 09:42
  • place these print statements before the `time.sleep(2)`, subprocess is started already there. It sleeps for 25 seconds , parallel issue a `ps ` in a shell to figure out that the subprocess runs as the user/group you think it should – hootnot Jul 09 '18 at 09:49

2 Answers2

1

You may try this one too. Here what I tried to do is setting a session id to the group of processes that may get created during the subprocess call and when you want kill, a signal is sent to the process group leader, it's transmitted to all of the child processes of this group.

import signal
process = subprocess.Popen(command,
                       stderr=subprocess.PIPE,
                       stdout=subprocess.PIPE,
                       preexec_fn=os.setsid)   # add session id to group

print(process.pid)

def kill():
    pid = process.pid
    cmd = "sudo kill %s" % pid
    print(cmd)
    os.killpg(os.getpgid(process.pid), signal.SIGTERM)  # send signal to the group

time.sleep(2)
kill()
Mufeed
  • 3,018
  • 4
  • 20
  • 29
  • Good idea and in a more pythonic way, I have just tried it and it actually unlocks python, but sadly it creates zombies... – chetyredva Jul 09 '18 at 11:19
0

Problem here in your code is, that it does not close thread in kill function

Function kill does kill your subprocess command. But it does not end thread.

Note: Use -9 if you want to force fully kill the process.

Solution to your problem is. use process.wait() (this will close your thread) in your kill function.

def kill():
    pid = process.pid
    cmd = "sudo kill -9 %s" % pid . # -9 to kill force fully
    print(cmd)
    print(os.system(cmd))
    print(process.wait()) # this will print -9 if killed force fully, else -15.
surya singh
  • 450
  • 2
  • 12
  • Thank you, it works, but not entirely because now I can't get the process stdout and stderr, (which is very important in my case), do you know how to do that? – chetyredva Jul 09 '18 at 10:57
  • so before you kill your program get stdout and stderr. – surya singh Jul 09 '18 at 10:59
  • Yes but I wont kill it every time, sometimes the process will end by itself, and if I use subprocess.communicate it will hang when I kill it – chetyredva Jul 09 '18 at 11:01
  • if you are using python 3.3+ user subprocess.check_output, you can provide time_out. else checkout http://www.bo-yang.net/2016/12/01/python-run-command-with-timeout – surya singh Jul 09 '18 at 11:10
  • ok now it works: I m now doing process.wait() and if ret != signal then I do process.communicate() – chetyredva Jul 09 '18 at 11:14
  • yes sadly I m stuck on python2 for that project ;'( – chetyredva Jul 09 '18 at 11:15
  • I don't have enough reputation to upvote your answer btw, but many thanks! :) – chetyredva Jul 09 '18 at 11:15
  • Thats fine. And if you don't want to use `kill` function you create. you can use process.terminate() or process.kill(). – surya singh Jul 09 '18 at 11:19
  • the problem with process.kill() is I get a OSError because I don't have the permission to kill a root process – chetyredva Jul 09 '18 at 11:20
  • yup, sorry. forgot about the sudo. – surya singh Jul 09 '18 at 11:21
  • Bad news, actually I had zombies with your solution, I had to mix with the answer below 1: add param preexec_fn=os.setsid to subprocess.popen 2: use pkill -g instead of kill 3: add the program I intend to run, as no passwd sudo (because there is no more tty) – chetyredva Jul 09 '18 at 11:41