[Dovecot] File descriptor leak in sieve-extprograms
Kirill A. Shutemov
kirill.shutemov at linux.intel.com
Sat Dec 14 00:14:30 EET 2013
Stephan Bosch wrote:
> On 12/13/2013 2:07 AM, Kirill A. Shutemov wrote:
> > I've tried to use sieve-filter for my inbox (~6000 messages). It failed after
> > some work with this backtrace:
> >
> > sieve-filter(kas): Error: socketpair() failed: Too many open files
> > sieve-filter(kas): Panic: file script-client-local.c: line 155 (script_client_local_disconnect): assertion failed: (pid >= 0)
> > sieve-filter(kas): Error: Raw backtrace: /usr/lib/dovecot/libdovecot.so.0(+0x66a71) [0x7f020e717a71] -> /usr/lib/dovecot/libdovecot.so.0(default_fatal_handler+0x2a) [0x7f020e717ada] -> /usr/lib/dovecot/libdovecot.so.0(i_fatal+0) [0x7f020e6d32ee] -> /usr/lib/dovecot/modules/sieve/lib90_sieve_extprograms_plugin.so(+0x4baf) [0x7f020dae0baf] -> /usr/lib/dovecot/modules/sieve/lib90_sieve_extprograms_plugin.so(+0x58ca) [0x7f020dae18ca] -> /usr/lib/dovecot/modules/sieve/lib90_sieve_extprograms_plugin.so(script_client_fail+0x2f) [0x7f020dae199f] -> /usr/lib/dovecot/modules/sieve/lib90_sieve_extprograms_plugin.so(script_client_run+0xc4) [0x7f020dae1fd4] -> /usr/lib/dovecot/modules/sieve/lib90_sieve_extprograms_plugin.so(+0x6134) [0x7f020dae2134] -> /usr/lib/dovecot/libdovecot-sieve.so.0(sieve_result_execute+0x3ac) [0x7f020ecd1adc] -> /usr/lib/dovecot/libdovecot-sieve.so.0(sieve_execute+0x4a) [0x7f020ece05aa] -> /usr/bin/sieve-filter(main+0x6a9) [0x403b49] -> /usr/lib/libc.so.6(__libc_
> > start_ma
> > in+0xf5) [0x7f020e327bc5] -> /usr/bin/sieve-filter() [0x404111]
> >
> > The reason is file descriptor leak in "script client local".
> > script_client_local_close_output() shutdowns write side of descriptor
> > and sets sclient->fd_out to -1, but never closes the descriptor.
> >
> > I've tried to fix this by the patch below. Tests works fine, but sieve-filter
> > crashed in other way:
>
> Wow, this is a very interesting stupidity on my part, especially the
> `sclient->fd_out != sclient->fd_out`.
>
> This probably fixes it, although I am not entirely sure. I am mainly a
> bit puzzled on how this causes the fd leak; the fd_in and fd_out are for
> the current backends always the same fd.
fd_in is not opened in my case: -1 all the way. I use vnd.dovecot.pipe.
I've hackaround sieve-filter crash with the ugly patch. I don't know how to fix
this properly.
diff --git a/src/plugins/sieve-extprograms/script-client-local.c b/src/plugins/sieve-extprograms/script-client-local.c
index 56d32f707c09..f54ef82132cf 100644
--- a/src/plugins/sieve-extprograms/script-client-local.c
+++ b/src/plugins/sieve-extprograms/script-client-local.c
@@ -139,7 +139,6 @@ static int script_client_local_close_output(struct script_client *sclient)
i_error("shutdown(%s, SHUT_WR) failed: %m", sclient->path);
return -1;
}
- sclient->fd_out = -1;
return 1;
}
diff --git a/src/plugins/sieve-extprograms/script-client.c b/src/plugins/sieve-extprograms/script-client.c
index 06a5d5d54ba9..b94d2029c176 100644
--- a/src/plugins/sieve-extprograms/script-client.c
+++ b/src/plugins/sieve-extprograms/script-client.c
@@ -47,13 +47,10 @@ static void script_client_disconnect
if ( sclient->ioloop != NULL )
io_loop_stop(sclient->ioloop);
- if ( sclient->disconnected )
- return;
-
if ( (ret=sclient->close_output(sclient)) < 0 )
error = TRUE;
-
- if ( (ret=sclient->disconnect(sclient, force)) < 0 )
+
+ if (!sclient->disconnected && (ret=sclient->disconnect(sclient, force)) < 0 )
error = TRUE;
if ( sclient->script_input != NULL )
@@ -68,10 +65,13 @@ static void script_client_disconnect
if (sclient->fd_in != -1 && close(sclient->fd_in) < 0)
i_error("close(%s) failed: %m", sclient->path);
- if (sclient->fd_out != -1 && sclient->fd_out != sclient->fd_out)
- i_error("close(%s/out) failed: %m", sclient->path);
- sclient->fd_in = sclient->fd_out = -1;
-
+ sclient->fd_in = -1;
+ if (force && sclient->fd_out != -1 && sclient->fd_out != sclient->fd_in) {
+ if (close(sclient->fd_out) < 0)
+ i_error("close(%s/out) failed: %m", sclient->path);
+ sclient->fd_out = -1;
+ }
+
sclient->disconnected = TRUE;
if (error && sclient->error == SCRIPT_CLIENT_ERROR_NONE ) {
sclient->error = SCRIPT_CLIENT_ERROR_UNKNOWN;
--
Kirill A. Shutemov
More information about the dovecot
mailing list