Skip to content

Commit 10eb89d

Browse files
committed
BUG: shift overflow in utf-8 decode
An initial byte \xFF will ask for 7 continuation bytes, and then the shift by (count * 5) will try to shift 35 bits.
1 parent 7c40c5e commit 10eb89d

3 files changed

Lines changed: 18 additions & 3 deletions

File tree

lutf8lib.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
5656
l_uint32 res = 0; /* final result */
5757
if (c < 0x80) /* ASCII? */
5858
res = c;
59+
else if (c >= 0xfe) /* c >= 1111 1110b ? */
60+
return NULL; /* would need six or more continuation bytes */
5961
else {
6062
int count = 0; /* to count number of continuation bytes */
6163
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
@@ -64,8 +66,9 @@ static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
6466
return NULL; /* invalid byte sequence */
6567
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
6668
}
69+
lua_assert(count <= 5);
6770
res |= ((l_uint32)(c & 0x7F) << (count * 5)); /* add first byte */
68-
if (count > 5 || res > MAXUTF || res < limits[count])
71+
if (res > MAXUTF || res < limits[count])
6972
return NULL; /* invalid byte sequence */
7073
s += count; /* skip continuation bytes read */
7174
}

makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ CWARNS= $(CWARNSCPP) $(CWARNSC) $(CWARNGCC)
6060
# create problems; some are only available in newer gcc versions. To
6161
# use some of them, we also have to define an environment variable
6262
# ASAN_OPTIONS="detect_invalid_pointer_pairs=2".
63-
# -fsanitize=undefined
63+
# -fsanitize=undefined (you may need to add "-lubsan" to libs)
6464
# -fsanitize=pointer-subtract -fsanitize=address -fsanitize=pointer-compare
6565
# TESTS= -DLUA_USER_H='"ltests.h"' -Og -g
6666

testes/utf8.lua

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,18 @@ s = "\0 \x7F\z
238238
s = string.gsub(s, " ", "")
239239
check(s, {0,0x7F, 0x80,0x7FF, 0x800,0xFFFF, 0x10000,0x10FFFF})
240240

241+
242+
-- again, without strictness
243+
s = "\xF0\x90\x80\x80 \xF7\xBF\xBF\xBF\z
244+
\xF8\x88\x80\x80\x80 \xFB\xBF\xBF\xBF\xBF\z
245+
\xFC\x84\x80\x80\x80\x80 \xFD\xBF\xBF\xBF\xBF\xBF"
246+
s = string.gsub(s, " ", "")
247+
check(s, {0x10000,0x1FFFFF, 0x200000,0x3FFFFFF, 0x4000000,0x7FFFFFFF}, true)
248+
241249
do
242250
-- original UTF-8 values
243251
local s = "\u{4000000}\u{7FFFFFFF}"
244-
assert(#s == 12)
252+
assert(s == "\xFC\x84\x80\x80\x80\x80\xFD\xBF\xBF\xBF\xBF\xBF")
245253
check(s, {0x4000000, 0x7FFFFFFF}, true)
246254

247255
s = "\u{200000}\u{3FFFFFF}"
@@ -257,6 +265,10 @@ local x = "日本語a-4\0éó"
257265
check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243})
258266

259267

268+
-- more than 5 continuation bytes
269+
assert(not utf8.len("\xff\x8f\x8f\x8f\x8f\x8f\x8f\x8f"))
270+
271+
260272
-- Supplementary Characters
261273
check("𣲷𠜎𠱓𡁻𠵼ab𠺢",
262274
{0x23CB7, 0x2070E, 0x20C53, 0x2107B, 0x20D7C, 0x61, 0x62, 0x20EA2,})

0 commit comments

Comments
 (0)