Two bugs in 2.3.10-rc2 that cause segfaults
Ken Murchison
murch at andrew.cmu.edu
Tue Oct 16 12:22:28 EDT 2007
Applied to CVS. Thanks for hunting these down.
Rob Mueller wrote:
> Hi Ken
>
> After some testing on our test server, we rolled out 2.3.10-rc2 onto one
> of our production IMAP stores and almost immediately starting noticing
> segfaults for some users.
>
> Bron and I spent quite a bit of time this afternoon debugging, and we're
> pretty sure we found both the causes.
>
> 1. In index_parse_sequence(), your realloc() doesn't multiply by
> sizeof(struct seq_range), so if you have a sequence list with more than
> about 8 items, it will start corrupting memory
>
> 2. The signed -> unsigned changes in the prot stream stuff weren't as
> innocent as they looked and created a subtle and nasty bug. You might
> want to audit the other code where you changed signed -> unsigned as
> well...
>
> Here's an example of the problem if you use IDLE and close the
> connection on it. In that case, what happens is:
>
> In cmd_idle(), we wait for data from the client by calling:
>
> c = getword(imapd_in, &arg);
>
> getword() calls prot_getc(), which looks like this:
>
> #define prot_getc(s) ((s)->cnt-- > 0 ? (int)*(s)->ptr++ : prot_fill(s))
>
> Say there's no data in the prot buffer, then cnt == 0. However when we
> call the above macro, it does cnt--, which makes cnt wrap to 4294967295,
> and then calls prot_fill. prot_fill() calls read(), and if read()
> returns <= 0 (eg other end closed the connection) it does.
>
> if (n <= 0) {
> if (n) s->error = xstrdup(strerror(errno));
> else s->eof = 1;
> return EOF;
> }
>
> So it sets the eof flag and returns EOF.
>
> Back in cmd_idle, we get the EOF, and exit out of cmd_idle and back into
> the main loop, which does.
>
> /* Parse tag */
> c = getword(imapd_in, &tag);
>
> Now getword calls the prot_getc() macro again... but uh, oh. cnt is
> definitely > 0 now (it's 4294967295) and so we reading through
> unitialised memory trying to interpret it as IMAP commands until we hit
> a segfault somewhere.
>
> Our fix is to change prot_getc() to only decrement cnt if it's non-zero.
> Because it's an expression macro, it uses the C comma operator which
> I've found often even experienced C people don't know about
> (http://www.eskimo.com/~scs/cclass/int/sx4db.html).
>
> #define prot_getc(s) ((s)->cnt > 0 ? (--(s)->cnt, (int)*(s)->ptr++) :
> prot_fill(s))
>
> Both patches are here:
>
> http://cyrus.brong.fastmail.fm/patches/cyrus-fix-segfaults-2.3.10.diff
>
> Rob
>
>
--
Kenneth Murchison
Systems Programmer
Project Cyrus Developer/Maintainer
Carnegie Mellon University
More information about the Cyrus-devel
mailing list