We recently found a piece of mail which causes show or scan to dump
core under Linux. The cause appears to be a fencepost in the part of
m_getfld() which reads the header name. ("m_getfld.c, my old nemesis,
we meet again.") The code sets up bp to be a pointer into the file's
read buffer and j to be the number of bytes available. If you
consider the trivial case where j is 0, you will see that whenever the
read buffer is exhausted, the byte after the end of the buffer is read
and bp is advanced to one byte past the end. On Linux systems, at
least in our environment, the byte just after the end of the read
buffer was not mapped, so the code got a segmentation violation trying
to access it. I believe this bug is rarely triggered because it's
unusual for headers to be longer than a single read block and for the
block division to be inside the name of a header (as opposed to the
value).
This patch appears to correct the problem. Although it changes the
value of bp at the end of the loop in the buffer exhaustion case, that
seems to be the right thing; I stepped through the patched code and
verified that m_getfld() properly returns the name of a header even if
it is split across two read blocks.
I decided against including the offended piece of mail because it
contained a whole bunch of people's email addresses which might show
up in search engines. The interesting feature of the mail was that
4096 bytes into the headers, we were in the middle of a header name.
Index: m_getfld.c
===================================================================
RCS file: /afs/dev.mit.edu/source/repository/third/nmh/sbr/m_getfld.c,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 m_getfld.c
*** m_getfld.c 1999/02/07 18:14:09 1.1.1.1
--- m_getfld.c 2000/08/08 19:19:18
***************
*** 259,265 ****
bp = sp = (unsigned char *) iob->_ptr - 1;
j = (cnt = iob->_cnt+1) < i ? cnt : i;
#endif
! while ((c = *bp++) != ':' && c != '\n' && --j >= 0)
*cp++ = c;
j = bp - sp;
--- 259,265 ----
bp = sp = (unsigned char *) iob->_ptr - 1;
j = (cnt = iob->_cnt+1) < i ? cnt : i;
#endif
! while (--j >= 0 && (c = *bp++) != ':' && c != '\n')
*cp++ = c;
j = bp - sp;