Bugtraq mailing list archives

Cyrus Sieve / libSieve buffer overflow


From: Timo Sirainen <tss () iki fi>
Date: Mon, 2 Dec 2002 19:56:45 +0200

problem
-------

Cyrus' Sieve implementation contains a couple of classic string based
buffer overflows in script parsing code. Anyone who can execute Sieve
scripts can exploit these bugs. Versions up to libSieve 2.1.2 and Cyrus
IMAP 2.1.10 are affected.

Note that with Cyrus IMAP server exploiting this gives you the privileges
of Cyrus user, capable of reading all users mails.

Problem comes when giving the script a >100 chars long corrupted header
name, >100 chars long IMAP flag or a script that contains lots of errors
to overflow the 500 char limit in error message.

fix
---

Apply the included patch. Note that this changes only the yacc files, you
still need to generate .c files from them. libSieve 2.1.3 will hopefully
also contain some more hardening against potential buffer overflows.

diff -ru cyrus-imapd-2.1.10-old/sieve/addr.y cyrus-imapd-2.1.10/sieve/addr.y
--- cyrus-imapd-2.1.10-old/sieve/addr.y 2002-10-28 18:30:18.000000000 +0200
+++ cyrus-imapd-2.1.10/sieve/addr.y     2002-12-02 04:52:58.000000000 +0200
@@ -82,8 +82,9 @@
 /* copy address error message into buffer provided by sieve parser */
 int yyerror(char *s)
 {
-extern char addrerr[];
+extern char addrerr[512];
 
-    strcpy(addrerr, s);
+    strncpy(addrerr, s, sizeof(addrerr)-1);
+    addrerr[sizeof(addrerr)-1] = '\0';
     return 0;
 }
diff -ru cyrus-imapd-2.1.10-old/sieve/sieve.y cyrus-imapd-2.1.10/sieve/sieve.y
--- cyrus-imapd-2.1.10-old/sieve/sieve.y        2002-05-14 19:51:50.000000000 +0300
+++ cyrus-imapd-2.1.10/sieve/sieve.y    2002-12-02 03:57:17.000000000 +0200
@@ -810,7 +810,7 @@
     addrptr = s;
     addrerr[0] = '\0'; /* paranoia */
     if (addrparse()) {
-       sprintf(errbuf, "address '%s': %s", s, addrerr);
+       snprintf(errbuf, sizeof(errbuf), "address '%s': %s", s, addrerr);
        yyerror(errbuf);
        return 0;
     }
@@ -835,7 +835,7 @@
           ;  controls, SP, and
           ;  ":". */
        if (!((*h >= 33 && *h <= 57) || (*h >= 59 && *h <= 126))) {
-           sprintf(errbuf, "header '%s': not a valid header", hdr);
+           snprintf(errbuf, sizeof(errbuf), "header '%s': not a valid header", hdr);
            yyerror(errbuf);
            return 0;
        }
@@ -853,14 +853,14 @@
        if (strcmp(f, "\\seen") && strcmp(f, "\\answered") &&
            strcmp(f, "\\flagged") && strcmp(f, "\\draft") &&
            strcmp(f, "\\deleted")) {
-           sprintf(errbuf, "flag '%s': not a system flag", f);
+           snprintf(errbuf, sizeof(errbuf), "flag '%s': not a system flag", f);
            yyerror(errbuf);
            return 0;
        }
        return 1;
     }
     if (!imparse_isatom(f)) {
-       sprintf(errbuf, "flag '%s': not a valid keyword", f);
+       snprintf(errbuf, sizeof(errbuf), "flag '%s': not a valid keyword", f);
        yyerror(errbuf);
        return 0;
     }


Current thread: