Menu

#237 Invalid read and SIGSEGV during processing of 7zip archive

v1.0 (example)
open
nobody
None
5
2022-05-24
2022-05-24
No

During extraction of the attached 7zip archive via

/p7zip_16.02/bin/7za e -so -y /testcase

an out-of-bounds read and a segmentation fault (SIGSEGV) is triggered. This possibly opens up other attack vectors to an attacker if files from untrusted sources are processed.

For reproduction of the crash, I attach a Docker image. Run ./build_upstream.sh to build the docker image and ./reproduce-upstream.sh to reproduce the crash.
If you need further details, please do not hesitate to ask.

Version
The input was tested on p7zip_16.02

Valgrind
[+] Running /p7zip_16.02/bin/7z e -pPASSWORD -so -y /testcase
==1== Memcheck, a memory error detector
==1== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==1== Command: /p7zip_16.02/bin/7za e -pPASSWORD -so -y /testcase
==1==
ERROR: Data Error in encrypted file. Wrong password? : testcase~
ERROR: Unsupported Method : testcase~
==1== Invalid read of size 8
==1== at 0x1601B1: NCoderMixer2::CMixerMT::GetCoder(unsigned int) (CoderMixer2.cpp:869)
==1== by 0x13D4FB: NArchive::N7z::CDecoder::Decode(IInStream, unsigned long long, NArchive::N7z::CFolders const&, unsigned int, unsigned long long const, ISequentialOutStream, ICompressProgressInfo, ISequentialInStream, ICryptoGetTextPassword, bool&, bool&, UString&, bool, unsigned int) (7zDecode.cpp:357)
==1== by 0x1426B1: NArchive::N7z::CHandler::Extract(unsigned int const
, unsigned int, int, IArchiveExtractCallback) (7zExtract.cpp:351)
==1== by 0x1C9E78: DecompressArchive (Extract.cpp:208)
==1== by 0x1C9E78: 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)
==1== by 0x1EDF43: Main2(int, char</ustring></ustring></int></copentype>
) (Main.cpp:923)
==1== by 0x1F141A: main (MainAr.cpp:66)
==1== Address 0x4f98fa8 is 0 bytes after a block of size 8 alloc'd
==1== at 0x483C583: operator new (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1== by 0x1610F5: ReserveOnePosition (MyVector.h:25)
==1== by 0x1610F5: Add (MyVector.h:201)
==1== by 0x1610F5: AddNew (MyVector.h:468)
==1== by 0x1610F5: NCoderMixer2::CMixerMT::AddCoder(CCreatedCoder const&) (CoderMixer2.cpp:860)
==1== by 0x13CC7D: NArchive::N7z::CDecoder::Decode(IInStream, unsigned long long, NArchive::N7z::CFolders const&, unsigned int, unsigned long long const, ISequentialOutStream, ICompressProgressInfo, ISequentialInStream, ICryptoGetTextPassword, bool&, bool&, UString&, bool, unsigned int) (7zDecode.cpp:327)
==1== by 0x1426B1: NArchive::N7z::CHandler::Extract(unsigned int const
, unsigned int, int, IArchiveExtractCallback) (7zExtract.cpp:351)
==1== by 0x1C9E78: DecompressArchive (Extract.cpp:208)
==1== by 0x1C9E78: 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)
==1== by 0x1EDF43: Main2(int, char</ustring></ustring></int></copentype>
) (Main.cpp:923)
==1== by 0x1F141A: main (MainAr.cpp:66)
==1==
==1== Invalid read of size 8
==1== at 0x13D032: operator ICompressCoder (MyCom.h:23)
==1== by 0x13D032: GetUnknown (CoderMixer2.h:210)
==1== by 0x13D032: NArchive::N7z::CDecoder::Decode(IInStream
, unsigned long long, NArchive::N7z::CFolders const&, unsigned int, unsigned long long const, ISequentialOutStream, ICompressProgressInfo, ISequentialInStream, ICryptoGetTextPassword, bool&, bool&, UString&, bool, unsigned int) (7zDecode.cpp:357)
==1== by 0x1426B1: NArchive::N7z::CHandler::Extract(unsigned int const, unsigned int, int, IArchiveExtractCallback) (7zExtract.cpp:351)
==1== by 0x1C9E78: DecompressArchive (Extract.cpp:208)
==1== by 0x1C9E78: Extract(CCodecs, CObjectVector<copentype> const&, CRecordVector<int> const&, CObjectVector<ustring>&, CObjectVector<ustring>&, NWildcard::CCensorNode const&, CExtractOptions const&, IOpenCallbackUI</ustring></ustring></int></copentype>, IExtractCallbackUI, IHashCalc, UString&, CDecompressStat&) (Extract.cpp:445)
==1== by 0x1EDF43: Main2(int, char) (Main.cpp:923)
==1== by 0x1F141A: main (MainAr.cpp:66)
==1== Address 0xf0 is not stack'd, malloc'd or (recently) free'd
==1==
==1==
==1== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==1== Access not within mapped region at address 0xF0
==1== at 0x13D032: operator ICompressCoder (MyCom.h:23)
==1== by 0x13D032: GetUnknown (CoderMixer2.h:210)
==1== by 0x13D032: NArchive::N7z::CDecoder::Decode(IInStream
, unsigned long long, NArchive::N7z::CFolders const&, unsigned int, unsigned long long const, ISequentialOutStream, ICompressProgressInfo*, ISequentialInStream
, ICryptoGetTextPassword, bool&, bool&, UString&, bool, unsigned int) (7zDecode.cpp:357)
==1== by 0x1426B1: NArchive::N7z::CHandler::Extract(unsigned int const
, unsigned int, int, IArchiveExtractCallback) (7zExtract.cpp:351)
==1== by 0x1C9E78: DecompressArchive (Extract.cpp:208)
==1== by 0x1C9E78: 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)
==1== by 0x1EDF43: Main2(int, char
*) (Main.cpp:923)
==1== by 0x1F141A: main (MainAr.cpp:66)
==1== If you believe this happened as a result of a stack
==1== overflow in your program's main thread (unlikely but
==1== possible), you can try to increase the size of the
==1== main thread stack using the --main-stacksize= flag.
==1== The main thread stack size used in this run was 8388608.
==1==
==1== HEAP SUMMARY:
==1== in use at exit: 13,047 bytes in 341 blocks
==1== total heap usage: 1,203 allocs, 862 frees, 18,680,497 bytes allocated
==1==
==1== LEAK SUMMARY:
==1== definitely lost: 0 bytes in 0 blocks
==1== indirectly lost: 0 bytes in 0 blocks
==1== possibly lost: 0 bytes in 0 blocks
==1== still reachable: 13,047 bytes in 341 blocks
==1== of which reachable via heuristic:
==1== newarray : 1,328 bytes in 2 blocks
==1== suppressed: 0 bytes in 0 blocks
==1== Rerun with --leak-check=full to see details of leaked memory
==1==
==1== For lists of detected and suppressed errors, rerun with: -s
==1== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)</ustring></ustring></int></copentype>

valgrind: the 'impossible' happened:
main(): signal was supposed to be fatal

host stacktrace:
==1== at 0x58046FFA: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux)
==1== by 0x58047127: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux)
==1== by 0x58047390: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux)
==1== by 0x580473C0: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux)
==1== by 0x580BA566: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux)
==1== by 0x580F6117: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux)

sched status:
running_tid=1

1 Attachments

Discussion


Log in to post a comment.

MongoDB Logo MongoDB