head	1.2;
access;
symbols
	OPENPKG_2_STABLE_MP:1.2
	OPENPKG_E1_MP_HEAD:1.2
	OPENPKG_E1_MP:1.2
	OPENPKG_E1_MP_2_STABLE:1.1
	OPENPKG_E1_FP:1.1
	OPENPKG_2_STABLE_20061018:1.1
	OPENPKG_2_STABLE:1.1.0.10
	OPENPKG_2_STABLE_BP:1.1
	OPENPKG_2_5_SOLID:1.1.0.8
	OPENPKG_2_5_SOLID_BP:1.1
	OPENPKG_2_4_RELEASE:1.1
	OPENPKG_2_4_SOLID:1.1.0.6
	OPENPKG_2_4_SOLID_BP:1.1
	OPENPKG_2_3_SOLID:1.1.0.4
	OPENPKG_2_2_SOLID:1.1.0.2;
locks; strict;
comment	@# @;


1.2
date	2007.01.05.20.00.12;	author rse;	state Exp;
branches;
next	1.1;
commitid	mWZCI7JOgf5I7m1s;

1.1
date	2005.06.08.12.28.29;	author ms;	state dead;
branches
	1.1.2.1
	1.1.4.1
	1.1.10.1;
next	;

1.1.2.1
date	2005.06.08.12.28.29;	author ms;	state Exp;
branches;
next	;

1.1.4.1
date	2005.06.08.12.32.57;	author ms;	state Exp;
branches;
next	;

1.1.10.1
date	2007.01.05.20.26.59;	author rse;	state Exp;
branches;
next	;
commitid	r7pjDr2YM1bUgm1s;


desc
@@


1.2
log
@mktemp is too unportable, so provide a fallback solution for portability
@
text
@Index: bzdiff
--- bzdiff.orig	2007-01-05 20:55:31 +0100
+++ bzdiff	2007-01-05 20:57:56 +0100
@@@@ -37,10 +37,15 @@@@
 	echo "Usage: $prog [${comp}_options] file [file]"
 	exit 1
 fi
+if type mktemp >/dev/null 2>&1; then
 tmp=`mktemp ${TMPDIR:-/tmp}/bzdiff.XXXXXXXXXX` || {
       echo 'cannot create a temporary file' >&2
       exit 1
 }
+else 
+    set -C
+    tmp=${TMPDIR-/tmp}/bzdiff.$$
+fi
 set $FILES
 if test $# -eq 1; then
 	FILE=`echo "$1" | sed 's/.bz2$//'`
@


1.1
log
@file bzip2.patch was initially added on branch OPENPKG_2_2_SOLID.
@
text
@d1 19
@


1.1.10.1
log
@MFC: security fixed version
@
text
@a0 19
Index: bzdiff
--- bzdiff.orig	2007-01-05 20:55:31 +0100
+++ bzdiff	2007-01-05 20:57:56 +0100
@@@@ -37,10 +37,15 @@@@
 	echo "Usage: $prog [${comp}_options] file [file]"
 	exit 1
 fi
+if type mktemp >/dev/null 2>&1; then
 tmp=`mktemp ${TMPDIR:-/tmp}/bzdiff.XXXXXXXXXX` || {
       echo 'cannot create a temporary file' >&2
       exit 1
 }
+else 
+    set -C
+    tmp=${TMPDIR-/tmp}/bzdiff.$$
+fi
 set $FILES
 if test $# -eq 1; then
 	FILE=`echo "$1" | sed 's/.bz2$//'`
@


1.1.4.1
log
@bzip2 based corrections in bzip2, analog, and most importantly openpkg itself: OpenPKG-SA-2005.008 (CAN-2005-0953 and CAN-2005-1260)
@
text
@a0 382
OpenPKG-SA-2005.008 and CAN-2005-0953,
TOCTOU file mode vulnerability.
Parts of following patch taken from Ubuntu (backport from bzip2 1.0.3):
  http://security.ubuntu.com/ubuntu/pool/main/b/bzip2/bzip2_1.0.2-2ubuntu0.1.diff.gz
Parts of following patch attributed to Steve GRUBB:
  http://marc.theaimsgroup.com/?l=bugtraq&m=111352423504277

Index: bzip2.c
diff -Nau bzip2.c.orig bzip2.c
--- bzip2.c.orig	2005-06-06 19:56:47 +0200
+++ bzip2.c	2005-06-06 19:57:18 +0200
@@@@ -312,6 +312,7 @@@@
 
 static void    copyFileName ( Char*, Char* );
 static void*   myMalloc     ( Int32 );
+static int     applySavedFileAttrToOutputFile ( int fd );
 
 
 
@@@@ -457,6 +458,10 @@@@
    ret = fflush ( zStream );
    if (ret == EOF) goto errhandler_io;
    if (zStream != stdout) {
+      int fd = fileno ( zStream );
+      if (fd < 0) goto errhandler_io;
+      ret = applySavedFileAttrToOutputFile ( fd );
+      if (ret != 0) goto errhandler_io;
       ret = fclose ( zStream );
       outputHandleJustInCase = NULL;
       if (ret == EOF) goto errhandler_io;
@@@@ -567,6 +572,12 @@@@
 
    closeok:
    if (ferror(zStream)) goto errhandler_io;
+   if ( stream != stdout) {
+      int fd = fileno ( stream );
+      if (fd < 0) goto errhandler_io;
+      ret = applySavedFileAttrToOutputFile ( fd );
+      if (ret != 0) goto errhandler_io;
+   }
    ret = fclose ( zStream );
    if (ret == EOF) goto errhandler_io;
 
@@@@ -1134,16 +1145,26 @@@@
    uTimBuf.actime = fileMetaInfo.st_atime;
    uTimBuf.modtime = fileMetaInfo.st_mtime;
 
-   retVal = chmod ( dstName, fileMetaInfo.st_mode );
-   ERROR_IF_NOT_ZERO ( retVal );
-
    retVal = utime ( dstName, &uTimBuf );
    ERROR_IF_NOT_ZERO ( retVal );
+#  endif
+}
+
+static
+int applySavedFileAttrToOutputFile ( int fd )
+{
+#  if BZ_UNIX
+   IntNative      retVal;
+
+   retVal = fchmod ( fd, fileMetaInfo.st_mode );
+   if (retVal != 0)
+       return retVal;
 
-   retVal = chown ( dstName, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
+   (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
    /* chown() will in many cases return with EPERM, which can
       be safely ignored.
    */
+   return 0;
 #  endif
 }
 
Index: bzip2recover.c
diff -Nau bzip2recover.c.orig bzip2recover.c
--- bzip2recover.c.orig	2005-06-06 19:56:47 +0200
+++ bzip2recover.c	2005-06-06 19:57:18 +0200
@@@@ -56,6 +56,8 @@@@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 
 /* This program records bit locations in the file to be recovered.
@@@@ -301,6 +303,19 @@@@
        name[n-1] == '2');
 }
 
+/*---------------------------------------------*/
+/* Open an output file safely with O_EXCL and good permissions */
+FILE* fopen_output( Char* name, const char* mode )
+{
+  FILE *fp;
+  int   fh;
+   
+  fh = open(name, O_WRONLY|O_CREAT|O_EXCL, 0600);
+  if (fh == -1) return NULL;
+  fp = fdopen(fh, mode);
+  if (fp == NULL) close(fh);
+  return fp;
+}
 
 /*---------------------------------------------------*/
 /*---                                             ---*/
@@@@ -518,7 +533,7 @@@@
          fprintf ( stderr, "   writing block %d to `%s' ...\n",
                            wrBlock+1, outFileName );
 
-         outFile = fopen ( outFileName, "wb" );
+         outFile = fopen_output ( outFileName, "wb" );
          if (outFile == NULL) {
             fprintf ( stderr, "%s: can't write `%s'\n",
                       progName, outFileName );


OpenPKG-SA-2005.008 and CAN-2005-1260,
Infinite loop in decompression of specially crafted bzip2 archives.
Parts of following patch taken from Ubuntu (backport from bzip2 1.0.3):
  http://security.ubuntu.com/ubuntu/pool/main/b/bzip2/bzip2_1.0.2-2ubuntu0.1.diff.gz

Index: bzlib.c
diff -Nau bzlib.c.orig bzlib.c
--- bzlib.c.orig	2005-06-06 19:56:47 +0200
+++ bzlib.c	2005-06-06 20:04:37 +0200
@@@@ -574,8 +574,11 @@@@
 
 
 /*---------------------------------------------------*/
+/* Return  True if data corruption is discovered.
+   Returns False if there is no problem.
+*/
 static
-void unRLE_obuf_to_output_FAST ( DState* s )
+Bool unRLE_obuf_to_output_FAST ( DState* s )
 {
    UChar k1;
 
@@@@ -584,7 +587,7 @@@@
       while (True) {
          /* try to finish existing run */
          while (True) {
-            if (s->strm->avail_out == 0) return;
+            if (s->strm->avail_out == 0) return False;
             if (s->state_out_len == 0) break;
             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
@@@@ -596,8 +599,11 @@@@
          }
    
          /* can a new run be started? */
-         if (s->nblock_used == s->save_nblock+1) return;
+         if (s->nblock_used == s->save_nblock+1) return False;
                
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
    
          s->state_out_len = 1;
          s->state_out_ch = s->k0;
@@@@ -667,6 +673,10 @@@@
                cs_avail_out--;
             }
          }   
+         /* Only caused by corrupt data stream? */
+         if (c_nblock_used > s_save_nblockPP)
+            return True;
+
          /* can a new run be started? */
          if (c_nblock_used == s_save_nblockPP) {
             c_state_out_len = 0; goto return_notr;
@@@@ -712,6 +722,7 @@@@
       s->strm->avail_out    = cs_avail_out;
       /* end save */
    }
+   return False;
 }
 
 
@@@@ -732,8 +743,11 @@@@
 
 
 /*---------------------------------------------------*/
+/* Return  True if data corruption is discovered.
+   Returns False if there is no problem.
+*/
 static
-void unRLE_obuf_to_output_SMALL ( DState* s )
+Bool unRLE_obuf_to_output_SMALL ( DState* s )
 {
    UChar k1;
 
@@@@ -742,7 +756,7 @@@@
       while (True) {
          /* try to finish existing run */
          while (True) {
-            if (s->strm->avail_out == 0) return;
+            if (s->strm->avail_out == 0) return False;
             if (s->state_out_len == 0) break;
             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
@@@@ -754,8 +768,11 @@@@
          }
    
          /* can a new run be started? */
-         if (s->nblock_used == s->save_nblock+1) return;
-               
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
    
          s->state_out_len = 1;
          s->state_out_ch = s->k0;
@@@@ -788,7 +805,7 @@@@
       while (True) {
          /* try to finish existing run */
          while (True) {
-            if (s->strm->avail_out == 0) return;
+            if (s->strm->avail_out == 0) return False;
             if (s->state_out_len == 0) break;
             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
@@@@ -800,7 +817,11 @@@@
          }
    
          /* can a new run be started? */
-         if (s->nblock_used == s->save_nblock+1) return;
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
    
          s->state_out_len = 1;
          s->state_out_ch = s->k0;
@@@@ -830,6 +851,7 @@@@
 /*---------------------------------------------------*/
 int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
 {
+   Bool corrupt;
    DState* s;
    if (strm == NULL) return BZ_PARAM_ERROR;
    s = strm->state;
@@@@ -840,12 +862,13 @@@@
       if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
       if (s->state == BZ_X_OUTPUT) {
          if (s->smallDecompress)
-            unRLE_obuf_to_output_SMALL ( s ); else
-            unRLE_obuf_to_output_FAST  ( s );
+            corrupt = unRLE_obuf_to_output_SMALL ( s ); else
+            corrupt = unRLE_obuf_to_output_FAST  ( s );
+         if (corrupt) return BZ_DATA_ERROR;
          if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
             BZ_FINALISE_CRC ( s->calculatedBlockCRC );
             if (s->verbosity >= 3) 
-               VPrintf2 ( " {0x%x, 0x%x}", s->storedBlockCRC, 
+               VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, 
                           s->calculatedBlockCRC );
             if (s->verbosity >= 2) VPrintf0 ( "]" );
             if (s->calculatedBlockCRC != s->storedBlockCRC)
@@@@ -863,7 +886,7 @@@@
          Int32 r = BZ2_decompress ( s );
          if (r == BZ_STREAM_END) {
             if (s->verbosity >= 3)
-               VPrintf2 ( "\n    combined CRCs: stored = 0x%x, computed = 0x%x", 
+               VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x", 
                           s->storedCombinedCRC, s->calculatedCombinedCRC );
             if (s->calculatedCombinedCRC != s->storedCombinedCRC)
                return BZ_DATA_ERROR;
Index: compress.c
diff -Nau compress.c.orig compress.c
--- compress.c.orig	2005-06-06 19:56:47 +0200
+++ compress.c	2005-06-06 20:00:50 +0200
@@@@ -488,9 +488,11 @@@@
       /*--
         Recompute the tables based on the accumulated frequencies.
       --*/
+      /* maxLen was changed from 20 to 17 in bzip2-1.0.3.  See 
+         comment in huffman.c for details. */
       for (t = 0; t < nGroups; t++)
          BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), 
-                                 alphaSize, 20 );
+                                 alphaSize, 17 /*20*/ );
    }
 
 
@@@@ -527,7 +529,7 @@@@
          if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
          if (s->len[t][i] < minLen) minLen = s->len[t][i];
       }
-      AssertH ( !(maxLen > 20), 3004 );
+      AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
       AssertH ( !(minLen < 1),  3005 );
       BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), 
                           minLen, maxLen, alphaSize );
@@@@ -651,8 +653,8 @@@@
       if (s->blockNo > 1) s->numZ = 0;
 
       if (s->verbosity >= 2)
-         VPrintf4( "    block %d: crc = 0x%8x, "
-                   "combined CRC = 0x%8x, size = %d\n",
+         VPrintf4( "    block %d: crc = 0x%08x, "
+                   "combined CRC = 0x%08x, size = %d\n",
                    s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
 
       BZ2_blockSort ( s );
@@@@ -703,7 +705,7 @@@@
       bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
       bsPutUInt32 ( s, s->combinedCRC );
       if (s->verbosity >= 2)
-         VPrintf1( "    final combined CRC = 0x%x\n   ", s->combinedCRC );
+         VPrintf1( "    final combined CRC = 0x%08x\n   ", s->combinedCRC );
       bsFinishWrite ( s );
    }
 }
Index: decompress.c
diff -Nau decompress.c.orig decompress.c
--- decompress.c.orig	2005-06-06 19:56:47 +0200
+++ decompress.c	2005-06-06 20:00:50 +0200
@@@@ -524,17 +524,23 @@@@
       if (s->origPtr < 0 || s->origPtr >= nblock)
          RETURN(BZ_DATA_ERROR);
 
+      /*-- Set up cftab to facilitate generation of T^(-1) --*/
+      s->cftab[0] = 0;
+      for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
+      for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
+      for (i = 0; i <= 256; i++) {
+         if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
+            /* s->cftab[i] can legitimately be == nblock */
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+
       s->state_out_len = 0;
       s->state_out_ch  = 0;
       BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
       s->state = BZ_X_OUTPUT;
       if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
 
-      /*-- Set up cftab to facilitate generation of T^(-1) --*/
-      s->cftab[0] = 0;
-      for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
-      for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
-
       if (s->smallDecompress) {
 
          /*-- Make a copy of cftab, used in generation of T --*/
Index: huffman.c
diff -Nau huffman.c.orig huffman.c
--- huffman.c.orig	2005-06-06 19:56:47 +0200
+++ huffman.c	2005-06-06 20:00:50 +0200
@@@@ -162,7 +162,24 @@@@
       
       if (! tooLong) break;
 
-      for (i = 1; i < alphaSize; i++) {
+      /* 17 Oct 04: keep-going condition for the following loop used
+         to be 'i < alphaSize', which missed the last element,
+         theoretically leading to the possibility of the compressor
+         looping.  However, this count-scaling step is only needed if
+         one of the generated Huffman code words is longer than
+         maxLen, which up to and including version 1.0.2 was 20 bits,
+         which is extremely unlikely.  In version 1.0.3 maxLen was
+         changed to 17 bits, which has minimal effect on compression
+         ratio, but does mean this scaling step is used from time to
+         time, enough to verify that it works.
+
+         This means that bzip2-1.0.3 and later will only produce
+         Huffman codes with a maximum length of 17 bits.  However, in
+         order to preserve backwards compatibility with bitstreams
+         produced by versions pre-1.0.3, the decompressor must still
+         handle lengths of up to 20. */
+
+      for (i = 1; i <= alphaSize; i++) {
          j = weight[i] >> 8;
          j = 1 + (j / 2);
          weight[i] = j << 8;
@


1.1.2.1
log
@bzip2 based corrections in bzip2, analog, and most importantly openpkg itself: OpenPKG-SA-2005.008 (CAN-2005-0953 and CAN-2005-1260)
@
text
@a0 382
OpenPKG-SA-2005.008 and CAN-2005-0953,
TOCTOU file mode vulnerability.
Parts of following patch taken from Ubuntu (backport from bzip2 1.0.3):
  http://security.ubuntu.com/ubuntu/pool/main/b/bzip2/bzip2_1.0.2-2ubuntu0.1.diff.gz
Parts of following patch attributed to Steve GRUBB:
  http://marc.theaimsgroup.com/?l=bugtraq&m=111352423504277

Index: bzip2.c
diff -Nau bzip2.c.orig bzip2.c
--- bzip2.c.orig	2005-06-06 19:56:47 +0200
+++ bzip2.c	2005-06-06 19:57:18 +0200
@@@@ -312,6 +312,7 @@@@
 
 static void    copyFileName ( Char*, Char* );
 static void*   myMalloc     ( Int32 );
+static int     applySavedFileAttrToOutputFile ( int fd );
 
 
 
@@@@ -457,6 +458,10 @@@@
    ret = fflush ( zStream );
    if (ret == EOF) goto errhandler_io;
    if (zStream != stdout) {
+      int fd = fileno ( zStream );
+      if (fd < 0) goto errhandler_io;
+      ret = applySavedFileAttrToOutputFile ( fd );
+      if (ret != 0) goto errhandler_io;
       ret = fclose ( zStream );
       outputHandleJustInCase = NULL;
       if (ret == EOF) goto errhandler_io;
@@@@ -567,6 +572,12 @@@@
 
    closeok:
    if (ferror(zStream)) goto errhandler_io;
+   if ( stream != stdout) {
+      int fd = fileno ( stream );
+      if (fd < 0) goto errhandler_io;
+      ret = applySavedFileAttrToOutputFile ( fd );
+      if (ret != 0) goto errhandler_io;
+   }
    ret = fclose ( zStream );
    if (ret == EOF) goto errhandler_io;
 
@@@@ -1134,16 +1145,26 @@@@
    uTimBuf.actime = fileMetaInfo.st_atime;
    uTimBuf.modtime = fileMetaInfo.st_mtime;
 
-   retVal = chmod ( dstName, fileMetaInfo.st_mode );
-   ERROR_IF_NOT_ZERO ( retVal );
-
    retVal = utime ( dstName, &uTimBuf );
    ERROR_IF_NOT_ZERO ( retVal );
+#  endif
+}
+
+static
+int applySavedFileAttrToOutputFile ( int fd )
+{
+#  if BZ_UNIX
+   IntNative      retVal;
+
+   retVal = fchmod ( fd, fileMetaInfo.st_mode );
+   if (retVal != 0)
+       return retVal;
 
-   retVal = chown ( dstName, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
+   (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
    /* chown() will in many cases return with EPERM, which can
       be safely ignored.
    */
+   return 0;
 #  endif
 }
 
Index: bzip2recover.c
diff -Nau bzip2recover.c.orig bzip2recover.c
--- bzip2recover.c.orig	2005-06-06 19:56:47 +0200
+++ bzip2recover.c	2005-06-06 19:57:18 +0200
@@@@ -56,6 +56,8 @@@@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 
 /* This program records bit locations in the file to be recovered.
@@@@ -301,6 +303,19 @@@@
        name[n-1] == '2');
 }
 
+/*---------------------------------------------*/
+/* Open an output file safely with O_EXCL and good permissions */
+FILE* fopen_output( Char* name, const char* mode )
+{
+  FILE *fp;
+  int   fh;
+   
+  fh = open(name, O_WRONLY|O_CREAT|O_EXCL, 0600);
+  if (fh == -1) return NULL;
+  fp = fdopen(fh, mode);
+  if (fp == NULL) close(fh);
+  return fp;
+}
 
 /*---------------------------------------------------*/
 /*---                                             ---*/
@@@@ -518,7 +533,7 @@@@
          fprintf ( stderr, "   writing block %d to `%s' ...\n",
                            wrBlock+1, outFileName );
 
-         outFile = fopen ( outFileName, "wb" );
+         outFile = fopen_output ( outFileName, "wb" );
          if (outFile == NULL) {
             fprintf ( stderr, "%s: can't write `%s'\n",
                       progName, outFileName );


OpenPKG-SA-2005.008 and CAN-2005-1260,
Infinite loop in decompression of specially crafted bzip2 archives.
Parts of following patch taken from Ubuntu (backport from bzip2 1.0.3):
  http://security.ubuntu.com/ubuntu/pool/main/b/bzip2/bzip2_1.0.2-2ubuntu0.1.diff.gz

Index: bzlib.c
diff -Nau bzlib.c.orig bzlib.c
--- bzlib.c.orig	2005-06-06 19:56:47 +0200
+++ bzlib.c	2005-06-06 20:04:37 +0200
@@@@ -574,8 +574,11 @@@@
 
 
 /*---------------------------------------------------*/
+/* Return  True if data corruption is discovered.
+   Returns False if there is no problem.
+*/
 static
-void unRLE_obuf_to_output_FAST ( DState* s )
+Bool unRLE_obuf_to_output_FAST ( DState* s )
 {
    UChar k1;
 
@@@@ -584,7 +587,7 @@@@
       while (True) {
          /* try to finish existing run */
          while (True) {
-            if (s->strm->avail_out == 0) return;
+            if (s->strm->avail_out == 0) return False;
             if (s->state_out_len == 0) break;
             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
@@@@ -596,8 +599,11 @@@@
          }
    
          /* can a new run be started? */
-         if (s->nblock_used == s->save_nblock+1) return;
+         if (s->nblock_used == s->save_nblock+1) return False;
                
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
    
          s->state_out_len = 1;
          s->state_out_ch = s->k0;
@@@@ -667,6 +673,10 @@@@
                cs_avail_out--;
             }
          }   
+         /* Only caused by corrupt data stream? */
+         if (c_nblock_used > s_save_nblockPP)
+            return True;
+
          /* can a new run be started? */
          if (c_nblock_used == s_save_nblockPP) {
             c_state_out_len = 0; goto return_notr;
@@@@ -712,6 +722,7 @@@@
       s->strm->avail_out    = cs_avail_out;
       /* end save */
    }
+   return False;
 }
 
 
@@@@ -732,8 +743,11 @@@@
 
 
 /*---------------------------------------------------*/
+/* Return  True if data corruption is discovered.
+   Returns False if there is no problem.
+*/
 static
-void unRLE_obuf_to_output_SMALL ( DState* s )
+Bool unRLE_obuf_to_output_SMALL ( DState* s )
 {
    UChar k1;
 
@@@@ -742,7 +756,7 @@@@
       while (True) {
          /* try to finish existing run */
          while (True) {
-            if (s->strm->avail_out == 0) return;
+            if (s->strm->avail_out == 0) return False;
             if (s->state_out_len == 0) break;
             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
@@@@ -754,8 +768,11 @@@@
          }
    
          /* can a new run be started? */
-         if (s->nblock_used == s->save_nblock+1) return;
-               
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
    
          s->state_out_len = 1;
          s->state_out_ch = s->k0;
@@@@ -788,7 +805,7 @@@@
       while (True) {
          /* try to finish existing run */
          while (True) {
-            if (s->strm->avail_out == 0) return;
+            if (s->strm->avail_out == 0) return False;
             if (s->state_out_len == 0) break;
             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
@@@@ -800,7 +817,11 @@@@
          }
    
          /* can a new run be started? */
-         if (s->nblock_used == s->save_nblock+1) return;
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
    
          s->state_out_len = 1;
          s->state_out_ch = s->k0;
@@@@ -830,6 +851,7 @@@@
 /*---------------------------------------------------*/
 int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
 {
+   Bool corrupt;
    DState* s;
    if (strm == NULL) return BZ_PARAM_ERROR;
    s = strm->state;
@@@@ -840,12 +862,13 @@@@
       if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
       if (s->state == BZ_X_OUTPUT) {
          if (s->smallDecompress)
-            unRLE_obuf_to_output_SMALL ( s ); else
-            unRLE_obuf_to_output_FAST  ( s );
+            corrupt = unRLE_obuf_to_output_SMALL ( s ); else
+            corrupt = unRLE_obuf_to_output_FAST  ( s );
+         if (corrupt) return BZ_DATA_ERROR;
          if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
             BZ_FINALISE_CRC ( s->calculatedBlockCRC );
             if (s->verbosity >= 3) 
-               VPrintf2 ( " {0x%x, 0x%x}", s->storedBlockCRC, 
+               VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, 
                           s->calculatedBlockCRC );
             if (s->verbosity >= 2) VPrintf0 ( "]" );
             if (s->calculatedBlockCRC != s->storedBlockCRC)
@@@@ -863,7 +886,7 @@@@
          Int32 r = BZ2_decompress ( s );
          if (r == BZ_STREAM_END) {
             if (s->verbosity >= 3)
-               VPrintf2 ( "\n    combined CRCs: stored = 0x%x, computed = 0x%x", 
+               VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x", 
                           s->storedCombinedCRC, s->calculatedCombinedCRC );
             if (s->calculatedCombinedCRC != s->storedCombinedCRC)
                return BZ_DATA_ERROR;
Index: compress.c
diff -Nau compress.c.orig compress.c
--- compress.c.orig	2005-06-06 19:56:47 +0200
+++ compress.c	2005-06-06 20:00:50 +0200
@@@@ -488,9 +488,11 @@@@
       /*--
         Recompute the tables based on the accumulated frequencies.
       --*/
+      /* maxLen was changed from 20 to 17 in bzip2-1.0.3.  See 
+         comment in huffman.c for details. */
       for (t = 0; t < nGroups; t++)
          BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), 
-                                 alphaSize, 20 );
+                                 alphaSize, 17 /*20*/ );
    }
 
 
@@@@ -527,7 +529,7 @@@@
          if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
          if (s->len[t][i] < minLen) minLen = s->len[t][i];
       }
-      AssertH ( !(maxLen > 20), 3004 );
+      AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
       AssertH ( !(minLen < 1),  3005 );
       BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), 
                           minLen, maxLen, alphaSize );
@@@@ -651,8 +653,8 @@@@
       if (s->blockNo > 1) s->numZ = 0;
 
       if (s->verbosity >= 2)
-         VPrintf4( "    block %d: crc = 0x%8x, "
-                   "combined CRC = 0x%8x, size = %d\n",
+         VPrintf4( "    block %d: crc = 0x%08x, "
+                   "combined CRC = 0x%08x, size = %d\n",
                    s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
 
       BZ2_blockSort ( s );
@@@@ -703,7 +705,7 @@@@
       bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
       bsPutUInt32 ( s, s->combinedCRC );
       if (s->verbosity >= 2)
-         VPrintf1( "    final combined CRC = 0x%x\n   ", s->combinedCRC );
+         VPrintf1( "    final combined CRC = 0x%08x\n   ", s->combinedCRC );
       bsFinishWrite ( s );
    }
 }
Index: decompress.c
diff -Nau decompress.c.orig decompress.c
--- decompress.c.orig	2005-06-06 19:56:47 +0200
+++ decompress.c	2005-06-06 20:00:50 +0200
@@@@ -524,17 +524,23 @@@@
       if (s->origPtr < 0 || s->origPtr >= nblock)
          RETURN(BZ_DATA_ERROR);
 
+      /*-- Set up cftab to facilitate generation of T^(-1) --*/
+      s->cftab[0] = 0;
+      for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
+      for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
+      for (i = 0; i <= 256; i++) {
+         if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
+            /* s->cftab[i] can legitimately be == nblock */
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+
       s->state_out_len = 0;
       s->state_out_ch  = 0;
       BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
       s->state = BZ_X_OUTPUT;
       if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
 
-      /*-- Set up cftab to facilitate generation of T^(-1) --*/
-      s->cftab[0] = 0;
-      for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
-      for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
-
       if (s->smallDecompress) {
 
          /*-- Make a copy of cftab, used in generation of T --*/
Index: huffman.c
diff -Nau huffman.c.orig huffman.c
--- huffman.c.orig	2005-06-06 19:56:47 +0200
+++ huffman.c	2005-06-06 20:00:50 +0200
@@@@ -162,7 +162,24 @@@@
       
       if (! tooLong) break;
 
-      for (i = 1; i < alphaSize; i++) {
+      /* 17 Oct 04: keep-going condition for the following loop used
+         to be 'i < alphaSize', which missed the last element,
+         theoretically leading to the possibility of the compressor
+         looping.  However, this count-scaling step is only needed if
+         one of the generated Huffman code words is longer than
+         maxLen, which up to and including version 1.0.2 was 20 bits,
+         which is extremely unlikely.  In version 1.0.3 maxLen was
+         changed to 17 bits, which has minimal effect on compression
+         ratio, but does mean this scaling step is used from time to
+         time, enough to verify that it works.
+
+         This means that bzip2-1.0.3 and later will only produce
+         Huffman codes with a maximum length of 17 bits.  However, in
+         order to preserve backwards compatibility with bitstreams
+         produced by versions pre-1.0.3, the decompressor must still
+         handle lengths of up to 20. */
+
+      for (i = 1; i <= alphaSize; i++) {
          j = weight[i] >> 8;
          j = 1 + (j / 2);
          weight[i] = j << 8;
@

