Package: sylpheed-claws
Version: 0.9.13-1
Severity: normal
Tags: patch

Sylpheed-claws segfaults when using the sylpheed-claws-pgpinline-plugin
from <URL:http://sylpheed.mine.nu:9981/debian/>.

Steps to reproduce:
* Start sylpheed-claws
* Load pgpinline-plugin
* Click "Compose Email"
* Write some nonsense (fill To/Subject/Body)
* Check Options->Privacy System->PGP Inline
* Check Options->Sign
* Click Submit
* Enter your passphrase
* Sylpheed-Claws segfaults

Tracking the bug down showed that it's caused by pgpinline_sign()'s call
to procmime_encode_content() [pgpinline.c:442].
Looking at the latter function it can be seen that:
a) The function will always fail when (meminfo->content ==
MIMECONTENT_MEM) && (encoding == ENC_BASE64).
b) The error handling of that function terribly sucks, which turns a
not-so-serious bug into a segfault.

The source of the bug is line 432:
---
    if (canonicalize_file(mimeinfo->data.filename, tmp_file) < 0) {
---
It is always called, no matter what mimeinfo->content is. Since
mimeinfo->data is a union (filename/mem), canonicalize_file tries to
open the passed mime data (the gpg-clearsigned message) as file, which
fails. At this point tmp_file has not yet been created by
canonicalize_file, so the following fopen on it (line 436) fails too,
which causes fread to access an invalid FILE* [tmp_fd] on line 444,
which results in the segfault.

So this bug is clearly one of sylpheed-claws, and not of the
pgpinline-plugin.

Fixing the segfault is easy, adding >return FALSE;< in 2 places is
enough. See attatchment sylpheed-claws-fixsegv.patch.

Making the function fully working with is a bit more problematic, since
procmime_encode_content() doesn't even know the name of the file where
the mime content is stored. The name isn't passed up by
str_open_as_stream() (which in turn doesn't have it itself, because it's
not returned by my_tmpfile()).

So you're basically left with two options: modify my_tmpfile and
str_open_as_stream to pass up the filename of the temporary file, or to
make a canonicalize_file variant which works on FILE* objects.

An implementation of the second way is in sylpheed-claws-fullfix.patch.
Please apply sylpheed-claws-fixsegv.patch as well as
sylpheed-claws-fullfix.patch. The first one fixes the error handling,
the second one makes the thing work right.

Perhaps this bug is related to #292089 and #280160. The symptoms look
similar, but I don't really understand what the submitter means in
#292089, and I don't use SA via sylpheed, so I can't check #280160.

Cheers,
Greek0

-- System Information:
Debian Release: 3.1
  APT prefers unstable
  APT policy: (990, 'unstable'), (500, 'testing')
Architecture: i386 (i686)
Kernel: Linux 2.6.8r01112004
Locale: [EMAIL PROTECTED], [EMAIL PROTECTED] (charmap=ISO-8859-15)

Versions of packages sylpheed-claws depends on:
ii  libaspell15              0.50.5-5        The GNU Aspell spell-checker runti
ii  libc6                    2.3.2.ds1-20    GNU C Library: Shared libraries an
ii  libcompfaceg1            1989.11.11-24   Compress/decompress images for mai
ii  libglib1.2               1.2.10-9        The GLib library of C routines
ii  libgpgme6                0.3.16-2        GPGME - GnuPG Made Easy
ii  libgtk1.2                1.2.10-17       The GIMP Toolkit set of widgets fo
ii  libldap2                 2.1.30-3        OpenLDAP libraries
ii  libpisock8               0.11.8-10       Library for communicating with a P
ii  libssl0.9.7              0.9.7e-3        SSL shared libraries
ii  libx11-6                 4.3.0.dfsg.1-10 X Window System protocol client li
ii  libxext6                 4.3.0.dfsg.1-10 X Window System miscellaneous exte
ii  libxi6                   4.3.0.dfsg.1-10 X Window System Input extension li
ii  sylpheed-claws-i18n      0.9.13-1        Locale data for Sylpheed Claws (i1
ii  xlibs                    4.3.0.dfsg.1-10 X Keyboard Extension (XKB) configu

-- no debconf information
--- old/sylpheed-claws-0.9.13/src/procmime.c    2004-12-04 09:09:00.000000000 
+0100
+++ sylpheed-claws-0.9.13/src/procmime.c        2005-01-28 00:56:01.000000000 
+0100
@@ -432,12 +432,14 @@
                        if (canonicalize_file(mimeinfo->data.filename, 
tmp_file) < 0) {
                                g_free(tmp_file);
                                fclose(infp);
+                               return FALSE;
                        }
                        if ((tmp_fp = fopen(tmp_file, "rb")) == NULL) {
                                FILE_OP_ERROR(tmp_file, "fopen");
                                unlink(tmp_file);
                                g_free(tmp_file);
                                fclose(infp);
+                               return FALSE;
                        }
                }
 
diff -Nur old/sylpheed-claws-0.9.13.fixsegv/src/common/utils.c 
sylpheed-claws-0.9.13/src/common/utils.c
--- old/sylpheed-claws-0.9.13.fixsegv/src/common/utils.c        2005-01-29 
11:04:33.000000000 +0100
+++ sylpheed-claws-0.9.13/src/common/utils.c    2005-01-29 11:23:57.000000000 
+0100
@@ -2597,10 +2597,7 @@
 gint canonicalize_file(const gchar *src, const gchar *dest)
 {
        FILE *src_fp, *dest_fp;
-       gchar buf[BUFFSIZE];
-       gint len;
-       gboolean err = FALSE;
-       gboolean last_linebreak = FALSE;
+       gint ErrorCode;
 
        if ((src_fp = fopen(src, "rb")) == NULL) {
                FILE_OP_ERROR(src, "fopen");
@@ -2618,6 +2615,44 @@
                g_warning("can't change file mode\n");
        }
 
+
+       if ((ErrorCode = canonicalize_file_from_fp(src_fp, dest_fp)) < 0) {
+               switch (ErrorCode) {
+                       case -1:
+                               FILE_OP_ERROR(src, "reading from");
+                               break;
+                       case -2:
+                               FILE_OP_ERROR(dest, "writing to");
+                               break;
+                       default:
+                               fprintf(stderr, 
+                                               "Unknown Error in 
canonicalize_file_from_fp");
+                               break;
+               }
+
+               fclose(src_fp);
+               fclose(dest_fp); 
+               unlink(dest);
+               return -1;
+       }
+
+       fclose(src_fp);
+       fclose(dest_fp); 
+       return 0;
+}
+
+/* canonicalize_file_from_fp reads from src_fp, changes all line endings to
+ * CRLF and adds a CRLF to the last line, if needed. The output is written to
+ * dest_fp. 0 is returned on normal operation, -1 if there was an error reading
+ * from src_fp, and -2 if there was an error writing to dest_fp.
+ * canonicalize_file_from_fp rewinds both fp's when it completed without
+ * errors. Otherwise the positions of the streams are undefined. */
+gint canonicalize_file_from_fp(FILE* src_fp, FILE* dest_fp)
+{
+       gchar buf[BUFFSIZE];
+       gint len;
+       gboolean last_linebreak = FALSE;
+
        while (fgets(buf, sizeof(buf), src_fp) != NULL) {
                gint r = 0;
 
@@ -2641,34 +2676,21 @@
                }
 
                if (r == EOF) {
-                       g_warning("writing to %s failed.\n", dest);
-                       fclose(dest_fp);
-                       fclose(src_fp);
-                       unlink(dest);
-                       return -1;
+                       return -2;
                }
        }
 
        if (last_linebreak == TRUE) {
                if (fputs("\r\n", dest_fp) == EOF)
-                       err = TRUE;
+                       return -2;
        }
 
        if (ferror(src_fp)) {
-               FILE_OP_ERROR(src, "fgets");
-               err = TRUE;
-       }
-       fclose(src_fp);
-       if (fclose(dest_fp) == EOF) {
-               FILE_OP_ERROR(dest, "fclose");
-               err = TRUE;
-       }
-
-       if (err) {
-               unlink(dest);
                return -1;
        }
 
+       rewind(src_fp);
+       rewind(dest_fp);
        return 0;
 }
 
diff -Nur old/sylpheed-claws-0.9.13.fixsegv/src/common/utils.h 
sylpheed-claws-0.9.13/src/common/utils.h
--- old/sylpheed-claws-0.9.13.fixsegv/src/common/utils.h        2005-01-29 
11:04:33.000000000 +0100
+++ sylpheed-claws-0.9.13/src/common/utils.h    2005-01-29 11:24:10.000000000 
+0100
@@ -410,6 +410,7 @@
 gchar *canonicalize_str                (const gchar    *str);
 gint canonicalize_file         (const gchar    *src,
                                 const gchar    *dest);
+gint canonicalize_file_from_fp(FILE* src_fp, FILE* dest_fp);
 gint canonicalize_file_replace (const gchar    *file);
 gint uncanonicalize_file       (const gchar    *src,
                                 const gchar    *dest);
diff -Nur old/sylpheed-claws-0.9.13.fixsegv/src/procmime.c 
sylpheed-claws-0.9.13/src/procmime.c
--- old/sylpheed-claws-0.9.13.fixsegv/src/procmime.c    2005-01-29 
11:07:40.000000000 +0100
+++ sylpheed-claws-0.9.13/src/procmime.c        2005-01-29 10:50:19.000000000 
+0100
@@ -425,20 +425,39 @@
                gchar inbuf[B64_LINE_SIZE], outbuf[B64_BUFFSIZE];
                FILE *tmp_fp = infp;
                gchar *tmp_file = NULL;
+               gint ErrorCode;
 
                if (mimeinfo->type == MIMETYPE_TEXT ||
                    mimeinfo->type == MIMETYPE_MESSAGE) {
+
                        tmp_file = get_tmp_file();
-                       if (canonicalize_file(mimeinfo->data.filename, 
tmp_file) < 0) {
+                       if ((tmp_fp = fopen(tmp_file, "w+b")) == NULL) {
+                               FILE_OP_ERROR(tmp_file, "fopen");
+                               unlink(tmp_file);
                                g_free(tmp_file);
                                fclose(infp);
                                return FALSE;
                        }
-                       if ((tmp_fp = fopen(tmp_file, "rb")) == NULL) {
-                               FILE_OP_ERROR(tmp_file, "fopen");
+
+                       if ((ErrorCode = canonicalize_file_from_fp(infp, 
tmp_fp)) < 0) {
+                               switch (ErrorCode) {
+                                       case -1:
+                                               fprintf(stderr, 
+                                                               "Read error in 
canonicalize_file_from_fp");
+                                               break;
+                                       case -2:
+                                               FILE_OP_ERROR(tmp_file, 
"writing to");
+                                               break;
+                                       default:
+                                               fprintf(stderr, 
+                                                               "Unknown error 
in canonicalize_file_from_fp");
+                                               break;
+                               }
+
+                               fclose(infp);
+                               fclose(tmp_fp);
                                unlink(tmp_file);
                                g_free(tmp_file);
-                               fclose(infp);
                                return FALSE;
                        }
                }

Reply via email to