Bug 9491 - Infinite loop in unlzma
Summary: Infinite loop in unlzma
Status: RESOLVED FIXED
Alias: None
Product: Busybox
Classification: Unclassified
Component: Other (show other bugs)
Version: unspecified
Hardware: All Linux
: P5 normal
Target Milestone: ---
Assignee: unassigned
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-12-21 15:51 UTC by Aaron S. Kurland
Modified: 2017-01-09 13:02 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Aaron S. Kurland 2016-12-21 15:51:42 UTC
There are three "infinite loops" in unlzma:

https://git.busybox.net/busybox/tree/archival/libarchive/decompress_unlzma.c#n283
https://git.busybox.net/busybox/tree/archival/libarchive/decompress_unlzma.c#n341
https://git.busybox.net/busybox/tree/archival/libarchive/decompress_unlzma.c#n435

They're not *quite* infinite as pos will overflow at some point, but it seems that a while-loop was not the intent. Looking at the code this was based on:

https://dev.openwrt.org/browser/trunk/target/linux/lantiq/image/lzma-loader/src/LzmaDecode.c?rev=36438#L304

It appears the intent was for an if-conditional. This issue was found by the Coverity Scan static code analyzer.
Comment 1 Denys Vlasenko 2017-01-09 13:02:46 UTC
commit b5ee04c4142c1e4841d2a8a2badcec3128e18f57
Author: Denys Vlasenko <vda.linux@googlemail.com>
Date:   Mon Jan 9 13:55:11 2017 +0100

    unlzma: fix erroneous "while" instead of "if"

    These parts of the code essentially check whether
    stepping back by rep0 goes negative or not.

    LZMA SDK from lzma1604.7z has the following in the corresponding places:

    ... = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]

    Clearly, not loop here.

    Technically, "while" here works: if condition is false (because pos
    underflowed), it iterates once, adds header.dict_size (a.k.a. dicBufSize),
    this makes pos positive but smaller than header.dict_size, and loop exits.

    Now we'll just check for negative result of subtraction, which is less code:

    function                                             old     new   delta
    unpack_lzma_stream                                  2659    2641     -18

    (I hope 2 Gbyte+ dictionaries won't be in use soon).
...
...

                                uint32_t pos = buffer_pos - rep0;
-                               while (pos >= header.dict_size)
+                               pos = buffer_pos - rep0;
+                               if ((int32_t)pos < 0)
                                        pos += header.dict_size;