Discussion:
Occasional crash in imap-2007f w/fix
Erik Lotspeich
2013-07-15 18:41:24 UTC
Permalink
Hi,

I have been experiencing a crash in imap-2007f for some time now. I have
built it with 'make lnp' on SLES 11p2 (x86_64).

I finally decided to investigate. The crash looked like this:

Jul 15 10:56:15 mail kernel: [332281.417489] imapd[12134]: segfault at
769 ip 000000000040c3ad sp 00007fffde2e6610 error 4 in imapd[400000+f6000]

I added a some debugging; here's output that helps to illustrate what is
happening (I output ~0 if the pointer value is 0; sorry if that's
confusing):

Jul 15 10:56:12 mail imapd[12134]: mail_close_full before close stream:
0x785960 stream->dtb->close: 0x45a300
Jul 15 10:56:12 mail imapd[12134]: mail_close_full after close stream:
0x785960 stream->dtb->close: 0xffffffffffffffff
Jul 15 10:56:12 mail imapd[12134]: mail_close_full before close stream:
0x744990 stream->dtb->close: 0x45a300
Jul 15 10:56:12 mail imapd[12134]: mail_close_full after close stream:
0x744990 stream->dtb->close: 0xffffffffffffffff
Jul 15 10:56:13 mail imapd[12134]: mail_close_full before close stream:
0x777ad0 stream->dtb->close: 0x45a300
Jul 15 10:56:13 mail imapd[12134]: mail_close_full after close stream:
0x777ad0 stream->dtb->close: 0xffffffffffffffff

Jul 15 10:56:15 mail imapd[12134]: mm_nocritical s: 0x744990 s->dtb:
0x6fa8e0
Jul 15 10:56:15 mail imapd[12134]: mm_nocritical before mail_close
Jul 15 10:56:15 mail imapd[12134]: mail_close_full before close stream:
0x744990 stream->dtb->close: 0x45a300
Jul 15 10:56:15 mail imapd[12134]: mail_close_full after close stream:
0x744990 stream->dtb->close: 0xffffffffffffffff
Jul 15 10:56:15 mail imapd[12134]: mm_nocritical after mail_close
Jul 15 10:56:15 mail imapd[12134]: main stream: 0x777ad0 stream->dtb: 0x760

There is a loop that closes all of the streams. Then the code tries to
free the main stream (the one imapd.c's stream variable is set to)
again. The stream that it closes a second time has pointer value
0x744990. The crash happens because, even though the first closes sets
the value of stream->dtb to 'NIL', that memory is reused. By the time
the longjmp jumps back to the code where setjmp was last called, that
memory was written to (hence the value of 0x760 there). A NULL check
isn't good enough, clearly.

Since it seems the loop that closes out the streams does ultimately
close the main stream, I devised a simple patch:

----begin patch
diff -u -r imap-2007f/src/imapd/imapd.c
imap-2007f-lotspeich//src/imapd/imapd.c
--- imap-2007f/src/imapd/imapd.c 2011-07-23 00:20:00.000000000 +0000
+++ imap-2007f-lotspeich//src/imapd/imapd.c 2013-07-15
14:46:03.000000000 +0000
@@ -383,9 +383,11 @@
if (setjmp (jmpenv)) { /* die if a signal handler say so */
/* in case we get borked now */
if (setjmp (jmpenv)) _exit (1);
+#if 0
/* need to close stream gracefully? */
if (stream && !stream->lock && (stream->dtb->flags & DR_XPOINT))
stream = mail_close (stream);
+#endif
ret = 1; /* set exit status */
}
else while (state != LOGOUT) {/* command processing loop */

----end of patch

Obviously, if my approach here is correct, a better patch would be to
simply remove those three lines of code.

The author of that code didn't seem entirely sure of the need to do a
close as he states "need to close stream gracefully?". Someone with more
experience with the code than me might be able to determine if there is
a case where the stream closing loop doesn't catch everything.

In any case, my patch has stopped the crashing for me.

Regards

Erik
Erik Lotspeich
2013-07-15 18:48:02 UTC
Permalink
Post by Erik Lotspeich
I added a some debugging; here's output that helps to illustrate what is
happening (I output ~0 if the pointer value is 0; sorry if that's
I output ~0 for stream->dtb->close if stream->dtb is NULL. Sorry for the
confusion/noise.

Regards

Erik

Loading...