diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-12-14 13:12:01 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-12-14 13:12:01 -0200 |
commit | 57f5b81da9f1f23380d20f164012e10c5f4fef94 (patch) | |
tree | f626d12697bfec8bba9290a0f11b29f71705eaab | |
parent | fdc25a1ebfe9968dcec390dd556375105aa0be40 (diff) | |
download | lua-github-57f5b81da9f1f23380d20f164012e10c5f4fef94.tar.gz |
Bug: Long brackets with a huge number of '=' causes overflow
A long bracket with too many equal signs can overflow the 'int' used for
the counting and some arithmetic done on the value. Changing the counter
to 'size_t' avoids that. (Because what is counted goes to a buffer, an
overflow in the counter will first raise a buffer-overflow error.)
-rw-r--r-- | bugs | 19 | ||||
-rw-r--r-- | llex.c | 30 |
2 files changed, 35 insertions, 14 deletions
@@ -4017,6 +4017,25 @@ patch = [[ +--[=[ +Bug{ +what = [[Long brackets with a huge number of '=' overflow some +internal buffer arithmetic]], +report = [[Marco, 2018/12/12]], +since = [[5.1]], +fix = nil, +example = [[ +local eqs = string.rep("=", 0x3ffffffe) +local code = "return [" .. eqs .. "[a]" .. eqs .. "]" +print(#assert(load(code))()) +]], +patch = [[ +]] +} +]=] + + + --[=[ Bug{ @@ -244,12 +244,12 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) { /* -** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return -** its number of '='s; otherwise, return a negative number (-1 iff there -** are no '='s after initial bracket) +** reads a sequence '[=*[' or ']=*]', leaving the last bracket. +** If sequence is well formed, return its number of '='s + 2; otherwise, +** return 1 if there is no '='s or 0 otherwise (an unfinished '[==...'). */ -static int skip_sep (LexState *ls) { - int count = 0; +static size_t skip_sep (LexState *ls) { + size_t count = 0; int s = ls->current; lua_assert(s == '[' || s == ']'); save_and_next(ls); @@ -257,11 +257,13 @@ static int skip_sep (LexState *ls) { save_and_next(ls); count++; } - return (ls->current == s) ? count : (-count) - 1; + return (ls->current == s) ? count + 2 + : (count == 0) ? 1 + : 0; } -static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { +static void read_long_string (LexState *ls, SemInfo *seminfo, size_t sep) { int line = ls->linenumber; /* initial line (for error message) */ save_and_next(ls); /* skip 2nd '[' */ if (currIsNewline(ls)) /* string starts with a newline? */ @@ -295,8 +297,8 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { } } endloop: if (seminfo) - seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), - luaZ_bufflen(ls->buff) - 2*(2 + sep)); + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + sep, + luaZ_bufflen(ls->buff) - 2 * sep); } @@ -444,9 +446,9 @@ static int llex (LexState *ls, SemInfo *seminfo) { /* else is a comment */ next(ls); if (ls->current == '[') { /* long comment? */ - int sep = skip_sep(ls); + size_t sep = skip_sep(ls); luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ - if (sep >= 0) { + if (sep >= 2) { read_long_string(ls, NULL, sep); /* skip long comment */ luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ break; @@ -458,12 +460,12 @@ static int llex (LexState *ls, SemInfo *seminfo) { break; } case '[': { /* long string or simply '[' */ - int sep = skip_sep(ls); - if (sep >= 0) { + size_t sep = skip_sep(ls); + if (sep >= 2) { read_long_string(ls, seminfo, sep); return TK_STRING; } - else if (sep != -1) /* '[=...' missing second bracket */ + else if (sep == 0) /* '[=...' missing second bracket? */ lexerror(ls, "invalid long string delimiter", TK_STRING); return '['; } |