Bug 1954559 (CVE-2021-3520)

Summary: CVE-2021-3520 lz4: memory corruption due to an integer overflow bug caused by memmove argument
Product: [Other] Security Response Reporter: Dhananjay Arunesh <darunesh>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED ERRATA QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: aileenc, avibelli, bgeorges, bibryam, chazlett, clement.escoffier, dandread, dkreling, drieden, ggaughan, gghezzo, gmalinko, gparvin, gsmet, hamadhan, hbraun, igor.raits, jamartis, janstey, jnethert, jochrist, jramanat, jross, jwakely, jweiser, jwon, kaycoth, krathod, larryellison2111, lthon, mszynkie, orlandoolivia106, pantinor, peholase, pgallagh, pjindal, pj.pandit, probinso, rruss, rsvoboda, sbiarozk, sdouglas, stcannon, swoodman, thee, travier, vmugicag, yann.collet.73
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: lz4 1.9.4 Doc Type: If docs needed, set a value
Doc Text:
There's a flaw in lz4. An attacker who submits a crafted file to an application linked with lz4 may be able to trigger an integer overflow, leading to calling of memmove() on a negative size argument, causing an out-of-bounds write and/or a crash. The greatest impact of this flaw is to availability, with some potential impact to confidentiality and integrity as well.
Story Points: ---
Clone Of: Environment:
Last Closed: 2021-06-29 16:41:14 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 1959427, 1959430, 1954560, 1957036, 1957037, 1957038, 1959428, 1959429, 1959431, 1959432, 1959433, 1959434, 1959435, 1959437, 1959438, 1959439, 1959440, 1959441, 1959442    
Bug Blocks: 1935389    

Description Dhananjay Arunesh 2021-04-28 11:36:37 UTC
A vulnerability was found in lz4, where a potential memory corruption due to an integer overflow bug which caused one of the memmove arguments to become negative. Depending on how the library was compiled this will hit an assert() inside the library and dump core, leaving a 4GB core file, or it wil go into libc and crash inside the memmove() function.

Reference:
https://github.com/lz4/lz4/pull/972

Comment 1 Dhananjay Arunesh 2021-04-28 11:38:13 UTC
Created lz4 tracking bugs for this issue:

Affects: fedora-all [bug 1954560]

Comment 3 Todd Cullum 2021-05-04 21:48:33 UTC
The lz4 binary itself catches the problem when it parses the header, but it seems not all library consumers do and therefore LZ4_decompress_generic() was patched.

Comment 5 Todd Cullum 2021-05-04 22:06:09 UTC
Statement:

This flaw is out of support scope for Red Hat Enterprise Linux 7. To learn more about Red Hat Enterprise Linux support life cycles, please see https://access.redhat.com/support/policy/updates/errata .

Comment 6 Todd Cullum 2021-05-04 22:40:26 UTC
Flaw summary:

In the LZ4_decompress_generic() routine, outputSize is retrieved from the lz4 file and is an integer. A code path allows outputSize to influence the value of `length` via `oend` in the call to memmove(op, ip, length). A crafted file can cause outputSize to be a negative value, and since length is interpreted by memmove() as a size_t, it can be an extremely large, out-of-bounds value. The upstream patch checks to ensure that outputSize is not less than 0 at the beginning of the routine.

Comment 11 errata-xmlrpc 2021-06-29 16:30:56 UTC
This issue has been addressed in the following products:

  Red Hat Enterprise Linux 8

Via RHSA-2021:2575 https://access.redhat.com/errata/RHSA-2021:2575

Comment 12 Product Security DevOps Team 2021-06-29 16:41:14 UTC
This bug is now closed. Further updates for individual products will be reflected on the CVE page(s):

https://access.redhat.com/security/cve/cve-2021-3520

Comment 13 errata-xmlrpc 2022-04-13 11:27:02 UTC
This issue has been addressed in the following products:

  Red Hat AMQ Streams 2.1.0

Via RHSA-2022:1345 https://access.redhat.com/errata/RHSA-2022:1345

Comment 16 errata-xmlrpc 2022-07-19 13:40:22 UTC
This issue has been addressed in the following products:

  RHINT Camel-Q 2.7

Via RHSA-2022:5606 https://access.redhat.com/errata/RHSA-2022:5606

Comment 17 errata-xmlrpc 2022-09-09 07:12:34 UTC
This issue has been addressed in the following products:

  RHAF Camel-K 1.8

Via RHSA-2022:6407 https://access.redhat.com/errata/RHSA-2022:6407

Comment 18 Yann Collet 2022-10-19 08:12:45 UTC
There are a nb of incorrect statements in this thread, and I want to provide a counterpoint for anyone willing to take the time to understand this topic.

Probably the most incorrect statement is contained in this assertion : 
"A crafted file can cause outputSize to be a negative value"

Absolutely not.

The #972 patch is completely unrelated to the payload ingested by the `LZ4_decompress*()` function, meaning there is no attack possible through a "crafted file" vector.

What https://github.com/lz4/lz4/pull/972 covers is an _incorrect usage of the interface_ , by extending the contract of this interface.

The incorrect usage is providing an incorrect parameter as output buffer size, aka a wrong buffer size.
Providing a wrong buffer size is considered UB territory, same class as providing a wrong pointer.
That being said, in #972 the contract has been extended to detect and return a specific case when the size parameter is so completely wrong that it is negative.
Note that this contract extension does not cover situations where the size is incorrect (too large) but still positive.

And neither should it try to.
All interface contracts have limits, and providing obviously bogus parameters should not be classified as a CVE for the called function.
It might be a CVE, but then for the _caller_ of the function.

It follows that any implementation that correctly invokes the LZ4 decoder interface was never at risk.

Other fixable statements seen in this thread : 
- "a potential memory corruption due to an integer overflow" : it's not an integer overflow, it's a careless cast to `int` on the _user side_ of the code base (before invoking LZ4_decompress*() function)
- "In the LZ4_decompress_generic() routine, outputSize is retrieved from the lz4 file" : LZ4_decompress*() never "retrieves" any size, it has no <stdio.h> dependency, it's unaware of the concept of file. What it does is receive an `outputSize` parameter. This parameter is controlled by the caller.

Not mentioned in the thread, but probably worth mentioning : 
In the initial issue, the issuer illustrates the issue with this example : "If the decompressed size is big enough, e.g. 0xff000000-0xffffffff".
The reference lz4 implementation publishes a _maximum block size_ as part of its interface, and is documented as not supporting single blocks larger than this maximum.
This maximum size is set at 0x7E000000 (https://github.com/lz4/lz4/blob/dev/lib/lz4.h#L212).
Hence, the examples are way out of range of the library contract.

PS : I'm not aware of, or don't know about, any process to "declassify" a CVE, so these comments are mostly provided for context.

Comment 19 khalaniaspyn2 2022-11-25 07:01:44 UTC Comment hidden (spam)
Comment 20 sonnylee 2023-05-16 08:04:14 UTC Comment hidden (spam)
Comment 21 paulahong 2023-05-17 01:29:48 UTC Comment hidden (spam)
Comment 22 SaintOtis12 2023-06-27 06:35:27 UTC Comment hidden (spam)
Comment 23 larryellison 2023-08-07 07:01:04 UTC Comment hidden (spam)
Comment 24 orlandoolivia106@gmail.com 2023-09-15 12:31:05 UTC Comment hidden (spam)