Package: gnupg Version: 1.4.5-3 Severity: grave Tags: security upstream From: Werner Koch <[EMAIL PROTECTED]> Subject: [Announce] GnuPG: remotely controllable function pointer [CVE-2006-6235] To: [EMAIL PROTECTED], info-gnu@gnu.org Date: Wed, 06 Dec 2006 16:55:52 +0100
GnuPG: remotely controllable function pointer [CVE-2006-6235] =============================================================== 2006-12-04 Summary ======= Tavis Ormandy of the Gentoo security team identified a severe and exploitable bug in the processing of encrypted packets in GnuPG. [ Please do not send private mail in response to this message. The mailing list gnupg-devel is the best place to discuss this problem (please subscribe first so you don't need moderator approval [1]). ] Impact ====== Using malformed OpenPGP packets an attacker is able to modify and dereference a function pointer in GnuPG. This is a remotely exploitable bug and affects any use of GnuPG where an attacker can control the data processed by GnuPG. It is not necessary limited to encrypted data, also signed data may be affected. Affected versions: All versions of GnuPG < 1.4.6 All versions of GnuPG-2 < 2.0.2 All beta versions of GnuPG-2 (1.9.0 .. 1.9.95) Affected tools: gpg, gpgv, gpg2 and gpgv2. Affected platforms: All. gpg-agent, gpgsm as well as other tools are not affected. A workaround is not known. [...] This is a patch against GnuPG 1.4.5. Change the directory to g10/ and apply this patch. 2006-12-02 Werner Koch <[EMAIL PROTECTED]> * encr-data.c: Allocate DFX context on the heap and not on the stack. Changes at several places. Fixes CVE-2006-6235. --- encr-data.c.orig 2006-05-16 14:34:26.000000000 +0200 +++ encr-data.c 2006-12-04 11:58:53.000000000 +0100 @@ -44,7 +44,27 @@ typedef struct { char defer[20]; int defer_filled; int eof_seen; -} decode_filter_ctx_t; + int refcount; +} *decode_filter_ctx_t; + + +/* Helper to release the decode context. */ +static void +release_dfx_context (decode_filter_ctx_t dfx) +{ + if (!dfx) + return; + + assert (dfx->refcount); + if ( !--dfx->refcount ) + { + cipher_close (dfx->cipher_hd); + dfx->cipher_hd = NULL; + md_close (dfx->mdc_hash); + dfx->mdc_hash = NULL; + xfree (dfx); + } +} /**************** @@ -60,7 +80,10 @@ decrypt_data( void *procctx, PKT_encrypt unsigned blocksize; unsigned nprefix; - memset( &dfx, 0, sizeof dfx ); + + dfx = xcalloc (1, sizeof *dfx); + dfx->refcount = 1; + if( opt.verbose && !dek->algo_info_printed ) { const char *s = cipher_algo_to_string( dek->algo ); if( s ) @@ -79,15 +102,15 @@ decrypt_data( void *procctx, PKT_encrypt BUG(); if( ed->mdc_method ) { - dfx.mdc_hash = md_open( ed->mdc_method, 0 ); + dfx->mdc_hash = md_open ( ed->mdc_method, 0 ); if ( DBG_HASHING ) - md_start_debug(dfx.mdc_hash, "checkmdc"); + md_start_debug (dfx->mdc_hash, "checkmdc"); } - dfx.cipher_hd = cipher_open( dek->algo, - ed->mdc_method? CIPHER_MODE_CFB - : CIPHER_MODE_AUTO_CFB, 1 ); + dfx->cipher_hd = cipher_open ( dek->algo, + ed->mdc_method? CIPHER_MODE_CFB + : CIPHER_MODE_AUTO_CFB, 1 ); /* log_hexdump( "thekey", dek->key, dek->keylen );*/ - rc = cipher_setkey( dfx.cipher_hd, dek->key, dek->keylen ); + rc = cipher_setkey ( dfx->cipher_hd, dek->key, dek->keylen ); if( rc == G10ERR_WEAK_KEY ) { log_info(_("WARNING: message was encrypted with" @@ -105,7 +128,7 @@ decrypt_data( void *procctx, PKT_encrypt goto leave; } - cipher_setiv( dfx.cipher_hd, NULL, 0 ); + cipher_setiv ( dfx->cipher_hd, NULL, 0 ); if( ed->len ) { for(i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) { @@ -122,8 +145,8 @@ decrypt_data( void *procctx, PKT_encrypt else temp[i] = c; } - cipher_decrypt( dfx.cipher_hd, temp, temp, nprefix+2); - cipher_sync( dfx.cipher_hd ); + cipher_decrypt ( dfx->cipher_hd, temp, temp, nprefix+2); + cipher_sync ( dfx->cipher_hd ); p = temp; /* log_hexdump( "prefix", temp, nprefix+2 ); */ if(dek->symmetric @@ -133,34 +156,34 @@ decrypt_data( void *procctx, PKT_encrypt goto leave; } - if( dfx.mdc_hash ) - md_write( dfx.mdc_hash, temp, nprefix+2 ); + if ( dfx->mdc_hash ) + md_write ( dfx->mdc_hash, temp, nprefix+2 ); - if( ed->mdc_method ) - iobuf_push_filter( ed->buf, mdc_decode_filter, &dfx ); + dfx->refcount++; + if ( ed->mdc_method ) + iobuf_push_filter( ed->buf, mdc_decode_filter, dfx ); else - iobuf_push_filter( ed->buf, decode_filter, &dfx ); + iobuf_push_filter( ed->buf, decode_filter, dfx ); proc_packets( procctx, ed->buf ); ed->buf = NULL; - if( ed->mdc_method && dfx.eof_seen == 2 ) + if( ed->mdc_method && dfx->eof_seen == 2 ) rc = G10ERR_INVALID_PACKET; else if( ed->mdc_method ) { /* check the mdc */ int datalen = md_digest_length( ed->mdc_method ); - cipher_decrypt( dfx.cipher_hd, dfx.defer, dfx.defer, 20); - md_final( dfx.mdc_hash ); + cipher_decrypt ( dfx->cipher_hd, dfx->defer, dfx->defer, 20); + md_final ( dfx->mdc_hash ); if( datalen != 20 - || memcmp(md_read( dfx.mdc_hash, 0 ), dfx.defer, datalen) ) + || memcmp(md_read( dfx->mdc_hash, 0 ), dfx->defer, datalen) ) rc = G10ERR_BAD_SIGN; - /*log_hexdump("MDC calculated:", md_read( dfx.mdc_hash, 0), datalen);*/ - /*log_hexdump("MDC message :", dfx.defer, 20);*/ + /*log_hexdump("MDC calculated:",md_read( dfx->mdc_hash, 0), datalen);*/ + /*log_hexdump("MDC message :", dfx->defer, 20);*/ } leave: - cipher_close(dfx.cipher_hd); - md_close( dfx.mdc_hash ); + release_dfx_context (dfx); return rc; } @@ -171,7 +194,7 @@ static int mdc_decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { - decode_filter_ctx_t *dfx = opaque; + decode_filter_ctx_t dfx = opaque; size_t n, size = *ret_len; int rc = 0; int c; @@ -226,8 +249,10 @@ mdc_decode_filter( void *opaque, int con } if( n ) { - cipher_decrypt( dfx->cipher_hd, buf, buf, n); - md_write( dfx->mdc_hash, buf, n ); + if (dfx->cipher_hd) + cipher_decrypt( dfx->cipher_hd, buf, buf, n); + if (dfx->mdc_hash) + md_write( dfx->mdc_hash, buf, n ); } else { assert( dfx->eof_seen ); @@ -235,6 +260,9 @@ mdc_decode_filter( void *opaque, int con } *ret_len = n; } + else if ( control == IOBUFCTRL_FREE ) { + release_dfx_context (dfx); + } else if( control == IOBUFCTRL_DESC ) { *(char**)buf = "mdc_decode_filter"; } @@ -244,7 +272,7 @@ mdc_decode_filter( void *opaque, int con static int decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { - decode_filter_ctx_t *fc = opaque; + decode_filter_ctx_t fc = opaque; size_t n, size = *ret_len; int rc = 0; @@ -252,12 +280,17 @@ decode_filter( void *opaque, int control assert(a); n = iobuf_read( a, buf, size ); if( n == -1 ) n = 0; - if( n ) - cipher_decrypt( fc->cipher_hd, buf, buf, n); + if( n ) { + if (fc->cipher_hd) + cipher_decrypt( fc->cipher_hd, buf, buf, n); + } else rc = -1; /* eof */ *ret_len = n; } + else if ( control == IOBUFCTRL_FREE ) { + release_dfx_context (fc); + } else if( control == IOBUFCTRL_DESC ) { *(char**)buf = "decode_filter"; } -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]