From b5b1995f2925b2f9be4a48304ac97a38f8608648 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 10 Mar 2025 15:21:32 -0300 Subject: Checks for type 'int' added to binary header The structure 'AbsLineInfo' is hard-dumped into binary chunks, and it comprises two 'int' fields. --- ldump.c | 13 ++++++++----- lundump.c | 38 ++++++++++++++++++++++++++------------ lundump.h | 5 +++-- testes/calls.lua | 47 ++++++++++++++++++++++++++++++----------------- 4 files changed, 67 insertions(+), 36 deletions(-) diff --git a/ldump.c b/ldump.c index 71d9a5b1..54f96674 100644 --- a/ldump.c +++ b/ldump.c @@ -253,16 +253,19 @@ static void dumpFunction (DumpState *D, const Proto *f) { } +#define dumpNumInfo(D, tvar, value) \ + { tvar i = value; dumpByte(D, sizeof(tvar)); dumpVar(D, i); } + + static void dumpHeader (DumpState *D) { dumpLiteral(D, LUA_SIGNATURE); dumpByte(D, LUAC_VERSION); dumpByte(D, LUAC_FORMAT); dumpLiteral(D, LUAC_DATA); - dumpByte(D, sizeof(Instruction)); - dumpByte(D, sizeof(lua_Integer)); - dumpByte(D, sizeof(lua_Number)); - dumpInteger(D, LUAC_INT); - dumpNumber(D, LUAC_NUM); + dumpNumInfo(D, int, LUAC_INT); + dumpNumInfo(D, Instruction, LUAC_INST); + dumpNumInfo(D, lua_Integer, LUAC_INT); + dumpNumInfo(D, lua_Number, LUAC_NUM); } diff --git a/lundump.c b/lundump.c index d074a073..d53bfc9a 100644 --- a/lundump.c +++ b/lundump.c @@ -345,13 +345,29 @@ static void checkliteral (LoadState *S, const char *s, const char *msg) { } -static void fchecksize (LoadState *S, size_t size, const char *tname) { - if (loadByte(S) != size) - error(S, luaO_pushfstring(S->L, "%s size mismatch", tname)); +static l_noret numerror (LoadState *S, const char *what, const char *tname) { + const char *msg = luaO_pushfstring(S->L, "%s %s mismatch", tname, what); + error(S, msg); } -#define checksize(S,t) fchecksize(S,sizeof(t),#t) +static void checknumsize (LoadState *S, int size, const char *tname) { + if (size != loadByte(S)) + numerror(S, "size", tname); +} + + +static void checknumformat (LoadState *S, int eq, const char *tname) { + if (!eq) + numerror(S, "format", tname); +} + + +#define checknum(S,tvar,value,tname) \ + { tvar i; checknumsize(S, sizeof(i), tname); \ + loadVar(S, i); \ + checknumformat(S, i == value, tname); } + static void checkHeader (LoadState *S) { /* skip 1st char (already read and checked) */ @@ -361,13 +377,10 @@ static void checkHeader (LoadState *S) { if (loadByte(S) != LUAC_FORMAT) error(S, "format mismatch"); checkliteral(S, LUAC_DATA, "corrupted chunk"); - checksize(S, Instruction); - checksize(S, lua_Integer); - checksize(S, lua_Number); - if (loadInteger(S) != LUAC_INT) - error(S, "integer format mismatch"); - if (loadNumber(S) != LUAC_NUM) - error(S, "float format mismatch"); + checknum(S, int, LUAC_INT, "int"); + checknum(S, Instruction, LUAC_INST, "instruction"); + checknum(S, lua_Integer, LUAC_INT, "Lua integer"); + checknum(S, lua_Number, LUAC_NUM, "Lua number"); } @@ -398,7 +411,8 @@ LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) { cl->p = luaF_newproto(L); luaC_objbarrier(L, cl, cl->p); loadFunction(&S, cl->p); - lua_assert(cl->nupvalues == cl->p->sizeupvalues); + if (cl->nupvalues != cl->p->sizeupvalues) + error(&S, "corrupted chunk"); luai_verifycode(L, cl->p); L->top.p--; /* pop table */ return cl; diff --git a/lundump.h b/lundump.h index 1d6e50ea..c4e06f9e 100644 --- a/lundump.h +++ b/lundump.h @@ -17,8 +17,9 @@ /* data to catch conversion errors */ #define LUAC_DATA "\x19\x93\r\n\x1a\n" -#define LUAC_INT 0x5678 -#define LUAC_NUM cast_num(370.5) +#define LUAC_INT -0x5678 +#define LUAC_INST 0x12345678 +#define LUAC_NUM cast_num(-370.5) /* ** Encode major-minor version in one byte, one nibble for each diff --git a/testes/calls.lua b/testes/calls.lua index 31028215..8b355957 100644 --- a/testes/calls.lua +++ b/testes/calls.lua @@ -480,15 +480,22 @@ assert((function (a) return a end)() == nil) print("testing binary chunks") do - local header = string.pack("c4BBc6BBB", - "\27Lua", -- signature - 0x55, -- version 5.5 (0x55) - 0, -- format - "\x19\x93\r\n\x1a\n", -- data - 4, -- size of instruction - string.packsize("j"), -- sizeof(lua integer) - string.packsize("n") -- sizeof(lua number) - ) + local headformat = "c4BBc6BiBI4BjBn" + local header = { -- header components + "\27Lua", -- signature + 0x55, -- version 5.5 (0x55) + 0, -- format + "\x19\x93\r\n\x1a\n", -- a binary string + string.packsize("i"), -- size of an int + -0x5678, -- an int + 4, -- size of an instruction + 0x12345678, -- an instruction (4 bytes) + string.packsize("j"), -- size of a Lua integer + -0x5678, -- a Lua integer + string.packsize("n"), -- size of a Lua float + -370.5, -- a Lua float + } + local c = string.dump(function () local a = 1; local b = 3; local f = function () return a + b + _ENV.c; end -- upvalues @@ -500,17 +507,23 @@ do assert(assert(load(c))() == 10) -- check header - assert(string.sub(c, 1, #header) == header) - -- check LUAC_INT and LUAC_NUM - local ci, cn = string.unpack("jn", c, #header + 1) - assert(ci == 0x5678 and cn == 370.5) - - -- corrupted header + local t = {string.unpack(headformat, c)} for i = 1, #header do + assert(t[i] == header[i]) + end + + -- Testing corrupted header. + -- A single wrong byte in the head invalidates the chunk, + -- except for the Lua float check. (If numbers are long double, + -- the representation may need padding, and changing that padding + -- will not invalidate the chunk.) + local headlen = string.packsize(headformat) + headlen = headlen - string.packsize("n") -- remove float check + for i = 1, headlen do local s = string.sub(c, 1, i - 1) .. - string.char(string.byte(string.sub(c, i, i)) + 1) .. + string.char((string.byte(string.sub(c, i, i)) + 1) & 0xFF) .. string.sub(c, i + 1, -1) - assert(#s == #c) + assert(#s == #c and s ~= c) assert(not load(s)) end -- cgit v1.2.3-55-g6feb