commit 9f7f0c94b67e9506ebf8ca674dd6cbb6a7989f44
Author: Oswald Buddenhagen <o...@users.sf.net>
Date:   Wed Nov 24 16:57:00 2021 +0100

    CVE-2021-3657: security fixes
    
    unlike in the 1.4 branch, we use signed ints for offsets and lengths, so
    many of the qualifying statements from the 1.4 series don't apply.

 src/drv_imap.c    |  9 +++++++++
 src/drv_maildir.c |  8 +++++++-
 src/socket.c      |  8 ++++++--
 src/sync.c        | 15 ++++++++++-----
 4 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/src/drv_imap.c b/src/drv_imap.c
index 4cc3b2a..0d6c869 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -780,6 +780,11 @@ parse_imap_list( imap_store_t *ctx, char **sp, 
parse_list_state_t *sts )
                        bytes = cur->len = strtol( s + 1, &s, 10 );
                        if (*s != '}' || *++s)
                                goto bail;
+                       if ((uint)bytes >= INT_MAX) {
+                               error( "IMAP error: excessively large literal 
from %s "
+                                      "- THIS MIGHT BE AN ATTEMPT TO HACK 
YOU!\n", ctx->conn.name );
+                               goto bail;
+                       }
 
                        s = cur->val = nfmalloc( cur->len + 1 );
                        s[cur->len] = 0;
@@ -1279,6 +1284,10 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char 
*cmd ATTR_UNUSED )
        }
        arg = list->val;
        argl = list->len;
+       if (argl > 1000) {
+               warn( "IMAP warning: ignoring unreasonably long mailbox name 
'%.100s[...]'\n", arg );
+               goto skip;
+       }
        if ((l = strlen( ctx->prefix ))) {
                if (!starts_with( arg, argl, ctx->prefix, l )) {
                        if (is_inbox( ctx, arg, argl )) {
diff --git a/src/drv_maildir.c b/src/drv_maildir.c
index e1622d3..40a4d2a 100644
--- a/src/drv_maildir.c
+++ b/src/drv_maildir.c
@@ -1147,7 +1147,8 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t 
*msglist )
                                        }
                                        goto retry;
                                }
-                               entry->size = st.st_size;
+                               // The clipped value is good enough for MaxSize 
comparisons.
+                               entry->size = st.st_size > INT_MAX ? INT_MAX : 
(int)st.st_size;
                        }
                        if (want_tuid || want_msgid) {
                                if (!(f = fopen( buf, "r" ))) {
@@ -1534,12 +1535,17 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, 
msg_data_t *data,
                }
        }
        fstat( fd, &st );
+       if (st.st_size > INT_MAX) {
+               error( "Maildir error: %s is too big", buf );
+               goto mbad;
+       }
        data->len = st.st_size;
        if (data->date == -1)
                data->date = st.st_mtime;
        data->data = nfmalloc( data->len );
        if (read( fd, data->data, data->len ) != data->len) {
                sys_error( "Maildir error: cannot read %s", buf );
+         mbad:
                close( fd );
                cb( DRV_MSG_BAD, aux );
                return;
diff --git a/src/socket.c b/src/socket.c
index 84449e7..d8548a9 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -898,6 +898,8 @@ do_append( conn_t *conn, buff_chunk_t *bc )
 /* This is big enough to avoid excessive chunking, but is
  * sufficiently small to keep SSL latency low with a slow uplink. */
 #define WRITE_CHUNK_SIZE 1024
+// Huge data blocks (message payloads) are forcibly chunked.
+#define MAX_WRITE_CHUNK_SIZE (1 << 30)
 
 static void
 do_flush( conn_t *conn )
@@ -952,7 +954,8 @@ do_flush( conn_t *conn )
 void
 socket_write( conn_t *conn, conn_iovec_t *iov, int iovcnt )
 {
-       int i, buf_avail, len, offset = 0, total = 0;
+       int i, buf_avail, len, offset = 0;
+       uint total = 0;
        buff_chunk_t *bc;
 
        for (i = 0; i < iovcnt; i++)
@@ -971,7 +974,8 @@ socket_write( conn_t *conn, conn_iovec_t *iov, int iovcnt )
                         * predict a reasonable output buffer size anyway - 
deflatePending() does
                         * not account for consumed but not yet compressed 
input, and adding up
                         * the deflateBound()s would be a tad *too* 
pessimistic. */
-                       buf_avail = total > WRITE_CHUNK_SIZE ? total : 
WRITE_CHUNK_SIZE;
+                       buf_avail = total > MAX_WRITE_CHUNK_SIZE ? 
MAX_WRITE_CHUNK_SIZE :
+                                       total > WRITE_CHUNK_SIZE ? total : 
WRITE_CHUNK_SIZE;
                        bc = nfmalloc( offsetof(buff_chunk_t, data) + buf_avail 
);
                        bc->len = 0;
 #ifndef HAVE_LIBZ
diff --git a/src/sync.c b/src/sync.c
index 7d3fe79..46e089c 100644
--- a/src/sync.c
+++ b/src/sync.c
@@ -333,7 +333,7 @@ copy_msg_bytes( char **out_ptr, const char *in_buf, int 
*in_idx, int in_len, int
 }
 
 static int
-copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars )
+copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars, int t )
 {
        char *in_buf = vars->data.data;
        int in_len = vars->data.len;
@@ -361,7 +361,8 @@ copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars )
                                goto nloop;
                        }
                }
-               /* invalid message */
+               warn( "Warning: message %u from %s has incomplete header; 
skipping.\n",
+                     vars->msg->uid, str_ms[1-t] );
                free( in_buf );
                return 0;
          oke:
@@ -382,6 +383,12 @@ copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars 
)
        }
 
        vars->data.len = in_len + extra;
+       if ((uint)vars->data.len > INT_MAX) {
+               warn( "Warning: message %u from %s is too big after conversion; 
skipping.\n",
+                     vars->msg->uid, str_ms[1-t] );
+               free( in_buf );
+               return 0;
+       }
        char *out_buf = vars->data.data = nfmalloc( vars->data.len );
        idx = 0;
        if (vars->srec) {
@@ -423,9 +430,7 @@ msg_fetched( int sts, void *aux )
                scr = (svars->drv[1-t]->get_caps( svars->ctx[1-t] ) / DRV_CRLF) 
& 1;
                tcr = (svars->drv[t]->get_caps( svars->ctx[t] ) / DRV_CRLF) & 1;
                if (vars->srec || scr != tcr) {
-                       if (!copy_msg_convert( scr, tcr, vars )) {
-                               warn( "Warning: message %u from %s has 
incomplete header.\n",
-                                     vars->msg->uid, str_ms[1-t] );
+                       if (!copy_msg_convert( scr, tcr, vars, t )) {
                                vars->cb( SYNC_NOGOOD, 0, vars );
                                return;
                        }


_______________________________________________
isync-devel mailing list
isync-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to