Menu

#240 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 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/7za e -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 -so -y /testcase
==1== 

ERRORS:
Headers Error

mmmERROR: Data Error : testcase~
ERROR: Data Error : testcase~
ERROR: Data Error : 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**) (Main.cpp:923)
==1==    by 0x1F141A: main (MainAr.cpp:66)
==1==  Address 0x0 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 0x0
==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**) (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: 4,205,541 bytes in 318 blocks
==1==   total heap usage: 1,212 allocs, 894 frees, 5,689,428 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: 4,205,541 bytes in 318 blocks
==1==                       of which reachable via heuristic:
==1==                         newarray           : 1,296 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: 1 errors from 1 contexts (suppressed: 0 from 0)

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