[issue12107] TCP listening sockets created without FD_CLOEXEC flag

2011-05-19 Thread Christophe Devriese

New submission from Christophe Devriese :

The specific issue this is creating is that a malicious user could use this 
socket in a subprocess which is started from a library (ie. I'm using a .so, 
which calls fork/exec).

A second failure mode is starting a daemon from withing, say, a django 
application. Djano opens a TCP listening socket, then starts up a daemon to 
provide some sort of service in the background. The daemon keeps running and 
inherits the socket. Now you restart the django app.

It refuses to start ! Why ? Because the socket was inherited, the listening 
socket isn't actually closed, and this results in the socket being stuck in 
CLOSE_WAIT as long as the daemon is running.

It seems to me that it is almost never the case that you'd want a TCP listening 
socket to be preserved across exec, and not setting this flag should thus be 
considered a bug for 2 reasons :

1) it results in accidental disclosure of information that shouldn't be exposed 
in certain cases.
2) it can result in denial of service

Solution : 

update SocketServer.py :
  in the class TCPServer
  add the following 2 lines in __init__ after self.socket = socket( ...:
flags = fcntl.fcntl(self.socket, fcntl.F_GETFD)
fcntl.fcntl(self.socket, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)

--
messages: 136273
nosy: Christophe.Devriese
priority: normal
severity: normal
status: open
title: TCP listening sockets created without FD_CLOEXEC flag
type: security

___
Python tracker 
<http://bugs.python.org/issue12107>
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue12107] TCP listening sockets created without FD_CLOEXEC flag

2011-05-20 Thread Christophe Devriese

Christophe Devriese  added the comment:

I realize this bugreport cannot fix 35 years of a bad design decision in
linux. That's not the intention (that's a gordian knot I *will* be keeping a
safe distance from). The intention is to create a saner default situation
for most python programs.

Christophe

2011/5/20 Charles-François Natali 

>
> Charles-François Natali  added the comment:
>
> Hello Christophe,
>
> First and foremost, I think that the FD_CLOEXEC approach is terminally
> broken, as it should have been the default in Unix. Now, we're stuck with
> this bad design.
> But we can't simply change the default to FD_CLOEXEC, for two reasons:
> - we can't silently change the Unix semantics
> - this is going to break some applications: for example, FD inherited
> across exec is used by super servers such as inetd, and there are others
> very legitimate uses
>
> >  in the class TCPServer
> >  add the following 2 lines in __init__ after self.socket = socket( ...:
> >flags = fcntl.fcntl(self.socket, fcntl.F_GETFD)
> >fcntl.fcntl(self.socket, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)
>
> There are at least two problems with this approach:
> 1) there's a race between the socket creation and the call to fcntl
> 2) accept doesn't necessarily inherit the FD_CLOEXEC flag
>
> 1) can be fixed on systems that support it through SOCK_CLOEXEC
> 2) can be fixed on systems that support it through accept4(), but it seems
> to break badly on some systems, see issue #10115
>
> But I think this is a perfectly legitimate request, so one approach to
> tackle this problem could be:
> - since accept4() seems to fail so badly in some configurations, the only
> portable and reliable choice left is probably to call accept() then
> fcntl(FD_CLOEXEC) (there's a race, but it's better than nothing). We might
> reconsider this syscall in a couple years when we're sure it's implemented
> correctly
> - in the socketserver module, add a new set_socket_cloexec attribute to
> BaseServer, which would do the right thing (i.e. create the socket with
> SOCK_CLOEXEC if available, otherwise call fcntl(FD_CLOEXEC)), and in
> TCPServer, call fcntl(FD_CLOEXEC) after accept.
>
> That way, this would at least fix the problem for people using the
> socketserver module. People using sockets directly of course have the option
> of using SOCK_CLOEXEC and fcntl(FD_CLOEXEC) explicitely in their code.
>
> Gregory, any thoughts on this?
>
> --
>
> ___
> Python tracker 
> <http://bugs.python.org/issue12107>
> ___
>

--
Added file: http://bugs.python.org/file22038/unnamed

___
Python tracker 
<http://bugs.python.org/issue12107>
___I realize this bugreport cannot fix 35 years of a bad design decision in linux. 
That's not the intention (that's a gordian knot I *will* be keeping a 
safe distance from). The intention is to create a saner default situation for 
most python programs.

Christophe2011/5/20 
Charles-François Natali <mailto:[email protected]";>[email protected]>


Charles-François Natali <mailto:[email protected]";>[email protected]> added the comment:

Hello Christophe,

First and foremost, I think that the FD_CLOEXEC approach is terminally broken, 
as it should have been the default in Unix. Now, we're stuck with this bad 
design.
But we can't simply change the default to FD_CLOEXEC, for two reasons:
- we can't silently change the Unix semantics
- this is going to break some applications: for example, FD inherited across 
exec is used by super servers such as inetd, and there are others very 
legitimate uses

>  in the class TCPServer
>  add the following 2 lines in __init__ after self.socket = socket( 
...:
>    flags = fcntl.fcntl(self.socket, fcntl.F_GETFD)
>    fcntl.fcntl(self.socket, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)

There are at least two problems with this approach:
1) there's a race between the socket creation and the call to fcntl
2) accept doesn't necessarily inherit the FD_CLOEXEC flag

1) can be fixed on systems that support it through SOCK_CLOEXEC
2) can be fixed on systems that support it through accept4(), but it seems to 
break badly on some systems, see issue #10115

But I think this is a perfectly legitimate request, so one approach to tackle 
this problem could be:
- since accept4() seems to fail so badly in some configurations, the only 
portable and reliable choice left is probably to call accept() then 
fcntl(FD_CLOEXEC) (there's a race, but it's better than nothing). We 
might reconsider this syscall in a couple years w

[issue12107] TCP listening sockets created without FD_CLOEXEC flag

2011-05-21 Thread Christophe Devriese

Christophe Devriese  added the comment:

It would already be a nice piece of progress if you could request the
SO_CLOEXEC (with fallback to FD_CLOEXEC), say, in the constructor, or even
with a module variable. I hope at least this change can make it in, so that
we have a decent in-python solution that can be used from within, say,
django.

Christophe

On Sat, May 21, 2011 at 1:24 AM, Antoine Pitrou wrote:

>
> Changes by Antoine Pitrou :
>
>
> Removed file: http://bugs.python.org/file22038/unnamed
>
> ___
> Python tracker 
> <http://bugs.python.org/issue12107>
> ___
>

--
Added file: http://bugs.python.org/file22050/unnamed

___
Python tracker 
<http://bugs.python.org/issue12107>
___It would already be a nice piece of progress if you could request the 
SO_CLOEXEC (with fallback to FD_CLOEXEC), say, in the constructor, or even with 
a module variable. I hope at least this change can make it in, so that we have 
a decent in-python solution that can be used from within, say, django.

ChristopheOn Sat, May 
21, 2011 at 1:24 AM, Antoine Pitrou <mailto:[email protected]";>[email protected]> 
wrote:


Changes by Antoine Pitrou <mailto:[email protected]";>[email protected]>:


Removed file: http://bugs.python.org/file22038/unnamed"; 
target="_blank">http://bugs.python.org/file22038/unnamed

___
Python tracker <mailto:[email protected]";>[email protected]>
<http://bugs.python.org/issue12107"; 
target="_blank">http://bugs.python.org/issue12107>
___

___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com