Skip to content

p7zip data corruption bug when extracting ZIP archives #60071

@nhz2

Description

@nhz2

XRef: p7zip-project/p7zip#112 (comment)

This bug causes p7zip to use uninitialized memory when constructing paths when extracting ZIP archives.

This bug is in the non-Windows versions of p7zip_jll v17.4 to v17.6 and is fixed in v17.7 #60025.

The bug was introduced in the p7zip fork in p7zip-project/p7zip@c104127

Julia versions affected:

  • 1.6.7
  • 1.8
  • 1.9
  • 1.10
  • 1.11
  • 1.12

The bug only affects extracting ZIP archives with specific characteristics.

Since Pkg.jl does not extract ZIP archives, it is not affected.

Here is a function to test if a file could trigger the bug.

using ZipArchives
function is_affected(path)
    r = ZipReader(read(path))
    for i in 1:zip_nentries(r)
        isUTF8 = !iszero(zip_general_purpose_bit_flag(r, i) & 1<<11)
        os = zip_version_made_by(r, i)>>8
        if !isUTF8 && (os == 0x00 || os == 0x0b)
            return true
        end
    end
end

foo.zip

Valgrind output for a debug build of `7za` with example file `foo.zip`

valgrind --tool=memcheck --track-origins=yes ./bin/7za x -ob2 foo.zip

==76618== Memcheck, a memory error detector
==76618== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==76618== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==76618== Command: ./bin/7za x -ob2 foo.zip
==76618== 

7-Zip (a) [64] 17.05 : Copyright (c) 1999-2021 Igor Pavlov : 2017-08-28
p7zip Version 17.05 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,16 CPUs Intel(R) Core(TM) i7-4910MQ CPU @ 2.90GHz (306C3),ASM,AES-NI)

Scanning the drive for archives:
1 file, 136 bytes (1 KiB)

Extracting archive: foo.zip
--
Path = foo.zip
Type = zip
Physical Size = 136

  0%==76618== Conditional jump or move depends on uninitialised value(s)
==76618==    at 0x554510: Utf8_To_Utf16(wchar_t*, unsigned long*, char const*, char const*) (UTFConvert.cpp:94)
==76618==    by 0x554B12: ConvertUTF8ToUnicode(AString const&, UString&) (UTFConvert.cpp:276)
==76618==    by 0x4B6A4E: NArchive::NZip::CItem::GetUnicodeString(UString&, AString const&, bool, bool, unsigned int) const (ZipItem.cpp:433)
==76618==    by 0x4A4BF5: NArchive::NZip::CHandler::GetProperty(unsigned int, unsigned int, tagPROPVARIANT*) (ZipHandler.cpp:337)
==76618==    by 0x52377A: CArc::GetItemPath(unsigned int, UString&) const (OpenArchive.cpp:710)
==76618==    by 0x523A18: CArc::GetItemPath2(unsigned int, UString&) const (OpenArchive.cpp:747)
==76618==    by 0x523C22: CArc::GetItem(unsigned int, CReadArcItem&) const (OpenArchive.cpp:799)
==76618==    by 0x509938: CArchiveExtractCallback::GetStream(unsigned int, ISequentialOutStream**, int) (ArchiveExtractCallback.cpp:647)
==76618==    by 0x4A7AE7: NArchive::NZip::CHandler::Extract(unsigned int const*, unsigned int, int, IArchiveExtractCallback*) (ZipHandler.cpp:1299)
==76618==    by 0x51CA2A: DecompressArchive(CCodecs*, CArchiveLink const&, unsigned long long, NWildcard::CCensorNode const&, CExtractOptions const&, bool, IExtractCallbackUI*, CArchiveExtractCallback*, UString&, unsigned long long&) (Extract.cpp:208)
==76618==    by 0x51D60E: Extract(CCodecs*, CObjectVector<COpenType> const&, CRecordVector<int> const&, CObjectVector<UString>&, CObjectVector<UString>&, NWildcard::CCensorNode const&, CExtractOptions const&, IOpenCallbackUI*, IExtractCallbackUI*, IHashCalc*, UString&, CDecompressStat&) (Extract.cpp:445)
==76618==    by 0x5464A5: Main2(int, char**) (Main.cpp:924)
==76618==  Uninitialised value was created by a heap allocation
==76618==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==76618==    by 0x54EFBA: AString::ReAlloc2(unsigned int) (MyString.cpp:376)
==76618==    by 0x4B6BAB: AString::GetBuf_SetEnd(unsigned int) (MyString.h:269)
==76618==    by 0x4B69D2: NArchive::NZip::CItem::GetUnicodeString(UString&, AString const&, bool, bool, unsigned int) const (ZipItem.cpp:426)
==76618==    by 0x4A4BF5: NArchive::NZip::CHandler::GetProperty(unsigned int, unsigned int, tagPROPVARIANT*) (ZipHandler.cpp:337)
==76618==    by 0x52377A: CArc::GetItemPath(unsigned int, UString&) const (OpenArchive.cpp:710)
==76618==    by 0x523A18: CArc::GetItemPath2(unsigned int, UString&) const (OpenArchive.cpp:747)
==76618==    by 0x523C22: CArc::GetItem(unsigned int, CReadArcItem&) const (OpenArchive.cpp:799)
==76618==    by 0x509938: CArchiveExtractCallback::GetStream(unsigned int, ISequentialOutStream**, int) (ArchiveExtractCallback.cpp:647)
==76618==    by 0x4A7AE7: NArchive::NZip::CHandler::Extract(unsigned int const*, unsigned int, int, IArchiveExtractCallback*) (ZipHandler.cpp:1299)
==76618==    by 0x51CA2A: DecompressArchive(CCodecs*, CArchiveLink const&, unsigned long long, NWildcard::CCensorNode const&, CExtractOptions const&, bool, IExtractCallbackUI*, CArchiveExtractCallback*, UString&, unsigned long long&) (Extract.cpp:208)
==76618==    by 0x51D60E: Extract(CCodecs*, CObjectVector<COpenType> const&, CRecordVector<int> const&, CObjectVector<UString>&, CObjectVector<UString>&, NWildcard::CCensorNode const&, CExtractOptions const&, IOpenCallbackUI*, IExtractCallbackUI*, IHashCalc*, UString&, CDecompressStat&) (Extract.cpp:445)
==76618== 
==76618== Conditional jump or move depends on uninitialised value(s)
==76618==    at 0x554510: Utf8_To_Utf16(wchar_t*, unsigned long*, char const*, char const*) (UTFConvert.cpp:94)
==76618==    by 0x554B69: ConvertUTF8ToUnicode(AString const&, UString&) (UTFConvert.cpp:277)
==76618==    by 0x4B6A4E: NArchive::NZip::CItem::GetUnicodeString(UString&, AString const&, bool, bool, unsigned int) const (ZipItem.cpp:433)
==76618==    by 0x4A4BF5: NArchive::NZip::CHandler::GetProperty(unsigned int, unsigned int, tagPROPVARIANT*) (ZipHandler.cpp:337)
==76618==    by 0x52377A: CArc::GetItemPath(unsigned int, UString&) const (OpenArchive.cpp:710)
==76618==    by 0x523A18: CArc::GetItemPath2(unsigned int, UString&) const (OpenArchive.cpp:747)
==76618==    by 0x523C22: CArc::GetItem(unsigned int, CReadArcItem&) const (OpenArchive.cpp:799)
==76618==    by 0x509938: CArchiveExtractCallback::GetStream(unsigned int, ISequentialOutStream**, int) (ArchiveExtractCallback.cpp:647)
==76618==    by 0x4A7AE7: NArchive::NZip::CHandler::Extract(unsigned int const*, unsigned int, int, IArchiveExtractCallback*) (ZipHandler.cpp:1299)
==76618==    by 0x51CA2A: DecompressArchive(CCodecs*, CArchiveLink const&, unsigned long long, NWildcard::CCensorNode const&, CExtractOptions const&, bool, IExtractCallbackUI*, CArchiveExtractCallback*, UString&, unsigned long long&) (Extract.cpp:208)
==76618==    by 0x51D60E: Extract(CCodecs*, CObjectVector<COpenType> const&, CRecordVector<int> const&, CObjectVector<UString>&, CObjectVector<UString>&, NWildcard::CCensorNode const&, CExtractOptions const&, IOpenCallbackUI*, IExtractCallbackUI*, IHashCalc*, UString&, CDecompressStat&) (Extract.cpp:445)
==76618==    by 0x5464A5: Main2(int, char**) (Main.cpp:924)
==76618==  Uninitialised value was created by a heap allocation
==76618==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==76618==    by 0x54EFBA: AString::ReAlloc2(unsigned int) (MyString.cpp:376)
==76618==    by 0x4B6BAB: AString::GetBuf_SetEnd(unsigned int) (MyString.h:269)
==76618==    by 0x4B69D2: NArchive::NZip::CItem::GetUnicodeString(UString&, AString const&, bool, bool, unsigned int) const (ZipItem.cpp:426)
==76618==    by 0x4A4BF5: NArchive::NZip::CHandler::GetProperty(unsigned int, unsigned int, tagPROPVARIANT*) (ZipHandler.cpp:337)
==76618==    by 0x52377A: CArc::GetItemPath(unsigned int, UString&) const (OpenArchive.cpp:710)
==76618==    by 0x523A18: CArc::GetItemPath2(unsigned int, UString&) const (OpenArchive.cpp:747)
==76618==    by 0x523C22: CArc::GetItem(unsigned int, CReadArcItem&) const (OpenArchive.cpp:799)
==76618==    by 0x509938: CArchiveExtractCallback::GetStream(unsigned int, ISequentialOutStream**, int) (ArchiveExtractCallback.cpp:647)
==76618==    by 0x4A7AE7: NArchive::NZip::CHandler::Extract(unsigned int const*, unsigned int, int, IArchiveExtractCallback*) (ZipHandler.cpp:1299)
==76618==    by 0x51CA2A: DecompressArchive(CCodecs*, CArchiveLink const&, unsigned long long, NWildcard::CCensorNode const&, CExtractOptions const&, bool, IExtractCallbackUI*, CArchiveExtractCallback*, UString&, unsigned long long&) (Extract.cpp:208)
==76618==    by 0x51D60E: Extract(CCodecs*, CObjectVector<COpenType> const&, CRecordVector<int> const&, CObjectVector<UString>&, CObjectVector<UString>&, NWildcard::CCensorNode const&, CExtractOptions const&, IOpenCallbackUI*, IExtractCallbackUI*, IHashCalc*, UString&, CDecompressStat&) (Extract.cpp:445)
==76618== 
==76618== Conditional jump or move depends on uninitialised value(s)
==76618==    at 0x489CB0: NArchive::NItemName::ReplaceToOsSlashes_Remove_TailSlash(UString&) (ItemNameUtils.cpp:55)
==76618==    by 0x4A4C01: NArchive::NZip::CHandler::GetProperty(unsigned int, unsigned int, tagPROPVARIANT*) (ZipHandler.cpp:338)
==76618==    by 0x52377A: CArc::GetItemPath(unsigned int, UString&) const (OpenArchive.cpp:710)
==76618==    by 0x523A18: CArc::GetItemPath2(unsigned int, UString&) const (OpenArchive.cpp:747)
==76618==    by 0x523C22: CArc::GetItem(unsigned int, CReadArcItem&) const (OpenArchive.cpp:799)
==76618==    by 0x509938: CArchiveExtractCallback::GetStream(unsigned int, ISequentialOutStream**, int) (ArchiveExtractCallback.cpp:647)
==76618==    by 0x4A7AE7: NArchive::NZip::CHandler::Extract(unsigned int const*, unsigned int, int, IArchiveExtractCallback*) (ZipHandler.cpp:1299)
==76618==    by 0x51CA2A: DecompressArchive(CCodecs*, CArchiveLink const&, unsigned long long, NWildcard::CCensorNode const&, CExtractOptions const&, bool, IExtractCallbackUI*, CArchiveExtractCallback*, UString&, unsigned long long&) (Extract.cpp:208)
==76618==    by 0x51D60E: Extract(CCodecs*, CObjectVector<COpenType> const&, CRecordVector<int> const&, CObjectVector<UString>&, CObjectVector<UString>&, NWildcard::CCensorNode const&, CExtractOptions const&, IOpenCallbackUI*, IExtractCallbackUI*, IHashCalc*, UString&, CDecompressStat&) (Extract.cpp:445)
==76618==    by 0x5464A5: Main2(int, char**) (Main.cpp:924)
==76618==    by 0x5493F4: main (MainAr.cpp:66)
==76618==  Uninitialised value was created by a heap allocation
==76618==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==76618==    by 0x54EFBA: AString::ReAlloc2(unsigned int) (MyString.cpp:376)
==76618==    by 0x4B6BAB: AString::GetBuf_SetEnd(unsigned int) (MyString.h:269)
==76618==    by 0x4B69D2: NArchive::NZip::CItem::GetUnicodeString(UString&, AString const&, bool, bool, unsigned int) const (ZipItem.cpp:426)
==76618==    by 0x4A4BF5: NArchive::NZip::CHandler::GetProperty(unsigned int, unsigned int, tagPROPVARIANT*) (ZipHandler.cpp:337)
==76618==    by 0x52377A: CArc::GetItemPath(unsigned int, UString&) const (OpenArchive.cpp:710)
==76618==    by 0x523A18: CArc::GetItemPath2(unsigned int, UString&) const (OpenArchive.cpp:747)
==76618==    by 0x523C22: CArc::GetItem(unsigned int, CReadArcItem&) const (OpenArchive.cpp:799)
==76618==    by 0x509938: CArchiveExtractCallback::GetStream(unsigned int, ISequentialOutStream**, int) (ArchiveExtractCallback.cpp:647)
==76618==    by 0x4A7AE7: NArchive::NZip::CHandler::Extract(unsigned int const*, unsigned int, int, IArchiveExtractCallback*) (ZipHandler.cpp:1299)
==76618==    by 0x51CA2A: DecompressArchive(CCodecs*, CArchiveLink const&, unsigned long long, NWildcard::CCensorNode const&, CExtractOptions const&, bool, IExtractCallbackUI*, CArchiveExtractCallback*, UString&, unsigned long long&) (Extract.cpp:208)
==76618==    by 0x51D60E: Extract(CCodecs*, CObjectVector<COpenType> const&, CRecordVector<int> const&, CObjectVector<UString>&, CObjectVector<UString>&, NWildcard::CCensorNode const&, CExtractOptions const&, IOpenCallbackUI*, IExtractCallbackUI*, IHashCalc*, UString&, CDecompressStat&) (Extract.cpp:445)
==76618== 
==76618== Conditional jump or move depends on uninitialised value(s)
==76618==    at 0x554E67: SplitPathToParts(UString const&, CObjectVector<UString>&) (Wildcard.cpp:88)
==76618==    by 0x52411C: CArc::GetItem(unsigned int, CReadArcItem&) const (OpenArchive.cpp:902)
==76618==    by 0x509938: CArchiveExtractCallback::GetStream(unsigned int, ISequentialOutStream**, int) (ArchiveExtractCallback.cpp:647)
==76618==    by 0x4A7AE7: NArchive::NZip::CHandler::Extract(unsigned int const*, unsigned int, int, IArchiveExtractCallback*) (ZipHandler.cpp:1299)
==76618==    by 0x51CA2A: DecompressArchive(CCodecs*, CArchiveLink const&, unsigned long long, NWildcard::CCensorNode const&, CExtractOptions const&, bool, IExtractCallbackUI*, CArchiveExtractCallback*, UString&, unsigned long long&) (Extract.cpp:208)
==76618==    by 0x51D60E: Extract(CCodecs*, CObjectVector<COpenType> const&, CRecordVector<int> const&, CObjectVector<UString>&, CObjectVector<UString>&, NWildcard::CCensorNode const&, CExtractOptions const&, IOpenCallbackUI*, IExtractCallbackUI*, IHashCalc*, UString&, CDecompressStat&) (Extract.cpp:445)
==76618==    by 0x5464A5: Main2(int, char**) (Main.cpp:924)
==76618==    by 0x5493F4: main (MainAr.cpp:66)
==76618==  Uninitialised value was created by a heap allocation
==76618==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==76618==    by 0x54EFBA: AString::ReAlloc2(unsigned int) (MyString.cpp:376)
==76618==    by 0x4B6BAB: AString::GetBuf_SetEnd(unsigned int) (MyString.h:269)
==76618==    by 0x4B69D2: NArchive::NZip::CItem::GetUnicodeString(UString&, AString const&, bool, bool, unsigned int) const (ZipItem.cpp:426)
==76618==    by 0x4A4BF5: NArchive::NZip::CHandler::GetProperty(unsigned int, unsigned int, tagPROPVARIANT*) (ZipHandler.cpp:337)
==76618==    by 0x52377A: CArc::GetItemPath(unsigned int, UString&) const (OpenArchive.cpp:710)
==76618==    by 0x523A18: CArc::GetItemPath2(unsigned int, UString&) const (OpenArchive.cpp:747)
==76618==    by 0x523C22: CArc::GetItem(unsigned int, CReadArcItem&) const (OpenArchive.cpp:799)
==76618==    by 0x509938: CArchiveExtractCallback::GetStream(unsigned int, ISequentialOutStream**, int) (ArchiveExtractCallback.cpp:647)
==76618==    by 0x4A7AE7: NArchive::NZip::CHandler::Extract(unsigned int const*, unsigned int, int, IArchiveExtractCallback*) (ZipHandler.cpp:1299)
==76618==    by 0x51CA2A: DecompressArchive(CCodecs*, CArchiveLink const&, unsigned long long, NWildcard::CCensorNode const&, CExtractOptions const&, bool, IExtractCallbackUI*, CArchiveExtractCallback*, UString&, unsigned long long&) (Extract.cpp:208)
==76618==    by 0x51D60E: Extract(CCodecs*, CObjectVector<COpenType> const&, CRecordVector<int> const&, CObjectVector<UString>&, CObjectVector<UString>&, NWildcard::CCensorNode const&, CExtractOptions const&, IOpenCallbackUI*, IExtractCallbackUI*, IHashCalc*, UString&, CDecompressStat&) (Extract.cpp:445)
==76618== 
Everything is Ok

Size:       0
Compressed: 136
==76618== 
==76618== HEAP SUMMARY:
==76618==     in use at exit: 0 bytes in 0 blocks
==76618==   total heap usage: 1,493 allocs, 1,493 frees, 523,088 bytes allocated
==76618== 
==76618== All heap blocks were freed -- no leaks are possible
==76618== 
==76618== For lists of detected and suppressed errors, rerun with: -s
==76618== ERROR SUMMARY: 82 errors from 4 contexts (suppressed: 0 from 0)

CC: @fxcoudert

Metadata

Metadata

Assignees

No one assigned

    Labels

    JLLsbugIndicates an unexpected problem or unintended behaviorupstreamThe issue is with an upstream dependency, e.g. LLVM

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions