From f8bc6d8ddc81bbb7ab8e5f233960ea9b01ff6e29 Mon Sep 17 00:00:00 2001 From: Tom Callaway Date: Fri, 31 Jul 2020 11:00:38 -0400 Subject: [PATCH] apply upstream fixes for CVE-2020-15889, CVE-2020-15945, and other known bugs --- lua-5.4.0-CVE-2020-15889.patch | 24 +++++ lua-5.4.0-CVE-2020-15945.patch | 169 +++++++++++++++++++++++++++++++++ lua-5.4.0-bug2.patch | 12 +++ lua-5.4.0-bug3.patch | 14 +++ lua-5.4.0-bug4.patch | 40 ++++++++ lua-5.4.0-bug5.patch | 12 +++ lua-5.4.0-bug6.patch | 22 +++++ lua-5.4.0-bug7.patch | 12 +++ lua-5.4.0-bug8.patch | 12 +++ lua.spec | 27 +++++- 10 files changed, 343 insertions(+), 1 deletion(-) create mode 100644 lua-5.4.0-CVE-2020-15889.patch create mode 100644 lua-5.4.0-CVE-2020-15945.patch create mode 100644 lua-5.4.0-bug2.patch create mode 100644 lua-5.4.0-bug3.patch create mode 100644 lua-5.4.0-bug4.patch create mode 100644 lua-5.4.0-bug5.patch create mode 100644 lua-5.4.0-bug6.patch create mode 100644 lua-5.4.0-bug7.patch create mode 100644 lua-5.4.0-bug8.patch diff --git a/lua-5.4.0-CVE-2020-15889.patch b/lua-5.4.0-CVE-2020-15889.patch new file mode 100644 index 0000000..a9bd7ce --- /dev/null +++ b/lua-5.4.0-CVE-2020-15889.patch @@ -0,0 +1,24 @@ +diff -up lua-5.4.0/src/lgc.c.CVE-2020-15889 lua-5.4.0/src/lgc.c +--- lua-5.4.0/src/lgc.c.CVE-2020-15889 2020-07-31 09:52:45.494753815 -0400 ++++ lua-5.4.0/src/lgc.c 2020-07-31 09:54:24.556428702 -0400 +@@ -1131,16 +1131,14 @@ static void finishgencycle (lua_State *L + + + /* +-** Does a young collection. First, mark 'OLD1' objects. (Only survival +-** and "recent old" lists can contain 'OLD1' objects. New lists cannot +-** contain 'OLD1' objects, at most 'OLD0' objects that were already +-** visited when marked old.) Then does the atomic step. Then, +-** sweep all lists and advance pointers. Finally, finish the collection. ++** Does a young collection. First, mark 'OLD1' objects. Then does the ++** atomic step. Then sweep all lists and advance pointers. Finally, ++** finish the collection. + */ + static void youngcollection (lua_State *L, global_State *g) { + GCObject **psurvival; /* to point to first non-dead survival object */ + lua_assert(g->gcstate == GCSpropagate); +- markold(g, g->survival, g->reallyold); ++ markold(g, g->allgc, g->reallyold); + markold(g, g->finobj, g->finobjrold); + atomic(L); + diff --git a/lua-5.4.0-CVE-2020-15945.patch b/lua-5.4.0-CVE-2020-15945.patch new file mode 100644 index 0000000..6ddf58b --- /dev/null +++ b/lua-5.4.0-CVE-2020-15945.patch @@ -0,0 +1,169 @@ +diff -up lua-5.4.0/lua-5.3.5/src/ldebug.c.CVE-2020-15945 lua-5.4.0/lua-5.3.5/src/ldebug.c +diff -up lua-5.4.0/src/ldebug.c.CVE-2020-15945 lua-5.4.0/src/ldebug.c +--- lua-5.4.0/src/ldebug.c.CVE-2020-15945 2020-07-31 09:58:23.504997354 -0400 ++++ lua-5.4.0/src/ldebug.c 2020-07-31 10:04:19.745448815 -0400 +@@ -33,10 +33,8 @@ + + #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) + +- +-/* Active Lua function (given call info) */ +-#define ci_func(ci) (clLvalue(s2v((ci)->func))) +- ++/* inverse of 'pcRel' */ ++#define invpcRel(pc, p) ((p)->code + (pc) + 1) + + static const char *funcnamefromcode (lua_State *L, CallInfo *ci, + const char **name); +@@ -127,20 +125,18 @@ static void settraps (CallInfo *ci) { + /* + ** This function can be called during a signal, under "reasonable" + ** assumptions. +-** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by +-** 'resethookcount') are for debug only, and it is no problem if they +-** get arbitrary values (causes at most one wrong hook call). 'hookmask' +-** is an atomic value. We assume that pointers are atomic too (e.g., gcc +-** ensures that for all platforms where it runs). Moreover, 'hook' is +-** always checked before being called (see 'luaD_hook'). ++** Fields 'basehookcount' and 'hookcount' (set by 'resethookcount') ++** are for debug only, and it is no problem if they get arbitrary ++** values (causes at most one wrong hook call). 'hookmask' is an atomic ++** value. We assume that pointers are atomic too (e.g., gcc ensures that ++** for all platforms where it runs). Moreover, 'hook' is always checked ++** before being called (see 'luaD_hook'). + */ + LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { + if (func == NULL || mask == 0) { /* turn off hooks? */ + mask = 0; + func = NULL; + } +- if (isLua(L->ci)) +- L->oldpc = L->ci->u.l.savedpc; + L->hook = func; + L->basehookcount = count; + resethookcount(L); +@@ -794,11 +790,24 @@ static int changedline (const Proto *p, + return 0; /* no line changes in the way */ + } + +- ++/* ++** Traces the execution of a Lua function. Called before the execution ++** of each opcode, when debug is on. 'L->oldpc' stores the last ++** instruction traced, to detect line changes. When entering a new ++** function, 'npci' will be zero and will test as a new line without ++** the need for 'oldpc'; so, 'oldpc' does not need to be initialized ++** before. Some exceptional conditions may return to a function without ++** updating 'oldpc'. In that case, 'oldpc' may be invalid; if so, it is ++** reset to zero. (A wrong but valid 'oldpc' at most causes an extra ++** call to a line hook.) ++*/ + int luaG_traceexec (lua_State *L, const Instruction *pc) { + CallInfo *ci = L->ci; + lu_byte mask = L->hookmask; ++ const Proto *p = ci_func(ci)->p; + int counthook; ++ /* 'L->oldpc' may be invalid; reset it in this case */ ++ int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; + if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ + ci->u.l.trap = 0; /* don't need to stop again */ + return 0; /* turn off 'trap' */ +@@ -819,15 +828,14 @@ int luaG_traceexec (lua_State *L, const + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ + if (mask & LUA_MASKLINE) { +- const Proto *p = ci_func(ci)->p; + int npci = pcRel(pc, p); + if (npci == 0 || /* call linehook when enter a new function, */ +- pc <= L->oldpc || /* when jump back (loop), or when */ +- changedline(p, pcRel(L->oldpc, p), npci)) { /* enter new line */ ++ pc <= invpcRel(oldpc, p) || /* when jump back (loop), or when */ ++ changedline(p, oldpc, npci)) { /* enter new line */ + int newline = luaG_getfuncline(p, npci); + luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ + } +- L->oldpc = pc; /* 'pc' of last call to line hook */ ++ L->oldpc = npci; /* 'pc' of last call to line hook */ + } + if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) +diff -up lua-5.4.0/src/ldebug.h.CVE-2020-15945 lua-5.4.0/src/ldebug.h +--- lua-5.4.0/src/ldebug.h.CVE-2020-15945 2020-07-31 10:04:30.727969467 -0400 ++++ lua-5.4.0/src/ldebug.h 2020-07-31 10:05:07.064383528 -0400 +@@ -13,6 +13,11 @@ + + #define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1) + ++ ++/* Active Lua function (given call info) */ ++#define ci_func(ci) (clLvalue(s2v((ci)->func))) ++ ++ + #define resethookcount(L) (L->hookcount = L->basehookcount) + + /* +diff -up lua-5.4.0/src/ldo.c.CVE-2020-15945 lua-5.4.0/src/ldo.c +--- lua-5.4.0/src/ldo.c.CVE-2020-15945 2020-07-31 10:05:32.374278847 -0400 ++++ lua-5.4.0/src/ldo.c 2020-07-31 10:06:43.643168227 -0400 +@@ -328,7 +328,7 @@ static StkId rethook (lua_State *L, Call + ptrdiff_t oldtop = savestack(L, L->top); /* hook may change top */ + int delta = 0; + if (isLuacode(ci)) { +- Proto *p = clLvalue(s2v(ci->func))->p; ++ Proto *p = ci_func(ci)->p; + if (p->is_vararg) + delta = ci->u.l.nextraargs + p->numparams + 1; + if (L->top < ci->top) +@@ -341,8 +341,8 @@ static StkId rethook (lua_State *L, Call + luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ + ci->func -= delta; + } +- if (isLua(ci->previous)) +- L->oldpc = ci->previous->u.l.savedpc; /* update 'oldpc' */ ++ if (isLua(ci = ci->previous)) ++ L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* update 'oldpc' */ + return restorestack(L, oldtop); + } + +diff -up lua-5.4.0/src/lstate.c.CVE-2020-15945 lua-5.4.0/src/lstate.c +--- lua-5.4.0/src/lstate.c.CVE-2020-15945 2020-07-31 10:06:52.754770540 -0400 ++++ lua-5.4.0/src/lstate.c 2020-07-31 10:07:22.512471730 -0400 +@@ -301,6 +301,7 @@ static void preinit_thread (lua_State *L + L->openupval = NULL; + L->status = LUA_OK; + L->errfunc = 0; ++ L->oldpc = 0; + } + + +diff -up lua-5.4.0/src/lstate.h.CVE-2020-15945 lua-5.4.0/src/lstate.h +--- lua-5.4.0/src/lstate.h.CVE-2020-15945 2020-07-31 10:07:30.784110703 -0400 ++++ lua-5.4.0/src/lstate.h 2020-07-31 10:08:15.957139065 -0400 +@@ -286,7 +286,6 @@ struct lua_State { + StkId top; /* first free slot in the stack */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ +- const Instruction *oldpc; /* last pc traced */ + StkId stack_last; /* last free slot in the stack */ + StkId stack; /* stack base */ + UpVal *openupval; /* list of open upvalues in this stack */ +@@ -297,6 +296,7 @@ struct lua_State { + volatile lua_Hook hook; + ptrdiff_t errfunc; /* current error handling function (stack index) */ + l_uint32 nCcalls; /* number of allowed nested C calls - 'nci' */ ++ int oldpc; /* last pc traced */ + int stacksize; + int basehookcount; + int hookcount; +diff -up lua-5.4.0/src/lvm.c.CVE-2020-15945 lua-5.4.0/src/lvm.c +--- lua-5.4.0/src/lvm.c.CVE-2020-15945 2020-07-31 10:08:32.014438227 -0400 ++++ lua-5.4.0/src/lvm.c 2020-07-31 10:08:57.189339437 -0400 +@@ -1796,7 +1796,7 @@ void luaV_execute (lua_State *L, CallInf + updatetrap(ci); + if (trap) { + luaD_hookcall(L, ci); +- L->oldpc = pc + 1; /* next opcode will be seen as a "new" line */ ++ L->oldpc = 1; /* next opcode will be seen as a "new" line */ + } + updatebase(ci); /* function has new base after adjustment */ + vmbreak; diff --git a/lua-5.4.0-bug2.patch b/lua-5.4.0-bug2.patch new file mode 100644 index 0000000..0236d82 --- /dev/null +++ b/lua-5.4.0-bug2.patch @@ -0,0 +1,12 @@ +diff -up lua-5.4.0/src/ldo.c.bug2 lua-5.4.0/src/ldo.c +--- lua-5.4.0/src/ldo.c.bug2 2020-07-31 10:40:55.409594540 -0400 ++++ lua-5.4.0/src/ldo.c 2020-07-31 10:41:19.193556341 -0400 +@@ -674,7 +674,7 @@ LUA_API int lua_resume (lua_State *L, lu + if (from == NULL) + L->nCcalls = CSTACKTHREAD; + else /* correct 'nCcalls' for this thread */ +- L->nCcalls = getCcalls(from) + from->nci - L->nci - CSTACKCF; ++ L->nCcalls = getCcalls(from) - L->nci - CSTACKCF; + if (L->nCcalls <= CSTACKERR) + return resume_error(L, "C stack overflow", nargs); + luai_userstateresume(L, nargs); diff --git a/lua-5.4.0-bug3.patch b/lua-5.4.0-bug3.patch new file mode 100644 index 0000000..08c5a90 --- /dev/null +++ b/lua-5.4.0-bug3.patch @@ -0,0 +1,14 @@ +diff -up lua-5.4.0/src/lundump.c.bug3 lua-5.4.0/src/lundump.c +--- lua-5.4.0/src/lundump.c.bug3 2020-07-31 10:43:45.954150092 -0400 ++++ lua-5.4.0/src/lundump.c 2020-07-31 10:44:31.560159336 -0400 +@@ -205,8 +205,9 @@ static void loadUpvalues (LoadState *S, + n = loadInt(S); + f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); + f->sizeupvalues = n; +- for (i = 0; i < n; i++) { ++ for (i = 0; i < n; i++) + f->upvalues[i].name = NULL; ++ for (i = 0; i < n; i++) { + f->upvalues[i].instack = loadByte(S); + f->upvalues[i].idx = loadByte(S); + f->upvalues[i].kind = loadByte(S); diff --git a/lua-5.4.0-bug4.patch b/lua-5.4.0-bug4.patch new file mode 100644 index 0000000..7c180da --- /dev/null +++ b/lua-5.4.0-bug4.patch @@ -0,0 +1,40 @@ +diff -up lua-5.4.0/src/ldo.c.bug4 lua-5.4.0/src/ldo.c +--- lua-5.4.0/src/ldo.c.bug4 2020-07-31 10:46:01.013254618 -0400 ++++ lua-5.4.0/src/ldo.c 2020-07-31 10:47:23.423657317 -0400 +@@ -466,13 +466,13 @@ void luaD_call (lua_State *L, StkId func + f = fvalue(s2v(func)); + Cfunc: { + int n; /* number of returns */ +- CallInfo *ci = next_ci(L); ++ CallInfo *ci; + checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ ++ L->ci = ci = next_ci(L); + ci->nresults = nresults; + ci->callstatus = CIST_C; + ci->top = L->top + LUA_MINSTACK; + ci->func = func; +- L->ci = ci; + lua_assert(ci->top <= L->stack_last); + if (L->hookmask & LUA_MASKCALL) { + int narg = cast_int(L->top - func) - 1; +@@ -486,18 +486,18 @@ void luaD_call (lua_State *L, StkId func + break; + } + case LUA_VLCL: { /* Lua function */ +- CallInfo *ci = next_ci(L); ++ CallInfo *ci; + Proto *p = clLvalue(s2v(func))->p; + int narg = cast_int(L->top - func) - 1; /* number of real arguments */ + int nfixparams = p->numparams; + int fsize = p->maxstacksize; /* frame size */ + checkstackp(L, fsize, func); ++ L->ci = ci = next_ci(L); + ci->nresults = nresults; + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus = 0; + ci->top = func + 1 + fsize; + ci->func = func; +- L->ci = ci; + for (; narg < nfixparams; narg++) + setnilvalue(s2v(L->top++)); /* complete missing arguments */ + lua_assert(ci->top <= L->stack_last); diff --git a/lua-5.4.0-bug5.patch b/lua-5.4.0-bug5.patch new file mode 100644 index 0000000..2579566 --- /dev/null +++ b/lua-5.4.0-bug5.patch @@ -0,0 +1,12 @@ +diff -up lua-5.4.0/src/ldo.h.bug5 lua-5.4.0/src/ldo.h +--- lua-5.4.0/src/ldo.h.bug5 2020-07-31 10:48:38.077398930 -0400 ++++ lua-5.4.0/src/ldo.h 2020-07-31 10:49:11.858926155 -0400 +@@ -44,7 +44,7 @@ + + /* macro to check stack size and GC */ + #define checkstackGC(L,fsize) \ +- luaD_checkstackaux(L, (fsize), (void)0, luaC_checkGC(L)) ++ luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) + + + /* type of protected functions, to be ran by 'runprotected' */ diff --git a/lua-5.4.0-bug6.patch b/lua-5.4.0-bug6.patch new file mode 100644 index 0000000..953eb32 --- /dev/null +++ b/lua-5.4.0-bug6.patch @@ -0,0 +1,22 @@ +diff -up lua-5.4.0/src/lvm.c.bug6 lua-5.4.0/src/lvm.c +--- lua-5.4.0/src/lvm.c.bug6 2020-07-31 10:50:38.760137542 -0400 ++++ lua-5.4.0/src/lvm.c 2020-07-31 10:51:39.284498878 -0400 +@@ -1104,7 +1104,7 @@ void luaV_finishOp (lua_State *L) { + + + #define checkGC(L,c) \ +- { luaC_condGC(L, L->top = (c), /* limit of live values */ \ ++ { luaC_condGC(L, (savepc(L), L->top = (c)), \ + updatetrap(ci)); \ + luai_threadyield(L); } + +@@ -1792,8 +1792,7 @@ void luaV_execute (lua_State *L, CallInf + vmbreak; + } + vmcase(OP_VARARGPREP) { +- luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p); +- updatetrap(ci); ++ ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); + if (trap) { + luaD_hookcall(L, ci); + L->oldpc = 1; /* next opcode will be seen as a "new" line */ diff --git a/lua-5.4.0-bug7.patch b/lua-5.4.0-bug7.patch new file mode 100644 index 0000000..83c2f1e --- /dev/null +++ b/lua-5.4.0-bug7.patch @@ -0,0 +1,12 @@ +diff -up lua-5.4.0/src/liolib.c.bug7 lua-5.4.0/src/liolib.c +--- lua-5.4.0/src/liolib.c.bug7 2020-07-31 10:53:20.857070633 -0400 ++++ lua-5.4.0/src/liolib.c 2020-07-31 10:53:58.694421042 -0400 +@@ -279,6 +279,8 @@ static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newprefile(L); ++ luaL_argcheck(L, ((mode[0] == 'r' || mode[0] == 'w') && mode[1] == '\0'), ++ 2, "invalid mode"); + p->f = l_popen(L, filename, mode); + p->closef = &io_pclose; + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; diff --git a/lua-5.4.0-bug8.patch b/lua-5.4.0-bug8.patch new file mode 100644 index 0000000..dc9e9c7 --- /dev/null +++ b/lua-5.4.0-bug8.patch @@ -0,0 +1,12 @@ +diff -up lua-5.4.0/src/lgc.c.bug8 lua-5.4.0/src/lgc.c +--- lua-5.4.0/src/lgc.c.bug8 2020-07-31 10:55:37.427116603 -0400 ++++ lua-5.4.0/src/lgc.c 2020-07-31 10:57:04.639314417 -0400 +@@ -856,6 +856,8 @@ static void GCTM (lua_State *L) { + if (unlikely(status != LUA_OK)) { /* error while running __gc? */ + luaE_warnerror(L, "__gc metamethod"); + L->top--; /* pops error object */ ++ if (isLua(L->ci)) ++ L->oldpc = L->ci->u.l.savedpc; /* update 'oldpc' */ + } + } + } diff --git a/lua.spec b/lua.spec index 26ea1bf..0cc9c16 100644 --- a/lua.spec +++ b/lua.spec @@ -15,7 +15,7 @@ Name: lua Version: %{major_version}.0 -Release: 3%{?dist} +Release: 4%{?dist} Summary: Powerful light-weight programming language License: MIT URL: http://www.lua.org/ @@ -41,6 +41,17 @@ Patch4: %{name}-5.3.0-configure-compat-module.patch Patch5: %{name}-5.3.0-autotoolize.patch Patch6: %{name}-5.3.5-luac-shared-link-fix.patch %endif +Patch7: %{name}-5.4.0-CVE-2020-15889.patch +Patch8: %{name}-5.4.0-CVE-2020-15945.patch +# https://www.lua.org/bugs.html +# Bug 1 is CVE-2020-15889 +Patch9: %{name}-5.4.0-bug2.patch +Patch10: %{name}-5.4.0-bug3.patch +Patch11: %{name}-5.4.0-bug4.patch +Patch12: %{name}-5.4.0-bug5.patch +Patch13: %{name}-5.4.0-bug6.patch +Patch14: %{name}-5.4.0-bug7.patch +Patch15: %{name}-5.4.0-bug8.patch BuildRequires: automake autoconf libtool readline-devel ncurses-devel Requires: lua-libs = %{version}-%{release} @@ -91,6 +102,15 @@ mv src/luaconf.h src/luaconf.h.template.in #%% patch2 -p1 -z .luac-shared %patch3 -p1 -z .configure-linux %patch4 -p1 -z .configure-compat-all +%patch7 -p1 -b .CVE-2020-15889 +%patch8 -p1 -b .CVE-2020-15945 +%patch9 -p1 -b .bug2 +%patch10 -p1 -b .bug3 +%patch11 -p1 -b .bug4 +%patch12 -p1 -b .bug5 +%patch13 -p1 -b .bug6 +%patch14 -p1 -b .bug7 +%patch15 -p1 -b .bug8 # Put proper version in configure.ac, patch0 hardcodes 5.3.0 sed -i 's|5.3.0|%{version}|g' configure.ac autoreconf -ifv @@ -216,6 +236,11 @@ install -Dpm 0644 %{SOURCE1001} $RPM_BUILD_ROOT/%{_fileattrsdir}/lua.attr %changelog +* Fri Jul 31 2020 Tom Callaway - 5.4.0-4 +- apply upstream fix for CVE-2020-15889 +- apply upstream fix for CVE-2020-15945 +- apply upstream fixes for "known bugs" + * Tue Jul 28 2020 Fedora Release Engineering - 5.4.0-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild