Hi team,
Quipper, a perf library used in this repro for Google's perf_data_converter, crashes with signs of memory corruption when parsing malformed perf .data files. Quick automated triage info below as you can check if the issue appears to be an exploitable vulnerability or just a crash as no further analysis was performed.
Quipper library code can be found here:
https://github.com/google/perf_data_converter/tree/master/src/quipper
Repro steps:
$ git clone https://github.com/google/perf_data_converter
(install deps and build)
$ ./perf_data_converter/bazel-bin/src/perf_to_profile -i repro.data -o test -f
repro.data (rename from repro.data.txt, had to add .txt to the extension for github issue file upload)
repro.data.txt
observe crash on console and within a debugger
Crash was found using litefuzz to mutate sample perf files. See below repro demonstration and debug output.
$ ./perf_data_converter/bazel-bin/src/perf_to_profile -i repro.data -o test -f
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
Debug output from gdb from initial crash triage below.
Note: this uses electric-fence malloc debugger, install with sudo apt-get install electric-fence to trigger the instrumented crash as you can see.
$ gdb -q perf_data_converter/bazel-bin/src/perf_to_profile
Reading symbols from perf_data_converter/bazel-bin/src/perf_to_profile...
(No debugging symbols found in perf_data_converter/bazel-bin/src/perf_to_profile)
(gdb) set environment LD_PRELOAD=/usr/lib/libefence.so
(gdb) r -i ~/repro.data -o /tmp/test.data -f
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff79489ab in mprotect () at ../sysdeps/unix/syscall-template.S:78
(gdb) bt
#0 0x00007ffff79489ab in mprotect () at ../sysdeps/unix/syscall-template.S:78
#1 0x00007ffff7dc623e in Page_AllowAccess () from /usr/lib/libefence.so
#2 0x00007ffff7dc5745 in ?? () from /usr/lib/libefence.so
#3 0x00007ffff7dc5e7e in memalign () from /usr/lib/libefence.so
#4 0x00007ffff7ae9b39 in operator new(unsigned long) () from /lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00005555555e16ca in __gnu_cxx::new_allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >::allocate(unsigned long, void const*) ()
#6 0x00005555555e15b8 in std::allocator_traits<std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > >::allocate(std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >&, unsigned long) ()
#7 0x00005555555e13a6 in std::_Vector_base<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > >::_M_allocate(unsigned long) ()
#8 0x0000555555600284 in std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > >::_M_default_append(unsigned long) ()
#9 0x00005555555fc17b in std::vector<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::allocator<std::__cxx11::basic_string<char, std::char_traits, std::allocator > > >::resize(unsigned long) ()
#10 0x00005555555f0328 in quipper::PerfReader::ReadCPUTopologyMetadata(quipper::DataReader*, unsigned long) ()
#11 0x00005555555ee39c in quipper::PerfReader::ReadMetadataWithoutHeader(quipper::DataReader*, unsigned int, unsigned long)::{lambda()#1}::operator()() const ()
#12 0x00005555555ee710 in quipper::PerfReader::ReadMetadataWithoutHeader(quipper::DataReader*, unsigned int, unsigned long) ()
#13 0x00005555555ede94 in quipper::PerfReader::ReadMetadata(quipper::DataReader*) ()
#14 0x00005555555f1717 in quipper::PerfReader::ReadFileData(quipper::DataReader*) ()
#15 0x00005555555e8ce6 in quipper::PerfReader::ReadFromData(quipper::DataReader*) ()
#16 0x00005555555e8b69 in quipper::PerfReader::ReadFromPointer(char const*, unsigned long) ()
#17 0x00005555555799ac in perftools::RawPerfDataToProfiles(void const*, unsigned long, std::map<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::less<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, std::allocator > const, std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > > const&, unsigned int, unsigned int, std::map<unsigned int, std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::less, std::allocator<std::pair<unsigned int const, std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > > const&) ()
#18 0x00005555555746c4 in StringToProfiles(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&, unsigned int, unsigned int) ()
#19 0x00005555555731e5 in main ()
(gdb) i r
rax 0xfffffffffffffff4 -12
rbx 0x7ffff703e730 140737337616176
rcx 0x7ffff79489ab 140737347094955
rdx 0x3 3
rsi 0xd6e6c3000 57687158784
rdi 0x7fff8894c000 140735484837888
rbp 0xd6e6c4000 0xd6e6c4000
rsp 0x7fffffffc9d8 0x7fffffffc9d8
r8 0xffffffff 4294967295
r9 0x0 0
r10 0x22 34
r11 0x202 514
r12 0x7ffff703e758 140737337616216
r13 0x7ffff703e758 140737337616216
r14 0xd6e6c2e80 57687158400
r15 0x7ffff7fc8128 140737353908520
rip 0x7ffff79489ab 0x7ffff79489ab <mprotect+11>
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) exploitable
Description: Segmentation fault on program counter
Short description: SegFaultOnPc (3/22)
Hash: 434b871bba6df1ba821918d14d98847d.3c60d5a82288d85766b6290f18c589bb
Exploitability Classification: EXPLOITABLE
Explanation: The target tried to access data at an address that matches the program counter. This is likely due to the execution of a branch instruction (ex: 'call') with a bad argument, but it could also be due to execution continuing past the end of a memory region or another cause. Regardless this likely indicates that the program counter contents are tainted and can be controlled by an attacker.
Other tags: AccessViolation (21/22)
Recommendation/fix is to provide more input validation and bounds checking to ensure malformed files that could trigger error conditions are instead handled gracefully.