Update 3: >= instead of > in the UTF-8 conversion Update 2: Work around http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30475 Update 1: fix corruption diff -uNr gnupg-1.4.6-orig/g10/build-packet.c gnupg-1.4.6/g10/build-packet.c --- gnupg-1.4.6-orig/g10/build-packet.c 2006-06-25 12:58:40.000000000 +0200 +++ gnupg-1.4.6/g10/build-packet.c 2007-01-19 16:08:52.132735215 +0100 @@ -745,17 +745,28 @@ /* Calculate new size of the area and allocate */ n0 = oldarea? oldarea->len : 0; - n = n0 + nlen + 1 + buflen; /* length, type, buffer */ + +// n = n0 + nlen + 1 + buflen; /* length, type, buffer */ + + n = n0 + nlen; + assert(n > n0); + assert(n + buflen > n); + n += buflen; + assert(n + 1 > n); + ++ n; + if (oldarea && n <= oldarea->size) { /* fits into the unused space */ newarea = oldarea; /*log_debug ("updating area for type %d\n", type );*/ } else if (oldarea) { + assert(sizeof (*newarea) + n - 1 > n); newarea = xrealloc (oldarea, sizeof (*newarea) + n - 1); newarea->size = n; /*log_debug ("reallocating area for type %d\n", type );*/ } else { + assert(sizeof (*newarea) + n - 1 > n); newarea = xmalloc (sizeof (*newarea) + n - 1); newarea->size = n; /*log_debug ("allocating area for type %d\n", type );*/ diff -uNr gnupg-1.4.6-orig/g10/import.c gnupg-1.4.6/g10/import.c --- gnupg-1.4.6-orig/g10/import.c 2006-12-04 10:36:28.000000000 +0100 +++ gnupg-1.4.6/g10/import.c 2007-01-19 16:08:52.136735443 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "options.h" @@ -533,6 +534,7 @@ else fingerprint_from_sk (sk, array, &n); s = array; + for (i=0; i < n ; i++, s++, p += 2) sprintf (p, "%02X", *s); @@ -547,7 +549,8 @@ u32 keyid[2]; size_t i, pos = 0, n; - buf = xmalloc (17+41+id->len+32); + assert(id->len>=0); + buf = xmalloc (17+41+(size_t)id->len+32); keyid_from_pk (pk, keyid); sprintf (buf, "%08X%08X ", keyid[0], keyid[1]); pos = 17; diff -uNr gnupg-1.4.6-orig/g10/keygen.c gnupg-1.4.6/g10/keygen.c --- gnupg-1.4.6-orig/g10/keygen.c 2006-07-26 12:32:13.000000000 +0200 +++ gnupg-1.4.6/g10/keygen.c 2007-01-19 16:08:52.136735443 +0100 @@ -1958,7 +1958,7 @@ if( !p ) return NULL; n = strlen(p); - uid = xmalloc_clear( sizeof *uid + n - 1 ); + uid = xmalloc_clear( sizeof *uid + n ); uid->len = n; strcpy(uid->name, p); uid->ref = 1; diff -uNr gnupg-1.4.6-orig/g10/misc.c gnupg-1.4.6/g10/misc.c --- gnupg-1.4.6-orig/g10/misc.c 2006-06-30 11:01:49.000000000 +0200 +++ gnupg-1.4.6/g10/misc.c 2007-01-19 16:08:52.136735443 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #include #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2 #include @@ -358,7 +359,16 @@ { static byte marker[SIZEOF_UNSIGNED_LONG*2]; static int initialized; + int fd; + if (!initialized) { + fd=open("/dev/urandom",O_RDONLY); + if (fd!=-1) { + if (read(fd,marker,sizeof(marker))==sizeof(marker)) + initialized=1; + close(fd); + } + } if ( !initialized ) { volatile ulong aa, bb; /* we really want the uninitialized value */ ulong a, b; diff -uNr gnupg-1.4.6-orig/g10/parse-packet.c gnupg-1.4.6/g10/parse-packet.c --- gnupg-1.4.6-orig/g10/parse-packet.c 2006-10-23 15:45:54.000000000 +0200 +++ gnupg-1.4.6/g10/parse-packet.c 2007-01-19 16:08:52.140735671 +0100 @@ -1533,7 +1533,7 @@ buf = p = xmalloc (2 + nbytes); *p++ = nbits >> 8; *p++ = nbits; - for (; nbytes && length; nbytes--, --*length) + for (; nbytes && *length; nbytes--, --*length) *p++ = iobuf_get (inp); if (nbytes) { @@ -1559,6 +1559,7 @@ int is_v4=0; int rc=0; + assert(pktlen > 0); version = iobuf_get_noeof(inp); pktlen--; if( pkttype == PKT_PUBLIC_SUBKEY && version == '#' ) { /* early versions of G10 use old PGP comments packets; diff -uNr gnupg-1.4.6-orig/g10/pipemode.c gnupg-1.4.6/g10/pipemode.c --- gnupg-1.4.6-orig/g10/pipemode.c 2005-07-27 19:02:56.000000000 +0200 +++ gnupg-1.4.6/g10/pipemode.c 2007-01-19 16:08:52.140735671 +0100 @@ -63,13 +63,13 @@ static size_t -make_control ( byte *buf, int code, int operation ) +make_control ( byte *buf, int code, int operation, size_t spaceleft ) { const byte *sesmark; size_t sesmarklen, n=0;; sesmark = get_session_marker( &sesmarklen ); - if ( sesmarklen > 20 ) + if ( sesmarklen > 20 || spaceleftstate = STX_begin; - n += make_control ( buf+n, 1, stx->operation ); + n += make_control ( buf+n, 1, stx->operation, size-n ); /* must leave after a control packet */ goto leave; @@ -192,9 +192,11 @@ return -1; } stx->state = STX_signed_data; - n += make_control ( buf+n, 2, 'B' ); + n += make_control ( buf+n, 2, 'B', size-n ); /* and now we fake a literal data packet much the same * as in armor.c */ + if (size-n<9) + BUG(); buf[n++] = 0xaf; /* old packet format, type 11, var length */ buf[n++] = 0; /* set the length header */ @@ -221,6 +223,7 @@ if (stx->block_mode) { buf[0] = (n-2) >> 8; buf[1] = (n-2); + if (size-n<2) BUG(); if ( buf[0] || buf[1] ) { /* end of blocks marker */ buf[n++] = 0; @@ -228,7 +231,7 @@ } stx->block_mode = 0; } - n += make_control ( buf+n, 3, 'B' ); + n += make_control ( buf+n, 3, 'B', size-n ); } else { log_error ("invalid state for @.\n"); diff -uNr gnupg-1.4.6-orig/g10/seskey.c gnupg-1.4.6/g10/seskey.c --- gnupg-1.4.6-orig/g10/seskey.c 2006-04-03 10:13:20.000000000 +0200 +++ gnupg-1.4.6/g10/seskey.c 2007-01-19 16:08:52.140735671 +0100 @@ -154,6 +154,7 @@ int i,n; MPI a; + assert(len+asnlen>len && len+asnlen+4>4); if( len + asnlen + 4 > nframe ) log_bug("can't encode a %d bit MD into a %d bits frame\n", (int)(len*8), (int)nbits); diff -uNr gnupg-1.4.6-orig/g10/status.c gnupg-1.4.6/g10/status.c --- gnupg-1.4.6-orig/g10/status.c 2006-04-03 09:58:31.000000000 +0200 +++ gnupg-1.4.6/g10/status.c 2007-01-19 16:08:52.140735671 +0100 @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef USE_SHM_COPROCESSING #ifdef USE_CAPABILITIES #include @@ -547,20 +548,22 @@ * If bool, returns static string on true (do not free) or NULL for false */ static char * -do_get_from_fd( const char *keyword, int hidden, int bool ) +do_get_from_fd( const char *keyword, int hidden, int is_bool ) { - int i, len; + int i; + unsigned int len; char *string; if(statusfp!=stdout) fflush(stdout); - write_status_text( bool? STATUS_GET_BOOL : + write_status_text( is_bool? STATUS_GET_BOOL : hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword ); for( string = NULL, i = len = 200; ; i++ ) { if( i >= len-1 ) { char *save = string; + assert(len+100 > len); len += 100; string = hidden? xmalloc_secure ( len ) : xmalloc ( len ); if( save ) @@ -582,7 +585,7 @@ write_status( STATUS_GOT_IT ); - if( bool ) /* Fixme: is this correct??? */ + if( is_bool ) /* Fixme: is this correct??? */ return (string[0] == 'Y' || string[0] == 'y') ? "" : NULL; return string; diff -uNr gnupg-1.4.6-orig/g10/tlv.c gnupg-1.4.6/g10/tlv.c --- gnupg-1.4.6-orig/g10/tlv.c 2005-07-27 19:02:56.000000000 +0200 +++ gnupg-1.4.6/g10/tlv.c 2007-01-19 16:08:52.140735671 +0100 @@ -182,6 +182,8 @@ tag = 0; do { + if(((tag << 7) >> 7) != tag) /* int overflow? */ + return gpg_error (GPG_ERR_BAD_BER); tag <<= 7; if (!length) return gpg_error (GPG_ERR_EOF); @@ -192,6 +194,8 @@ while (c & 0x80); } *r_tag = tag; + if ((size_t)*r_tag != tag) /* truncation? */ + return gpg_error (GPG_ERR_BAD_BER); /* Get the length. */ if (!length) @@ -288,8 +292,12 @@ *buflen = n; return 0; } - for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--) + for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--) { + size_t old=vlen; vlen = vlen*10 + (*s - '0'); + if (vlen/10 != old) + return gpg_error (GPG_ERR_INV_SEXP); + } if (!n || *s != ':') return gpg_error (GPG_ERR_INV_SEXP); s++; n--; diff -uNr gnupg-1.4.6-orig/g10/trustdb.c gnupg-1.4.6/g10/trustdb.c --- gnupg-1.4.6-orig/g10/trustdb.c 2006-03-08 00:20:58.000000000 +0100 +++ gnupg-1.4.6/g10/trustdb.c 2007-01-19 16:08:52.140735671 +0100 @@ -1560,7 +1560,14 @@ u32 expire; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL ); - expire = p? sig->timestamp + buffer_to_u32(p) : 0; + + if (p) { + /* the least we can do is not wrap around --fefe */ + expire = sig->timestamp + buffer_to_u32(p); + if (expire < sig->timestamp) + expire=(size_t)-1; /* all ones */ + } else + expire=0; if (expire==0 || expire > curtime ) { @@ -2025,6 +2032,7 @@ *next_expire = pk->expiredate; if (nkeys == maxkeys) { + assert(maxkeys+1000 > maxkeys && (maxkeys+1001)*sizeof(*keys) > maxkeys*sizeof(*keys)); maxkeys += 1000; keys = xrealloc (keys, (maxkeys+1) * sizeof *keys); } diff -uNr gnupg-1.4.6-orig/keyserver/gpgkeys_hkp.c gnupg-1.4.6/keyserver/gpgkeys_hkp.c --- gnupg-1.4.6-orig/keyserver/gpgkeys_hkp.c 2006-12-03 16:37:44.000000000 +0100 +++ gnupg-1.4.6/keyserver/gpgkeys_hkp.c 2007-01-19 16:08:52.140735671 +0100 @@ -137,8 +137,11 @@ { char *tmp; - keymax+=200; - tmp=realloc(key,keymax+1); + keymax=strlen(line)+keylen+200; + if (keymax > 1ull*1024*1024) + tmp=0; + else + tmp=realloc(key,keymax+1); if(!tmp) { free(key); diff -uNr gnupg-1.4.6-orig/util/cert.c gnupg-1.4.6/util/cert.c --- gnupg-1.4.6-orig/util/cert.c 2006-04-03 10:13:21.000000000 +0200 +++ gnupg-1.4.6/util/cert.c 2007-01-19 16:08:52.144735899 +0100 @@ -138,6 +138,7 @@ /* 15 bytes takes us to here */ + if ((uintptr_t)pt>(uintptr_t)emsg || (uintptr_t)pt+dlen>(uintptr_t)emsg) goto fail; if(ctype==3 && iobuf && dlen) { /* PGP type */ diff -uNr gnupg-1.4.6-orig/util/iobuf.c gnupg-1.4.6/util/iobuf.c --- gnupg-1.4.6-orig/util/iobuf.c 2006-07-31 11:22:48.000000000 +0200 +++ gnupg-1.4.6/util/iobuf.c 2007-01-19 16:08:52.144735899 +0100 @@ -2158,6 +2158,7 @@ while( (c=iobuf_get(a)) != -1 ) { if( nbytes == length ) { /* increase the buffer */ if( length > maxlen ) { /* this is out limit */ +truncate: /* skip the rest of the line */ while( c != '\n' && (c=iobuf_get(a)) != -1 ) ; @@ -2176,6 +2177,8 @@ } *p++ = c; nbytes++; + if (nbytes+1>=maxlen) + goto truncate; if( c == '\n' ) break; } diff -uNr gnupg-1.4.6-orig/util/membuf.c gnupg-1.4.6/util/membuf.c --- gnupg-1.4.6-orig/util/membuf.c 2005-07-27 19:02:56.000000000 +0200 +++ gnupg-1.4.6/util/membuf.c 2007-01-19 16:08:52.144735899 +0100 @@ -23,6 +23,7 @@ #include #include #include +#include #include "util.h" @@ -51,10 +52,13 @@ if (mb->out_of_core) return; + assert(mb->len + len > mb->len); if (mb->len + len >= mb->size) { char *p; + assert(len + 1024 > len); + assert(mb->size + len > mb->size); mb->size += len + 1024; p = xrealloc (mb->buf, mb->size); mb->buf = p; diff -uNr gnupg-1.4.6-orig/util/strgutil.c gnupg-1.4.6/util/strgutil.c --- gnupg-1.4.6-orig/util/strgutil.c 2006-10-02 14:07:23.000000000 +0200 +++ gnupg-1.4.6/util/strgutil.c 2007-01-19 16:09:32.491035103 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef HAVE_LANGINFO_CODESET #include #endif @@ -796,7 +797,7 @@ byte encbuf[8]; int encidx; const byte *s; - size_t n; + size_t n, old_n; byte *buffer = NULL, *p = NULL; unsigned long val = 0; size_t slen; @@ -805,7 +806,7 @@ /* 1. pass (p==NULL): count the extended utf-8 characters */ /* 2. pass (p!=NULL): create string */ for( ;; ) { - for( slen=length, nleft=encidx=0, n=0, s=string; slen; s++, slen-- ) { + for( slen=length, nleft=encidx=0, n=old_n=0, s=string; slen; s++, slen-- ) { if( resync ) { if( !(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)) ) { /* still invalid */ @@ -976,6 +977,7 @@ } } + assert(n >= old_n); old_n=n; } if( !buffer ) { /* allocate the buffer after the first pass */ buffer = p = xmalloc( n + 1 ); @@ -1211,7 +1213,7 @@ const char *p = format; /* Add one to make sure that it is never zero, which might cause malloc to return NULL. */ - int total_width = strlen (format) + 1; + size_t total_width = strlen (format) + 1; va_list ap; /* this is not really portable but works under Windows */ @@ -1225,13 +1227,20 @@ ++p; if (*p == '*') { + int fnord=va_arg (ap, int); + if (total_width+fnord>1) +#endif + if (fnord>INT_MAX || total_width+fnordINT_MAX || total_width+fnord