On Fri, May 14, 2010 at 10:26:40AM -0400, Jeffrey Stedfast wrote: > On 05/14/2010 05:19 AM, Damian Pietras wrote: > > I've hit a bug in gmime 2.4.15 while composing a message. Gmime is > > segfaulting if I use GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE. Valgrind > > says it's a buffer overflow while encoding to quoted printable. > > > > It's right, in a simple test case that encodes mostly binary data > > using GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE a buffer overrun occurs in > > g_mime_encoding_quoted_encode_step. > > > > I think the reason is that GMIME_QP_ENCODE_LEN looks like: > > > > #define GMIME_QP_ENCODE_LEN(x) ((size_t) ((((x) + 1) * 3) + 1)) > > > > is wrong because g_mime_encoding_quoted_encode_step inserts an EOL > > char after every 74th output character which the macro doesn't take > > into account. The bug doesn't occur if using base64 encoding. > > > > > > try this macro: > > #define GMIME_QP_ENCODE_LEN(x) ((size_t) ((((x) / 24) * 73) + 74)) I couldn't test it on weekend but I've tested it now and it still crashes in my case. I took another look at the code and this computation doesn't account the worst case: gmime-encodings.c:972 inserts "=\n" every 72 chars. I calculated and tested that this works for me: ((size_t) ((((x) / 12) * 37) + 39)) This adds 2 chars ("=\n") for every input char assuming that every input char may need encoding. This is my test program and the test file is attached: static void encoding_test (int fd) { const size_t buf_size = 4 * 1024; char *buf; ssize_t res; GMimeEncoding state; buf = malloc (buf_size); g_mime_encoding_init_encode (&state, GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE); //g_mime_encoding_init_encode (&state, GMIME_CONTENT_ENCODING_BASE64); while ((res = read(fd, buf, buf_size)) > 0) { char *outbuf = malloc (g_mime_encoding_outlen(&state, res)); size_t outLen; outLen = g_mime_encoding_step (&state, buf, res, outbuf); res = write (1, outbuf, outLen); if (res < 0) { perror ("write"); return; } free (outbuf); } if (res < 0) { perror ("read"); } char *outbuf = malloc (g_mime_encoding_outlen(&state, res)); size_t outLen = g_mime_encoding_flush (&state, buf, res, outbuf); res = write (1, outbuf, outLen); if (res < 0) { perror ("write"); return; } free (outbuf); } -- Damian Pietras http://www.linuxprogrammingblog.com
Attachment:
Testowy1.doc
Description: MS-Word document