aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2013-02-27 16:39:56 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2013-02-27 16:39:56 +0100
commitc3045edec221876596fe910901191720d8f55986 (patch)
tree9fb80f2e681f44a070db742ba0b3131de6556508
parenta1ae2b75a71b4b99948aa0f9a15cf1de52bb40d6 (diff)
downloadbusybox-w32-c3045edec221876596fe910901191720d8f55986.tar.gz
busybox-w32-c3045edec221876596fe910901191720d8f55986.tar.bz2
busybox-w32-c3045edec221876596fe910901191720d8f55986.zip
xz: fix incorrect XZ_BUF_ERROR
xz_dec_run() could incorrectly return XZ_BUF_ERROR if all of the following was true: - The caller knows how many bytes of output to expect and only provides that much output space. - When the last output bytes are decoded, the caller-provided input buffer ends right before the LZMA2 end of payload marker. So LZMA2 won't provide more output anymore, but it won't know it yet and thus won't return XZ_STREAM_END yet. - A BCJ filter is in use and it hasn't left any unfiltered bytes in the temp buffer. This can happen with any BCJ filter, but in practice it's more likely with filters other than the x86 BCJ. This fixes <https://bugzilla.redhat.com/show_bug.cgi?id=735408> where Squashfs thinks that a valid file system is corrupt. Thanks to Jindrich Novy for telling me that such a bug report exists, Phillip Lougher for providing excellent debug info, and other people on #fedora-ppc. This also fixes a similar bug in single-call mode where the uncompressed size of a XZ Block using BCJ + LZMA2 was 0 bytes and caller provided no output space. Many empty .xz files don't contain any Blocks and thus don't trigger this bug. This also tweaks a closely related detail: xz_dec_bcj_run() could call xz_dec_lzma2_run() to decode into temp buffer when it was known to be useless. This was harmless although it wasted a minuscule number of CPU cycles. Signed-off-by: Lasse Collin <lasse.collin@tukaani.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--archival/libarchive/unxz/xz_dec_bcj.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/archival/libarchive/unxz/xz_dec_bcj.c b/archival/libarchive/unxz/xz_dec_bcj.c
index a01a4cdcf..e0f913a94 100644
--- a/archival/libarchive/unxz/xz_dec_bcj.c
+++ b/archival/libarchive/unxz/xz_dec_bcj.c
@@ -446,8 +446,12 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
446 * next filter in the chain. Apply the BCJ filter on the new data 446 * next filter in the chain. Apply the BCJ filter on the new data
447 * in the output buffer. If everything cannot be filtered, copy it 447 * in the output buffer. If everything cannot be filtered, copy it
448 * to temp and rewind the output buffer position accordingly. 448 * to temp and rewind the output buffer position accordingly.
449 *
450 * This needs to be always run when temp.size == 0 to handle a special
451 * case where the output buffer is full and the next filter has no
452 * more output coming but hasn't returned XZ_STREAM_END yet.
449 */ 453 */
450 if (s->temp.size < b->out_size - b->out_pos) { 454 if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
451 out_start = b->out_pos; 455 out_start = b->out_pos;
452 memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); 456 memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
453 b->out_pos += s->temp.size; 457 b->out_pos += s->temp.size;
@@ -470,16 +474,25 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
470 s->temp.size = b->out_pos - out_start; 474 s->temp.size = b->out_pos - out_start;
471 b->out_pos -= s->temp.size; 475 b->out_pos -= s->temp.size;
472 memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); 476 memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
477
478 /*
479 * If there wasn't enough input to the next filter to fill
480 * the output buffer with unfiltered data, there's no point
481 * to try decoding more data to temp.
482 */
483 if (b->out_pos + s->temp.size < b->out_size)
484 return XZ_OK;
473 } 485 }
474 486
475 /* 487 /*
476 * If we have unfiltered data in temp, try to fill by decoding more 488 * We have unfiltered data in temp. If the output buffer isn't full
477 * data from the next filter. Apply the BCJ filter on temp. Then we 489 * yet, try to fill the temp buffer by decoding more data from the
478 * hopefully can fill the actual output buffer by copying filtered 490 * next filter. Apply the BCJ filter on temp. Then we hopefully can
479 * data from temp. A mix of filtered and unfiltered data may be left 491 * fill the actual output buffer by copying filtered data from temp.
480 * in temp; it will be taken care on the next call to this function. 492 * A mix of filtered and unfiltered data may be left in temp; it will
493 * be taken care on the next call to this function.
481 */ 494 */
482 if (s->temp.size > 0) { 495 if (b->out_pos < b->out_size) {
483 /* Make b->out{,_pos,_size} temporarily point to s->temp. */ 496 /* Make b->out{,_pos,_size} temporarily point to s->temp. */
484 s->out = b->out; 497 s->out = b->out;
485 s->out_pos = b->out_pos; 498 s->out_pos = b->out_pos;