[Zope3-dev] DoS problem in zope.sendmail.maildir

Sascha Ottolski sascha.ottolski at lalisio.com
Wed Jun 6 12:04:50 EDT 2007


Hi,

I discovered a problem with the maildir implementation, that is 
triggered when trying to use the QueuedDelivery with many (read: more 
than current filedescriptor limit of the zope process) mails at once:


Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python2.4/threading.py", line 442, in __bootstrap
    self.run()
  File "/home/so/sandbox/app/zope3/lib/python/zope/sendmail/delivery.py", line 193, in run
  File "/home/so/sandbox/app/Zope-3.3.0/lib/python/zope/sendmail/maildir.py", line 69, in __iter__
OSError: [Errno 24] Too many open files: '/home/so/sandbox/var/zope/lib/python/lalisio/app/site/../../../../var/zope/var/mqueue/new'


Which then seems to make the whole server blocking; trying to open a 
page on the the server results in:


Traceback (most recent call last):
  File "/home/so/sandbox/app/zope3/lib/python/twisted/python/log.py", line 43, in callWithContext

  File "/home/so/sandbox/app/zope3/lib/python/twisted/python/context.py", line 59, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/home/so/sandbox/app/zope3/lib/python/twisted/python/context.py", line 37, in callWithContext
    return func(*args,**kw)
  File "/home/so/sandbox/app/zope3/lib/python/twisted/internet/selectreactor.py", line 139, in _doReadOrWrite

--- <exception caught here> ---
  File "/home/so/sandbox/app/zope3/lib/python/twisted/internet/tcp.py", line 753, in doRead

  File "/usr/lib/python2.4/socket.py", line 161, in accept

socket.error: (24, 'Too many open files')


I need to kill -9 the server after that, SIGTERM seems to be ignored.

The reason for that to happen is clear to me, however, I'm not sure how
a fix could look like.

One source of the problem is


try:
    fd = os.open(filename, os.O_CREAT|os.O_EXCL|os.O_WRONLY, 0600)
except OSError:
    # File exists


OSError is obviously to broad to catch as a test if the unique filename 
could be created. May be use os.path.exists(filename) instead? But I'm 
not sure if this is equivalent in a platform independant way.

The real source of the problem lies in the MaildirMessageWriter: The 
passed-in filedescriptor remains open until commit() is called. No 
problem for sending some mails only, but when sending lots of 
messages in one transaction, the filedescriptor limit kicks in.

A dirty solution might be to change the write() and writeline() to open 
and close the file on every call. But there's probably a saner way. 

BTW, I'm wondering if it is really safe to assume that 
os.rename(self._filename, self._new_filename) in the commit() message 
never fails? Although I believe that it's almost impossible that it 
really could :-)


Thanks, 

Sascha

-- 
Lalisio - connecting knowledge worldwide

Lalisio GmbH
Puschkinstraße 1
99084 Erfurt
fon +49 (0)361 541 43 80
fax +49 (0)361 541 43 79
kontakt at lalisio.com
www.lalisio.com

Sitz der Gesellschaft: Erfurt
Amtsgericht Jena, HRB 113943
Geschäftsführerin: Ute Rother
Ust-Id.: DE813237441


More information about the Zope3-dev mailing list