Re: [Python-Dev] Proposal for a new function "open_noinherit" to avoid problems with subprocesses and security risks

2007-06-30 Thread Henning von Bargen
> Martin v. Löwis wrote:
> Exactly. My proposal is still to provide an API to toggle the
> flag after the handle was created.

OK, here is an API that I tested on Windows and for sockets only.
Perhaps someone can test it on Non-Windows (Linux, for example?)

I think the best place for it would be as a new method "set_noinherit"
for file and socket objects or as a new function in the os module
(thus the implementation should probably be rewritten at the C level).

Note that for file objects, the code would need an additional call to
win32file._get_osfhandle, because .fileno() returns the Windows handle
only for sockets, but not for files.

The code below uses thes Mark Hammond's win32all library.

import os

if os.name == "nt":

import win32api, win32con
def set_noinherit(socket, noinherit=True):
"""
Mark a socket as non-inheritable to child processes.

This should be called right after socket creation if you want
to prevent the socket from being inherited to child processes.

Notes:

Unintentional socket or file inheritance is a security risk and
can cause errors like "permission denied", "adress already in use" 
etc.
in programs that start subprocesses, particularly in multi-threaded
programs. These errors tend to occur seemingly randomly and are hard
to reproduce (race condition!) and even harder to debug.

Thus it is good practice to call this function as soon as possible
after opening a file or socket that you doesn't need to be inherited
to subprocesses.
Note that in a multi-threaded environment, it is still possible that
another thread starts a subprocess after you created a file/socket,
but before you call set_noinherit.

Note that for sockets, the new socket returned from accept() will be
inheritable even if the listener socket was not; so you should call
set_noinherit for the new socket as well.

Availability: Posix, Windows
"""

flags = 0
if noinherit:
flags = flags | win32con.HANDLE_FLAG_INHERIT
win32api.SetHandleInformation(socket.fileno(), 
win32con.HANDLE_FLAG_INHERIT, flags)

else:

import fcntl
def set_noinherit(socket, noinherit=True):
"""
... documentation copied from the nt case ...
"""

fd = socket.fileno()
flags = fcntl.fcntl(fd, fcntl.F_GETFD) & ~fncl.FD_CLOEXEC
if noinherit:
flags = flags | fcntl.FD_CLOEXEC)
fcntl.fcntl(fd, fcntl.F_SETFD, flags)


>
>> Martin, you mentioned that for sockets, inheritance is not a problem
>> unless accept(), recv() or select() is called in the child process
>> (as far as I understood it).
>
> I did not say "no problems". I said "there is no ambiguity whereto
> direct the data if the child processes don't perform accept/recv".
>
>> * http://mail.python.org/pipermail/python-list/2003-November/236043.html
>>"socket's strange behavior with subprocesses"
>>Funny: Even notepad.exe is used there as an example child process...
>
> Sure: the system will not shutdown the connection as long as the handle
> is still open in the subprocess (as the subprocess *might* send more
> data - which it won't).
>
> I think the problem could be avoided by the parent process explicitly
> performing shutdown(2), but I'm uncertain as I have never actively used
> shutdown().
>
>> * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4202949
>>   Java has switched to non-inheritable sockets as well.
>
> Not surprisingly - they don't support fork(). If they would,
> they could not have made that change. The bug report is the
> same issue: clients will be able to connect as long as the
> listen backlog fills. Then they will be turned down, as notepad
> will never perform accept.

I think I more or less understand what happens.

The fact remains, that a subprocess takes influence on the behaviour
of server and client programs in an unwanted (and for many people:
unexpected) manner.

Regarding the influence of socket inheritance for server apps,
I performed some tests on Windows. If a subprocess is started
after the parent called accept(), then a client can still
connect() and send() to the socket - even if the parent process
has closed it and exited meanwhile.
This works until the queue is full (whose size was specified in
listen()). THEN the client will get (10061, 'Connection refused');
as you already explained.

And client and server will have the socket in CLOSE_WAIT resp.
FIN_WAIT2 status. However I doubt that this is actually a problem
as long as the server continues accept()ing.
But it means the client and server OS have to manage the socket
until the subprocess exits - even though neither client nor server
need the socket anymore.

One might argue that it is not actually a big problem, since the
subprocess will exit sooner or later.
This is more or less true for Linux, etc.

However, so

Re: [Python-Dev] Proposal for a new function "open_noinherit" to avoid problems with subprocesses and security risks

2007-06-30 Thread Martin v. Löwis
> I think the best place for it would be as a new method "set_noinherit"
> for file and socket objects or as a new function in the os module
> (thus the implementation should probably be rewritten at the C level).

Indeed. Can you come up with a C implementation of it?
I think it should be a function in the posix/nt module, expecting
OS handles; the function in the os module could additionally support
sockets and file objects also in a polymorphic way.

> This works until the queue is full (whose size was specified in
> listen()). THEN the client will get (10061, 'Connection refused');
> as you already explained.

That's for accept, yes. For send, you can continue sending until
the TCP window closes (plus some unspecified amount of local
buffering the OS might do).

> However, sometimes a subprocess might crash or hang.
> Now what happens if the server program is closed and then started
> again? On Linux, no problem (more or less). When the server program
> is closed, the subprocess will be killed by the OS (I think), and
> the socket is released (perhaps with a few minutes delay).

That's not true. The child process can run indefinitely even though
the parent process has terminated. You may be thinking of SIGHUP,
which is sent to all processes when the user logs out of
the terminal.

Regards,
Martin

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Summary of Tracker Issues

2007-06-30 Thread Tracker

ACTIVITY SUMMARY (06/24/07 - 07/01/07)
Tracker at http://bugs.python.org/

To view or respond to any of the issues listed below, click on the issue 
number.  Do NOT respond to this message.


 1645 open ( +0) /  8584 closed ( +0) / 10229 total ( +0)

Average duration of open issues: 843 days.
Median duration of open issues: 791 days.

Open Issues Breakdown
   open  1645 ( +0)
pending 0 ( +0)

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com