-
Notifications
You must be signed in to change notification settings - Fork 43
Closed
Copy link
Labels
Description
A Buffer Overflow in ParseText exists from the Initial Commit. This reproduction is made with Clang and fil-c toolchains.
The Code
template <class T, icTagTypeSignature Tsig>
icUInt32Number CIccXmlArrayType<T, Tsig>::ParseText(T* pBuf, icUInt32Number nSize, const char *szText)
{
icUInt32Number n = 0, b = 0;
bool bInNum = false;
char num[256] = {0};
while (*szText && n<nSize) {
if (icIsNumChar(*szText)) {
if (!bInNum) {
bInNum = true;
b=0;
}
num[b] = *szText;
if (b+2<sizeof(num))
b++;
}
else if (bInNum) {
num[b] = 0;
if (!strncmp(num, "nan", 3) || !strncmp(num, "-nan", 4)) {
pBuf[n] = (T)nanf(num);
}
else {
pBuf[n] = (T)atof(num);
}
n++;
bInNum = false;
}
szText++;
}
if (bInNum) {
num[b] = 0;
if (!strncmp(num, "nan", 3) || !strncmp(num, "-nan", 4)) {
pBuf[n] = (T)nanf(num);
}
else {
pBuf[n] = (T)atof(num);
}
n++;
}
return n;
}
...
The Bug
- The loop exits because n == nSize
- But bInNum remains true (last number didn’t get flushed inside the loop)
- The final block writes pBuf[n], where n == nSize
→ Heap-buffer-overflow by one element
fil-c
Fil-C is a memory-safe implementation of C and C++ created by Filip Pizlo at Epic Games. It provides full C/C++ compatibility while preventing all memory safety errors through a combination of concurrent garbage co
llection and invisible capabilities (InvisiCap system).
Key characteristics:
- Memory Safety: All pointers carry capabilities tracking bounds and type information
- GIMSO Principle: "Garbage In, Memory Safety Out" - no unsafe escape hatches
- Garbage Collection: Uses FUGC (Fil's Unbelievable Garbage Collector) - concurrent, non-moving GC
- Platform: Currently Linux/X86_64 only
- Performance: 1.5x-5x slower than standard C (actively being optimized)
Build fil-c
Required: Namespace builds for all dependencies
Build iccDEV
Cmake Configure for iccDEV
export PATH="$HOME/fil-c/build/bin:$PATH" CC=filcc CXX=fil++ AR=llvm-ar RANLIB=llvm-ranlib LD_LIBRARY_PATH="$HOME/fil-c/build/lib:$LD_LIBRARY_PATH" && \
LIBCXX="$HOME/fil-c/build/bin/../include/c++/v1" && rm -rf CMakeCache.txt CMakeFiles && cmake -G Ninja -D CMAKE_C_COMPILER="$CC" \
-D CMAKE_CXX_COMPILER="$CXX" -D CMAKE_AR="$AR" -D CMAKE_RANLIB="$RANLIB" -D CMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ -fuse-ld=lld" \
-D CMAKE_SHARED_LINKER_FLAGS="-stdlib=libc++ -fuse-ld=lld" -D CMAKE_MODULE_LINKER_FLAGS="-stdlib=libc++ -fuse-ld=lld" \
-D CMAKE_CXX_FLAGS="-isystem $LIBCXX -isystem /usr/include -isystem /usr/include/x86_64-linux-gnu -stdlib=libc++" \
-D LIBXML2_INCLUDE_DIR="$HOME/fil-c/build/include/libxml2" -D LIBXML2_LIBRARY="$HOME/fil-c/build/lib/libxml2.so" \
-D TIFF_INCLUDE_DIR=/usr/include/x86_64-linux-gnu -D TIFF_LIBRARY=/usr/lib/x86_64-linux-gnu/libtiff.so \
-D PNG_PNG_INCLUDE_DIR=/usr/include -D PNG_LIBRARY=/usr/lib/x86_64-linux-gnu/libpng16.so -D ZLIB_INCLUDE_DIR=/usr/include \
-D ZLIB_LIBRARY=/usr/lib/x86_64-linux-gnu/libz.so -D JPEG_INCLUDE_DIR=/usr/include
-D JPEG_LIBRARY=/usr/lib/x86_64-linux-gnu/libjpeg.so \
Cmake
make -j$(nproc)
Add Tools to PATH
cd Testing/
echo "=== Updating PATH ==="
for d in ../Build/Tools/*; do
[ -d "$d" ] && export PATH="$(realpath "$d"):$PATH"
done
fil-c reproduction
$ Testing/CMYK-3DLUTs$ iccFromXml CMYK-3DLUTs2.xml CMYK-3DLUTs2.icc
filc safety error: cannot read pointer with ptr >= upper.
pointer: 0x718f0b40ea20,0x718f0b408c10,0x718f0b40ea20
expected 1 bytes.
semantic origin:
IccXML/IccLibXML/IccUtilXml.cpp:995:10: CIccXmlArrayType<unsigned short, (icTagTypeSignature)1969828150>::ParseText(unsigned short*, unsigned int, char const*)
check scheduled at:
IccXML/IccLibXML/IccUtilXml.cpp:995:10: CIccXmlArrayType<unsigned short, (icTagTypeSignature)1969828150>::ParseText(unsigned short*, unsigned int, char const*)
IccXML/IccLibXML/IccUtilXml.cpp:813:12: CIccXmlArrayType<unsigned short, (icTagTypeSignature)1969828150>::ParseTextArrayNum(char const*, unsigned int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccMpeXml.cpp:750:19: CIccSinglSampledeCurveXml::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccMpeXml.cpp:1106:17: ParseXmlCurve(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>)
IccXML/IccLibXML/IccMpeXml.cpp:1164:37: CIccMpeXmlCurveSet::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccMpeXml.cpp: non-virtual thunk to CIccMpeXmlCurveSet::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccMpeXml.cpp:2582:26: CIccMpeXmlCalculator::ParseImport(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccMpeXml.cpp:3099:8: CIccMpeXmlCalculator::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccMpeXml.cpp: non-virtual thunk to CIccMpeXmlCalculator::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccTagXml.cpp:4059:20: CIccTagXmlMultiProcessElement::ParseElement(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccTagXml.cpp:4119:12: CIccTagXmlMultiProcessElement::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccTagXml.cpp: non-virtual thunk to CIccTagXmlMultiProcessElement::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccProfileXml.cpp:719:20: CIccProfileXml::ParseTag(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccProfileXml.cpp:828:12: CIccProfileXml::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&)
IccXML/IccLibXML/IccProfileXml.cpp:885:13: CIccProfileXml::LoadXml(char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)
IccXML/CmdLine/IccFromXml/IccFromXml.cpp:68:18: main
../sysdeps/nptl/libc_start_call_main.h:58:16: __libc_start_call_main
../csu/libc-start.c:161:3: __libc_start_main
<runtime>: start_program
[3554241] filc panic: thwarted a futile attempt to violate memory safety.
Trace/breakpoint trap (core dumped)
Clang Asan Repro
$ iccFromXml CMYK-3DLUTs2.xml CMYK-3DLUTs2.icc
=================================================================
==477335==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x52b00001b04f at pc 0x733f0371998c bp 0x7ffc63aa7810 sp 0x7ffc63aa7808
READ of size 1 at 0x52b00001b04f thread T0
#0 0x733f0371998b in CIccXmlArrayType<unsigned short, (icTagTypeSignature)1969828150>::ParseText(unsigned short*, unsigned int, char const*) IccXML/IccLibXML/IccUtilXml.cpp:995:10
#1 0x733f0371bdba in CIccXmlArrayType<unsigned short, (icTagTypeSignature)1969828150>::ParseTextArrayNum(char const*, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccUtilXml.cpp:813:12
#2 0x733f03575f70 in CIccSinglSampledeCurveXml::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccMpeXml.cpp:750:19
#3 0x733f03581f35 in ParseXmlCurve(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) IccXML/IccLibXML/IccMpeXml.cpp:1106:17
#4 0x733f0358143b in CIccMpeXmlCurveSet::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccMpeXml.cpp:1164:37
#5 0x733f035b0dad in CIccMpeXmlCalculator::ParseImport(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccMpeXml.cpp:2582:26
#6 0x733f035c4b9f in CIccMpeXmlCalculator::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccMpeXml.cpp:3099:8
#7 0x733f036a3665 in CIccTagXmlMultiProcessElement::ParseElement(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccTagXml.cpp:4059:20
#8 0x733f036a56a3 in CIccTagXmlMultiProcessElement::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccTagXml.cpp:4119:12
#9 0x733f03626682 in CIccProfileXml::ParseTag(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccProfileXml.cpp:719:20
#10 0x733f0362a9f7 in CIccProfileXml::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccProfileXml.cpp:828:12
#11 0x733f0362afe9 in CIccProfileXml::LoadXml(char const*, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*) IccXML/IccLibXML/IccProfileXml.cpp:885:13
#12 0x5b81abd66f07 in main IccXML/CmdLine/IccFromXml/IccFromXml.cpp:68:18
#13 0x733f01c2a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#14 0x733f01c2a28a in __libc_start_main csu/../csu/libc-start.c:360:3
#15 0x5b81abc8a574 in _start (Build/Tools/IccFromXml/iccFromXml+0x2f574) (BuildId: 15ca05e0f3102b7bd8d1a018f19c97e7552121b7)
0x52b00001b04f is located 0 bytes after 24143-byte region [0x52b000015200,0x52b00001b04f)
allocated by thread T0 here:
#0 0x5b81abd63b01 in operator new[](unsigned long) (Build/Tools/IccFromXml/iccFromXml+0x108b01) (BuildId: 15ca05e0f3102b7bd8d1a018f19c97e7552121b7)
#1 0x733f03574a2d in CIccSinglSampledeCurveXml::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccMpeXml.cpp:686:19
#2 0x733f03581f35 in ParseXmlCurve(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) IccXML/IccLibXML/IccMpeXml.cpp:1106:17
#3 0x733f0358143b in CIccMpeXmlCurveSet::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccMpeXml.cpp:1164:37
#4 0x733f035b0dad in CIccMpeXmlCalculator::ParseImport(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccMpeXml.cpp:2582:26
#5 0x733f035c4b9f in CIccMpeXmlCalculator::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccMpeXml.cpp:3099:8
#6 0x733f036a3665 in CIccTagXmlMultiProcessElement::ParseElement(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccTagXml.cpp:4059:20
#7 0x733f036a56a3 in CIccTagXmlMultiProcessElement::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccTagXml.cpp:4119:12
#8 0x733f03626682 in CIccProfileXml::ParseTag(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccProfileXml.cpp:719:20
#9 0x733f0362a9f7 in CIccProfileXml::ParseXml(_xmlNode*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) IccXML/IccLibXML/IccProfileXml.cpp:828:12
#10 0x733f0362afe9 in CIccProfileXml::LoadXml(char const*, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*) IccXML/IccLibXML/IccProfileXml.cpp:885:13
#11 0x5b81abd66f07 in main IccXML/CmdLine/IccFromXml/IccFromXml.cpp:68:18
#12 0x733f01c2a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#13 0x733f01c2a28a in __libc_start_main csu/../csu/libc-start.c:360:3
#14 0x5b81abc8a574 in _start (Build/Tools/IccFromXml/iccFromXml+0x2f574) (BuildId: 15ca05e0f3102b7bd8d1a018f19c97e7552121b7)
SUMMARY: AddressSanitizer: heap-buffer-overflow IccXML/IccLibXML/IccUtilXml.cpp:995:10 in CIccXmlArrayType<unsigned short, (icTagTypeSignature)1969828150>::ParseText(unsigned short*, unsigned int, char const*)
Shadow bytes around the buggy address:
0x52b00001ad80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x52b00001ae00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x52b00001ae80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x52b00001af00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x52b00001af80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x52b00001b000: 00 00 00 00 00 00 00 00 00[07]fa fa fa fa fa fa
0x52b00001b080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x52b00001b100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x52b00001b180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x52b00001b200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x52b00001b280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==477335==ABORTING
Potential Fix
...
if (bInNum && n < nSize) {
num[b] = 0;
if (!strncmp(num, "nan", 3) || !strncmp(num, "-nan", 4))
pBuf[n] = (T)nanf(num);
else
pBuf[n] = (T)atof(num);
n++;
}
...
Summary
This issue to be addressed in a future PR.