Coordinated Disclosure Timeline
- 2023-05-08: Reported as a private issue in the repository.
- 2023-07-17: Fixed in the master branch, post v0.0.8.
Summary
A crafted sequence of bytes triggers memory read past the bounds of a globally allocated object buffer.
Product
uchardet
Tested Version
Master branch, post v0.0.8.
Details
Global buffer read overflow in GetOrderFromCodePoint
(GHSL-2023-105
)
The out of bounds read happens in GetOrderFromCodePoint
[1] when i
becomes equal to max
. For example, in the PoC, initially max
is set to 64
[2] (it is a half of the true size of the mModel->charOrderTable
buffer). i
is set to 32
[3]. The binary search in the loop increases the i
until it reaches 63
in [4] and max
is assigned to i
. However in the next loop iteration the index i * 2
(64) [1] reads one integer out of the true buffer size (64).
int nsLanguageDetector::GetOrderFromCodePoint(int codePoint)
{
int max = mModel->charOrderTableSize; // [2]
int i = max / 2; // [3]
int c = mModel->charOrderTable[i * 2];
while ((c = mModel->charOrderTable[i * 2]) != codePoint) // [1] buffer read overflow
{
if (c > codePoint)
{
if (i == 0)
break;
max = i - 1;
i = i / 2;
}
else if (i < max - 1)
{
i += (max - i) / 2;
}
else if (i == max - 1) // [4]
{
i = max; // [5]
}
else
{
break;
}
}
return (c == codePoint) ? mModel->charOrderTable[i * 2 + 1] : -1;
}
Impact
This issue may be used to leak internal memory allocation information.
Resources
To reproduce the issue:
- Make ASAN build or set breakpoint with the condition
i == 64
atwhile ((c = mModel->charOrderTable[i * 2]) != codePoint)
. - Run the following program to hit the breakpoint or out of bounds access with ASAN:
uchardet_t ud = uchardet_new(); uchardet_handle_data(ud, "\xe6\xbc\xa2", 3);
The output when built with ASAN:
==13==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000006100a0 at pc 0x000000595025 bp 0x7ffc86d95830 sp 0x7ffc86d95828
READ of size 4 at 0x0000006100a0 thread T0
SCARINESS: 17 (4-byte-read-global-buffer-overflow)
#0 0x595024 in GetOrderFromCodePoint /src/uchardet/src/nsLanguageDetector.cpp:254:15
#1 0x595024 in nsLanguageDetector::HandleData(int const*, unsigned int) /src/uchardet/src/nsLanguageDetector.cpp:49:13
#2 0x584dbd in nsMBCSGroupProber::HandleData(char const*, unsigned int, int**, int*) /src/uchardet/src/nsMBCSGroupProber.cpp:369:32
#3 0x57e3cd in nsUniversalDetector::HandleData(char const*, unsigned int) /src/uchardet/src/nsUniversalDetector.cpp:275:34
#4 0x5786ae in uchardet_handle_data /src/uchardet/src/uchardet.cpp:220:63
DEDUP_TOKEN: GetOrderFromCodePoint--nsLanguageDetector::HandleData(int const*, unsigned int)--nsMBCSGroupProber::HandleData(char const*, unsigned int, int**, int*)
0x0000006100a0 is located 0 bytes to the right of global variable 'Unicode_CharOrder' defined in '/src/uchardet/src/LangModels/LangArabicModel.cpp:110:27' (0x60fea0) of size 512
SUMMARY: AddressSanitizer: global-buffer-overflow /src/uchardet/src/nsLanguageDetector.cpp:254:15 in GetOrderFromCodePoint
Shadow bytes around the buggy address:
0x0000800b9fc0: f9 f9 f9 f9 00 05 f9 f9 00 00 00 00 00 00 f9 f9
0x0000800b9fd0: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800b9fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800b9ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800ba000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0000800ba010: 00 00 00 00[f9]f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000800ba020: f9 f9 f9 f9 00 00 00 00 00 00 00 f9 f9 f9 f9 f9
0x0000800ba030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800ba040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800ba050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800ba060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==13==ABORTING
Credit
This issue was discovered and reported by GHSL team member @JarLob (Jaroslav Lobačevski).
Contact
You can contact the GHSL team at securitylab@github.com
, please include a reference to GHSL-2023-105
in any communication regarding this issue.