Shutting down a cross-platform multithreaded app

Chris Angelico rosuav at gmail.com
Sat Sep 19 00:09:12 CEST 2015


On Sat, Sep 19, 2015 at 7:48 AM, Random832 <random832 at fastmail.com> wrote:
> On Fri, Sep 18, 2015, at 17:40, Chris Angelico wrote:
>> Bear in mind, though, that Windows has no protection against other
>> processes shutting you down.
>
> Neither does Unix. Any process that can send you a signal can send you
> SIGKILL.

Incorrect. If your server is running as root, only root can kill it:

rosuav at sikorsky:~$ kill -9 17080
bash: kill: (17080) - Operation not permitted

If it's running as some other user, then that user can kill it (that
includes the simple case where a non-root user starts a process and
also tries to kill it), as can root, of course. So you have protection
against direct signals (and not just 9/KILL, naturally); and you also
have protection against an AF_UNIX socket, which is what I was talking
about here. The control over sockets is a bit more flexible, as I'm
fairly sure group permissions can't be set for process signals, but
they can for named sockets:

rosuav at sikorsky:~$ python3
Python 3.6.0a0 (default:30bc256f2346, Sep 17 2015, 02:01:45)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
>>> s.bind("/tmp/demo_socket")
>>> import os
>>> os.chmod("/tmp/demo_socket",0o750)
>>> s.listen(1)
>>> s.accept()
# program pauses here
(<socket.socket fd=4, family=AddressFamily.AF_UNIX,
type=SocketKind.SOCK_STREAM, proto=0, laddr=/tmp/demo_socket>, b'')

In another terminal, using Python 2 for variety:

rosuav at sikorsky:~$ sudo sudo -u tfr python
Python 2.7.9 (default, Mar  1 2015, 12:57:24)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> s = socket.socket(socket.AF_UNIX)
>>> s.connect("/tmp/demo_socket")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 13] Permission denied

Err, nope! What if I don't change users?

rosuav at sikorsky:~$ python
Python 2.7.9 (default, Mar  1 2015, 12:57:24)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> s = socket.socket(socket.AF_UNIX)
>>> s.connect("/tmp/demo_socket")
>>>

Looks good. (Feel free to concoct your own scenario that proves that
group permissions work here; I don't have any handy demo cases.)

Unix is designed for this exact sort of thing. Windows isn't, and
privilege escalation attacks are far more common there.

> Of course, what Windows lacks is a generalized way for other processes
> to send "less destructive" signals that do give you a chance to clean
> up. (You can sometimes send a ctrl-break event, but that's it.) And most
> frameworks for "emulating" them (including python's os module) simulate
> sending other signals by calling TerminateProcess with an exit status
> related to the signal.

Yeah, the whole notion of less-destructive (or even completely
non-destructive - look at how a lot of daemons use SIGHUP) signals is
absent on Windows. But that's not really the problem here; the problem
is that there's no way to say "this is a socket for my process ONLY",
which in Unix would be done with a socket.socketpair, but on Windows I
think has to be simulated.

That said, though.... socket.socketpair() IS supported on Windows...
as of Python 3.5. I haven't tested it to see what it's like. If you
can restrict your support to 3.5+, you might be able to do this
instead of what I was describing above.

ChrisA


More information about the Python-list mailing list