diff --git a/backport-Bug-Loading-a-corrupted-binary-file-can-segfault.patch b/backport-Bug-Loading-a-corrupted-binary-file-can-segfault.patch new file mode 100644 index 0000000000000000000000000000000000000000..8696ecdca681d5b94f2b8cf91187651f329ce385 --- /dev/null +++ b/backport-Bug-Loading-a-corrupted-binary-file-can-segfault.patch @@ -0,0 +1,79 @@ +From ab859fe59b464a038a45552921cb2b23892343af Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Fri, 17 Mar 2023 15:52:09 -0300 +Subject: [PATCH] Bug: Loading a corrupted binary file can segfault + +The size of the list of upvalue names are stored separated from the +size of the list of upvalues, but they share the same array. +--- + lua-5.4.3-tests/calls.lua | 14 ++++++++++++++ + src/ldump.c | 8 ++++++-- + src/lundump.c | 2 ++ + 3 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/lua-5.4.3-tests/calls.lua b/lua-5.4.3-tests/calls.lua +index ff72d8f..65b6858 100644 +--- a/lua-5.4.3-tests/calls.lua ++++ b/lua-5.4.3-tests/calls.lua +@@ -327,6 +327,20 @@ do -- another bug (in 5.4.0) + end + + ++do -- another bug (since 5.2) ++ -- corrupted binary dump: list of upvalue names is larger than number ++ -- of upvalues, overflowing the array of upvalues. ++ local code = ++ "\x1b\x4c\x75\x61\x54\x00\x19\x93\x0d\x0a\x1a\x0a\x04\x08\x08\x78\x56\z ++ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x77\x40\x00\x86\x40\z ++ \x74\x65\x6d\x70\x81\x81\x01\x00\x02\x82\x48\x00\x02\x00\xc7\x00\x01\z ++ \x00\x80\x80\x80\x82\x00\x00\x80\x81\x82\x78\x80\x82\x81\x86\x40\x74\z ++ \x65\x6d\x70" ++ ++ assert(load(code)) -- segfaults in previous versions ++end ++ ++ + x = string.dump(load("x = 1; return x")) + a = assert(load(read1(x), nil, "b")) + assert(a() == 1 and _G.x == 1) +diff --git a/src/ldump.c b/src/ldump.c +index f848b66..f231691 100644 +--- a/src/ldump.c ++++ b/src/ldump.c +@@ -10,6 +10,7 @@ + #include "lprefix.h" + + ++#include + #include + + #include "lua.h" +@@ -55,8 +56,11 @@ static void dumpByte (DumpState *D, int y) { + } + + +-/* dumpInt Buff Size */ +-#define DIBS ((sizeof(size_t) * 8 / 7) + 1) ++/* ++** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6" ++** rounds up the division.) ++*/ ++#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7) + + static void dumpSize (DumpState *D, size_t x) { + lu_byte buff[DIBS]; +diff --git a/src/lundump.c b/src/lundump.c +index 5aa55c4..8013e66 100644 +--- a/src/lundump.c ++++ b/src/lundump.c +@@ -248,6 +248,8 @@ static void loadDebug (LoadState *S, Proto *f) { + f->locvars[i].endpc = loadInt(S); + } + n = loadInt(S); ++ if (n != 0) /* does it have debug information? */ ++ n = f->sizeupvalues; /* must be this many */ + for (i = 0; i < n; i++) + f->upvalues[i].name = loadStringN(S, f); + } +-- +2.33.0 diff --git a/backport-Bug-Recursion-in-getobjname-can-stack-overflow.patch b/backport-Bug-Recursion-in-getobjname-can-stack-overflow.patch new file mode 100644 index 0000000000000000000000000000000000000000..96e36d9ccf08340a2badee1ff40d23f3e6874301 --- /dev/null +++ b/backport-Bug-Recursion-in-getobjname-can-stack-overflow.patch @@ -0,0 +1,232 @@ +From 7923dbbf72da303ca1cca17efd24725668992f15 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Wed, 1 Nov 2023 12:00:54 -0300 +Subject: [PATCH] Bug: Recursion in 'getobjname' can stack overflow + +'getobjname' now broken in two, a basic version that handles locals, +upvalues, and constants, and a full version, which uses the basic +version to handle table accesses (globals and fields). +--- + lua-5.4.3-tests/errors.lua | 3 + + src/ldebug.c | 154 ++++++++++++++++++++----------------- + 2 files changed, 87 insertions(+), 70 deletions(-) + +diff --git a/lua-5.4.3-tests/errors.lua b/lua-5.4.3-tests/errors.lua +index a3d0676..5cef9e1 100644 +--- a/lua-5.4.3-tests/errors.lua ++++ b/lua-5.4.3-tests/errors.lua +@@ -121,6 +121,9 @@ assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'")) + checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number") + checkmessage("a=(1)..{}", "a table value") + ++-- bug in 5.4.6 ++checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'") ++ + -- calls + checkmessage("local a; a(13)", "local 'a'") + checkmessage([[ +diff --git a/src/ldebug.c b/src/ldebug.c +index 5524fae..c605a8a 100644 +--- a/src/ldebug.c ++++ b/src/ldebug.c +@@ -416,41 +416,6 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + ** ======================================================= + */ + +-static const char *getobjname (const Proto *p, int lastpc, int reg, +- const char **name); +- +- +-/* +-** Find a "name" for the constant 'c'. +-*/ +-static void kname (const Proto *p, int c, const char **name) { +- TValue *kvalue = &p->k[c]; +- *name = (ttisstring(kvalue)) ? svalue(kvalue) : "?"; +-} +- +- +-/* +-** Find a "name" for the register 'c'. +-*/ +-static void rname (const Proto *p, int pc, int c, const char **name) { +- const char *what = getobjname(p, pc, c, name); /* search for 'c' */ +- if (!(what && *what == 'c')) /* did not find a constant name? */ +- *name = "?"; +-} +- +- +-/* +-** Find a "name" for a 'C' value in an RK instruction. +-*/ +-static void rkname (const Proto *p, int pc, Instruction i, const char **name) { +- int c = GETARG_C(i); /* key index */ +- if (GETARG_k(i)) /* is 'c' a constant? */ +- kname(p, c, name); +- else /* 'c' is a register */ +- rname(p, pc, c, name); +-} +- +- + static int filterpc (int pc, int jmptarget) { + if (pc < jmptarget) /* is code conditional (inside a jump)? */ + return -1; /* cannot know who sets that register */ +@@ -508,28 +473,29 @@ static int findsetreg (const Proto *p, int lastpc, int reg) { + + + /* +-** Check whether table being indexed by instruction 'i' is the +-** environment '_ENV' ++** Find a "name" for the constant 'c'. + */ +-static const char *gxf (const Proto *p, int pc, Instruction i, int isup) { +- int t = GETARG_B(i); /* table index */ +- const char *name; /* name of indexed variable */ +- if (isup) /* is an upvalue? */ +- name = upvalname(p, t); +- else +- getobjname(p, pc, t, &name); +- return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; ++static const char *kname (const Proto *p, int index, const char **name) { ++ TValue *kvalue = &p->k[index]; ++ if (ttisstring(kvalue)) { ++ *name = getstr(tsvalue(kvalue)); ++ return "constant"; ++ } ++ else { ++ *name = "?"; ++ return NULL; ++ } + } + + +-static const char *getobjname (const Proto *p, int lastpc, int reg, +- const char **name) { +- int pc; +- *name = luaF_getlocalname(p, reg + 1, lastpc); ++static const char *basicgetobjname (const Proto *p, int *ppc, int reg, ++ const char **name) { ++ int pc = *ppc; ++ *name = luaF_getlocalname(p, reg + 1, pc); + if (*name) /* is a local? */ + return "local"; + /* else try symbolic execution */ +- pc = findsetreg(p, lastpc, reg); ++ *ppc = pc = findsetreg(p, pc, reg); + if (pc != -1) { /* could find instruction? */ + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); +@@ -537,18 +503,80 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, + case OP_MOVE: { + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (b < GETARG_A(i)) +- return getobjname(p, pc, b, name); /* get name for 'b' */ ++ return basicgetobjname(p, ppc, b, name); /* get name for 'b' */ + break; + } ++ case OP_GETUPVAL: { ++ *name = upvalname(p, GETARG_B(i)); ++ return "upvalue"; ++ } ++ case OP_LOADK: return kname(p, GETARG_Bx(i), name); ++ case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name); ++ default: break; ++ } ++ } ++ return NULL; /* could not find reasonable name */ ++} ++ ++ ++/* ++** Find a "name" for the register 'c'. ++*/ ++static void rname (const Proto *p, int pc, int c, const char **name) { ++ const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */ ++ if (!(what && *what == 'c')) /* did not find a constant name? */ ++ *name = "?"; ++} ++ ++ ++/* ++** Find a "name" for a 'C' value in an RK instruction. ++*/ ++static void rkname (const Proto *p, int pc, Instruction i, const char **name) { ++ int c = GETARG_C(i); /* key index */ ++ if (GETARG_k(i)) /* is 'c' a constant? */ ++ kname(p, c, name); ++ else /* 'c' is a register */ ++ rname(p, pc, c, name); ++} ++ ++ ++/* ++** Check whether table being indexed by instruction 'i' is the ++** environment '_ENV' ++*/ ++static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) { ++ int t = GETARG_B(i); /* table index */ ++ const char *name; /* name of indexed variable */ ++ if (isup) /* is 't' an upvalue? */ ++ name = upvalname(p, t); ++ else /* 't' is a register */ ++ basicgetobjname(p, &pc, t, &name); ++ return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; ++} ++ ++ ++/* ++** Extend 'basicgetobjname' to handle table accesses ++*/ ++static const char *getobjname (const Proto *p, int lastpc, int reg, ++ const char **name) { ++ const char *kind = basicgetobjname(p, &lastpc, reg, name); ++ if (kind != NULL) ++ return kind; ++ else if (lastpc != -1) { /* could find instruction? */ ++ Instruction i = p->code[lastpc]; ++ OpCode op = GET_OPCODE(i); ++ switch (op) { + case OP_GETTABUP: { + int k = GETARG_C(i); /* key index */ + kname(p, k, name); +- return gxf(p, pc, i, 1); ++ return isEnv(p, lastpc, i, 1); + } + case OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ +- rname(p, pc, k, name); +- return gxf(p, pc, i, 0); ++ rname(p, lastpc, k, name); ++ return isEnv(p, lastpc, i, 0); + } + case OP_GETI: { + *name = "integer index"; +@@ -557,24 +585,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, + case OP_GETFIELD: { + int k = GETARG_C(i); /* key index */ + kname(p, k, name); +- return gxf(p, pc, i, 0); +- } +- case OP_GETUPVAL: { +- *name = upvalname(p, GETARG_B(i)); +- return "upvalue"; +- } +- case OP_LOADK: +- case OP_LOADKX: { +- int b = (op == OP_LOADK) ? GETARG_Bx(i) +- : GETARG_Ax(p->code[pc + 1]); +- if (ttisstring(&p->k[b])) { +- *name = svalue(&p->k[b]); +- return "constant"; +- } +- break; ++ return isEnv(p, lastpc, i, 0); + } + case OP_SELF: { +- rkname(p, pc, i, name); ++ rkname(p, lastpc, i, name); + return "method"; + } + default: break; /* go through to return NULL */ +-- +2.33.0 \ No newline at end of file diff --git a/backport-Bug-stack-overflow-with-nesting-of-coroutine.close.patch b/backport-Bug-stack-overflow-with-nesting-of-coroutine.close.patch new file mode 100644 index 0000000000000000000000000000000000000000..60d9439ee766c1088b01059aae0d1839babe7a89 --- /dev/null +++ b/backport-Bug-stack-overflow-with-nesting-of-coroutine.close.patch @@ -0,0 +1,116 @@ +From 1e64c1391f9a14115b5cc82066dbf545ae73ee27 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Tue, 25 Oct 2022 16:44:06 -0300 +Subject: [PATCH] Bug: stack overflow with nesting of coroutine.close + +--- + lua-5.4.3-tests/cstack.lua | 26 ++++++++++++++++++++++++++ + lua-5.4.3-tests/ltests/ltests.c | 2 +- + src/lcorolib.c | 4 ++-- + src/lstate.c | 3 ++- + src/lua.h | 2 +- + 5 files changed, 32 insertions(+), 5 deletions(-) + +diff --git a/lua-5.4.3-tests/cstack.lua b/lua-5.4.3-tests/cstack.lua +index ca76c87..97afe9f 100644 +--- a/lua-5.4.3-tests/cstack.lua ++++ b/lua-5.4.3-tests/cstack.lua +@@ -84,6 +84,32 @@ do -- bug in 5.4.0 + end + + ++do -- bug since 5.4.0 ++ local count = 0 ++ print("chain of 'coroutine.close'") ++ -- create N coroutines forming a list so that each one, when closed, ++ -- closes the previous one. (With a large enough N, previous Lua ++ -- versions crash in this test.) ++ local coro = false ++ for i = 1, 1000 do ++ local previous = coro ++ coro = coroutine.create(function() ++ local cc = setmetatable({}, {__close=function() ++ count = count + 1 ++ if previous then ++ assert(coroutine.close(previous)) ++ end ++ end}) ++ coroutine.yield() -- leaves 'cc' pending to be closed ++ end) ++ assert(coroutine.resume(coro)) -- start it and run until it yields ++ end ++ local st, msg = coroutine.close(coro) ++ assert(not st and string.find(msg, "C stack overflow")) ++ print("final count: ", count) ++end ++ ++ + do + print("nesting of resuming yielded coroutines") + local count = 0 +diff --git a/lua-5.4.3-tests/ltests/ltests.c b/lua-5.4.3-tests/ltests/ltests.c +index a50f783..ef6168b 100644 +--- a/lua-5.4.3-tests/ltests/ltests.c ++++ b/lua-5.4.3-tests/ltests/ltests.c +@@ -1533,7 +1533,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { + lua_newthread(L1); + } + else if EQ("resetthread") { +- lua_pushinteger(L1, lua_resetthread(L1)); ++ lua_pushinteger(L1, lua_resetthread(L1, L)); + } + else if EQ("newuserdata") { + lua_newuserdata(L1, getnum); +diff --git a/src/lcorolib.c b/src/lcorolib.c +index fedbebe..c62acf2 100644 +--- a/src/lcorolib.c ++++ b/src/lcorolib.c +@@ -76,7 +76,7 @@ static int luaB_auxwrap (lua_State *L) { + if (l_unlikely(r < 0)) { /* error? */ + int stat = lua_status(co); + if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ +- stat = lua_resetthread(co); /* close its tbc variables */ ++ stat = lua_resetthread(co, L); /* close its tbc variables */ + lua_assert(stat != LUA_OK); + lua_xmove(co, L, 1); /* copy error message */ + } +@@ -172,7 +172,7 @@ static int luaB_close (lua_State *L) { + int status = auxstatus(L, co); + switch (status) { + case COS_DEAD: case COS_YIELD: { +- status = lua_resetthread(co); ++ status = lua_resetthread(co, L); + if (status == LUA_OK) { + lua_pushboolean(L, 1); + return 1; +diff --git a/src/lstate.c b/src/lstate.c +index 59b4f21..4df1fd7 100644 +--- a/src/lstate.c ++++ b/src/lstate.c +@@ -343,9 +343,10 @@ int luaE_resetthread (lua_State *L, int status) { + } + + +-LUA_API int lua_resetthread (lua_State *L) { ++LUA_API int lua_resetthread (lua_State *L, lua_State *from) { + int status; + lua_lock(L); ++ L->nCcalls = (from) ? getCcalls(from) : 0; + status = luaE_resetthread(L, L->status); + lua_unlock(L); + return status; +diff --git a/src/lua.h b/src/lua.h +index 820535b..17ecfe5 100644 +--- a/src/lua.h ++++ b/src/lua.h +@@ -153,7 +153,7 @@ extern const char lua_ident[]; + LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); + LUA_API void (lua_close) (lua_State *L); + LUA_API lua_State *(lua_newthread) (lua_State *L); +-LUA_API int (lua_resetthread) (lua_State *L); ++LUA_API int (lua_resetthread) (lua_State *L, lua_State *from); + + LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + +-- +2.33.0 diff --git a/lua.spec b/lua.spec index e21c9f698bbd5db9868b8555c15241afb2bb7079..59db09f91444fdc99b06e8aa4b52100419141572 100644 --- a/lua.spec +++ b/lua.spec @@ -6,7 +6,7 @@ Name: lua Version: 5.4.3 -Release: 12 +Release: 13 Summary: A powerful, efficient, lightweight, embeddable scripting language License: MIT URL: http://www.lua.org/ @@ -38,6 +38,9 @@ Patch6011: backport-Using-inline-in-some-functions.patch Patch6012: backport-Removed-goto-s-in-luaD_precall.patch Patch6013: backport-More-uniform-implementation-for-tail-calls.patch Patch6014: backport-CVE-2021-45985.patch +Patch6015: backport-Bug-stack-overflow-with-nesting-of-coroutine.close.patch +Patch6016: backport-Bug-Loading-a-corrupted-binary-file-can-segfault.patch +Patch6017: backport-Bug-Recursion-in-getobjname-can-stack-overflow.patch BuildRequires: automake autoconf libtool readline-devel ncurses-devel @@ -85,6 +88,9 @@ mv src/luaconf.h src/luaconf.h.template.in %patch6012 -p1 %patch6013 -p1 %patch6014 -p1 +%patch6015 -p1 +%patch6016 -p1 +%patch6017 -p1 # Put proper version in configure.ac, patch0 hardcodes 5.3.0 sed -i 's|5.3.0|%{version}|g' configure.ac @@ -159,6 +165,9 @@ LD_LIBRARY_PATH=$RPM_BUILD_ROOT/%{_libdir} $RPM_BUILD_ROOT/%{_bindir}/lua -e"_U= %{_mandir}/man1/lua*.1* %changelog +* Thu Jan 18 2024 yanglongkang - 5.4.3-13 +- fix Segmentation fault + * Tue Aug 22 2023 panchenbo - 5.4.3-12 - add sw_64 support