Description
Dear jsoncpp dev team,
I have faced with this bug, which could lead to security issues.
Prerequisites:
jsoncpp-1.8.4
Affected OS: Linux
Test sources:
`
#include
#include
#include
#include "json/json.h"
using namespace std;
int main(int argc,char *argv[])
{
Json::Value jsonRoot;
Json::Value jsonItem;
ifstream ifs;
ifs.open(argv[1]);
jsonRoot.clear();
Json::CharReaderBuilder builder;
builder["collectComments"]=false;
JSONCPP_STRING errs;
if (!parseFromStream(builder,ifs,&jsonRoot,&errs))
{
return -1;
}
return 0;
}
`
Steps to reproduce:
afl-g++ -g test.cpp -I /usr/local/lib/ -L /usr/local/lib/libjsoncpp.a -ljsoncpp -o test2
valgrind -v --tool=memcheck --leak-check=full ./test2 poc
(attached poc
poc.zip
)
==73238== Memcheck, a memory error detector
==73238== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==73238== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==73238== Command: ./test2 jsonouput/crashes/id:000000,sig:06,src:000033,op:havoc,rep:4
==73238==
--73238-- Valgrind options:
--73238-- -v
--73238-- --tool=memcheck
--73238-- --leak-check=full
--73238-- Contents of /proc/version:
--73238-- Linux version 4.17.0-kali1-amd64 ([email protected]) (gcc version 7.3.0 (Debian 7.3.0-25)) #1 SMP Debian 4.17.8-1kali1 (2018-07-24)
--73238--
--73238-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-avx-avx2-bmi
--73238-- Page sizes: currently 4096, max supported 4096
--73238-- Valgrind library directory: /usr/lib/valgrind
--73238-- Reading syms from /root/jsoncpp/test2
--73238-- Reading syms from /usr/lib/x86_64-linux-gnu/ld-2.27.so
--73238-- Considering /usr/lib/debug/.build-id/dc/5cb16f5e644116cac64a4c3f5da4d081b81a4f.debug ..
--73238-- .. build-id is valid
--73238-- Reading syms from /usr/lib/valgrind/memcheck-amd64-linux
--73238-- Considering /usr/lib/valgrind/memcheck-amd64-linux ..
--73238-- .. CRC mismatch (computed 7680f3df wanted 92e0f93c)
--73238-- Considering /usr/lib/debug/usr/lib/valgrind/memcheck-amd64-linux ..
--73238-- .. CRC is valid
--73238-- object doesn't have a dynamic symbol table
--73238-- Scheduler: using generic scheduler lock implementation.
--73238-- Reading suppressions file: /usr/lib/valgrind/default.supp
==73238== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-73238-by-root-on-???
==73238== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-73238-by-root-on-???
==73238== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-73238-by-root-on-???
==73238==
==73238== TO CONTROL THIS PROCESS USING vgdb (which you probably
==73238== don't want to do, unless you know exactly what you're doing,
==73238== or are doing some strange experiment):
==73238== /usr/lib/valgrind/../../bin/vgdb --pid=73238 ...command...
==73238==
==73238== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==73238== /path/to/gdb ./test2
==73238== and then give GDB the following command
==73238== target remote | /usr/lib/valgrind/../../bin/vgdb --pid=73238
==73238== --pid is optional if only one valgrind process is running
==73238==
--73238-- REDIR: 0x401e290 (ld-linux-x86-64.so.2:strlen) redirected to 0x58061781 (vgPlain_amd64_linux_REDIR_FOR_strlen)
--73238-- REDIR: 0x401e070 (ld-linux-x86-64.so.2:index) redirected to 0x5806179b (vgPlain_amd64_linux_REDIR_FOR_index)
--73238-- Reading syms from /usr/lib/valgrind/vgpreload_core-amd64-linux.so
--73238-- Considering /usr/lib/valgrind/vgpreload_core-amd64-linux.so ..
--73238-- .. CRC mismatch (computed 66a2a561 wanted 3789c7eb)
--73238-- Considering /usr/lib/debug/usr/lib/valgrind/vgpreload_core-amd64-linux.so ..
--73238-- .. CRC is valid
--73238-- Reading syms from /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so
--73238-- Considering /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so ..
--73238-- .. CRC mismatch (computed 8487a070 wanted 8af30a91)
--73238-- Considering /usr/lib/debug/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so ..
--73238-- .. CRC is valid
==73238== WARNING: new redirection conflicts with existing -- ignoring it
--73238-- old: 0x0401e290 (strlen ) R-> (0000.0) 0x58061781 vgPlain_amd64_linux_REDIR_FOR_strlen
--73238-- new: 0x0401e290 (strlen ) R-> (2007.0) 0x04838a60 strlen
--73238-- REDIR: 0x401aab0 (ld-linux-x86-64.so.2:strcmp) redirected to 0x4839b90 (strcmp)
--73238-- REDIR: 0x401e7d0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x483d1a0 (mempcpy)
--73238-- Reading syms from /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
--73238-- object doesn't have a symbol table
--73238-- Reading syms from /usr/lib/x86_64-linux-gnu/libm-2.27.so
--73238-- Considering /usr/lib/debug/.build-id/fa/b2857727406caccd7ab22e1729b09ccf2c3eb7.debug ..
--73238-- .. build-id is valid
--73238-- Reading syms from /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
--73238-- object doesn't have a symbol table
--73238-- Reading syms from /usr/lib/x86_64-linux-gnu/libc-2.27.so
--73238-- Considering /usr/lib/debug/.build-id/dc/87cd1e2b171a4c51139cb4e1f2ec630e711de3.debug ..
--73238-- .. build-id is valid
--73238-- REDIR: 0x4c1c050 (libc.so.6:memmove) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1b280 (libc.so.6:strncpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1c330 (libc.so.6:strcasecmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1acd0 (libc.so.6:strcat) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1b2b0 (libc.so.6:rindex) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1d900 (libc.so.6:rawmemchr) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1c1c0 (libc.so.6:mempcpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1bff0 (libc.so.6:bcmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1b240 (libc.so.6:strncmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1ad40 (libc.so.6:strcmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1c120 (libc.so.6:memset) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c35b60 (libc.so.6:wcschr) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1b1e0 (libc.so.6:strnlen) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1adb0 (libc.so.6:strcspn) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1c380 (libc.so.6:strncasecmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1ad80 (libc.so.6:strcpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1c4c0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1b2e0 (libc.so.6:strpbrk) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1ad00 (libc.so.6:index) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1b1b0 (libc.so.6:strlen) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c221b0 (libc.so.6:memrchr) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1c3d0 (libc.so.6:strcasecmp_l) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1bfc0 (libc.so.6:memchr) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c36920 (libc.so.6:wcslen) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1b590 (libc.so.6:strspn) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1c300 (libc.so.6:stpncpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1c2d0 (libc.so.6:stpcpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1d930 (libc.so.6:strchrnul) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4c1c420 (libc.so.6:strncasecmp_l) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--73238-- REDIR: 0x4cee700 (libc.so.6:__strrchr_avx2) redirected to 0x48383e0 (rindex)
--73238-- REDIR: 0x4c175c0 (libc.so.6:malloc) redirected to 0x4835750 (malloc)
--73238-- REDIR: 0x4cee8d0 (libc.so.6:__strlen_avx2) redirected to 0x48389a0 (strlen)
--73238-- REDIR: 0x4ceaee0 (libc.so.6:__memcmp_avx2_movbe) redirected to 0x483bab0 (bcmp)
--73238-- REDIR: 0x4cca0a0 (libc.so.6:__strcmp_ssse3) redirected to 0x4839a50 (strcmp)
--73238-- REDIR: 0x4c1ba70 (libc.so.6:__GI_strstr) redirected to 0x483d410 (__strstr_sse2)
--73238-- REDIR: 0x48f6040 (libstdc++.so.6:operator new[](unsigned long)) redirected to 0x48364e0 (operator new[](unsigned long))
--73238-- REDIR: 0x48f5f90 (libstdc++.so.6:operator new(unsigned long)) redirected to 0x4835dc0 (operator new(unsigned long))
--73238-- REDIR: 0x4ceee10 (libc.so.6:__memcpy_avx_unaligned_erms) redirected to 0x483c390 (memmove)
--73238-- REDIR: 0x4c17c50 (libc.so.6:free) redirected to 0x4836980 (free)
--73238-- REDIR: 0x48f4220 (libstdc++.so.6:operator delete(void*)) redirected to 0x4836e80 (operator delete(void*))
--73238-- memcheck GC: 1000 nodes, 255 survivors (25.5%)
--73238-- memcheck GC: 1014 new table size (driftup)
--73238-- memcheck GC: 1014 nodes, 445 survivors (43.9%)
--73238-- memcheck GC: 1029 new table size (driftup)
--73238-- memcheck GC: 1029 nodes, 590 survivors (57.3%)
--73238-- memcheck GC: 1455 new table size (stepup)
--73238-- memcheck GC: 1455 nodes, 805 survivors (55.3%)
--73238-- memcheck GC: 2057 new table size (stepup)
--73238-- memcheck GC: 2057 nodes, 1118 survivors (54.4%)
--73238-- memcheck GC: 2909 new table size (stepup)
--73238-- memcheck GC: 2909 nodes, 1565 survivors (53.8%)
--73238-- memcheck GC: 4113 new table size (stepup)
--73238-- REDIR: 0x4c17d60 (libc.so.6:realloc) redirected to 0x4837960 (realloc)
terminate called after throwing an instance of 'Json::RuntimeError'
what(): Exceeded stackLimit in readValue().
==73238==
==73238== Process terminating with default action of signal 6 (SIGABRT)
==73238== at 0x4BC9F3B: raise (raise.c:51)
==73238== by 0x4BCB2F0: abort (abort.c:79)
==73238== by 0x48EF942: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==73238== by 0x48F5895: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==73238== by 0x48F58D0: std::terminate() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==73238== by 0x48F5B03: __cxa_throw (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==73238== by 0x111347: Json::throwRuntimeError(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) [clone .cold.180] (json_value.cpp:199)
==73238== by 0x154A5B: Json::OurReader::readValue() (json_reader.cpp:1103)
==73238== by 0x152B37: Json::OurReader::readArray(Json::OurReader::Token&) (json_reader.cpp:1530)
==73238== by 0x153B5A: Json::OurReader::readValue() (json_reader.cpp:1119)
==73238== by 0x152B37: Json::OurReader::readArray(Json::OurReader::Token&) (json_reader.cpp:1530)
==73238== by 0x153B5A: Json::OurReader::readValue() (json_reader.cpp:1119)
==73238==
==73238== HEAP SUMMARY:
==73238== in use at exit: 162,551 bytes in 2,048 blocks
==73238== total heap usage: 2,065 allocs, 17 frees, 239,243 bytes allocated
==73238==
==73238== Searching for pointers to 2,048 not-freed blocks
==73238== Checked 374,864 bytes
==73238==
==73238== 168 bytes in 1 blocks are possibly lost in loss record 32 of 43
==73238== at 0x48357BF: malloc (vg_replace_malloc.c:299)
==73238== by 0x48F475F: __cxa_allocate_exception (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==73238== by 0x16398A: Json::throwRuntimeError(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) (json_value.cpp:199)
==73238== by 0x154A5B: Json::OurReader::readValue() (json_reader.cpp:1103)
==73238== by 0x152B37: Json::OurReader::readArray(Json::OurReader::Token&) (json_reader.cpp:1530)
==73238== by 0x153B5A: Json::OurReader::readValue() (json_reader.cpp:1119)
==73238== by 0x152B37: Json::OurReader::readArray(Json::OurReader::Token&) (json_reader.cpp:1530)
==73238== by 0x153B5A: Json::OurReader::readValue() (json_reader.cpp:1119)
==73238== by 0x152B37: Json::OurReader::readArray(Json::OurReader::Token&) (json_reader.cpp:1530)
==73238== by 0x153B5A: Json::OurReader::readValue() (json_reader.cpp:1119)
==73238== by 0x152B37: Json::OurReader::readArray(Json::OurReader::Token&) (json_reader.cpp:1530)
==73238== by 0x153B5A: Json::OurReader::readValue() (json_reader.cpp:1119)
==73238==
==73238== LEAK SUMMARY:
==73238== definitely lost: 0 bytes in 0 blocks
==73238== indirectly lost: 0 bytes in 0 blocks
==73238== possibly lost: 168 bytes in 1 blocks
==73238== still reachable: 162,383 bytes in 2,047 blocks
==73238== suppressed: 0 bytes in 0 blocks
==73238== Reachable blocks (those to which a pointer was found) are not shown.
==73238== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==73238==
==73238== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==73238== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Bug analysis:
parseFromStream——》Reader::parse——》Reader::readValue()——》if (nodes_.size() > stackLimit_g)
throwRuntimeError("Exceeded stackLimit in readValue().");