From: Aurelien DARRAGON Date: Tue, 4 Jun 2024 08:41:32 +0000 (+0200) Subject: BUG/MINOR: hlua: prevent LJMP in hlua_traceback() X-Git-Tag: v3.1-dev1~69 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=365ee28510a11993176ffd22704676732c051a4f;p=thirdparty%2Fhaproxy.git BUG/MINOR: hlua: prevent LJMP in hlua_traceback() Function is often used on error paths where no precaution is taken against LJMP. Since the function is used on error paths (which include out-of-memory error paths) the function lua_getinfo() could also raise a memory exception, causing the process to crash or improper error handling if the caller isn't prepared against that eventually. Since the function is only used on rare events (error handling) and is lacking the __LJMP prototype pefix, let's make it safe by protecting the lua_getinfo() call so that hlua_traceback() callers may use it safely now (the function will always succeed, output will be truncated in case of error). This could be backported to all stable versions. --- diff --git a/src/hlua.c b/src/hlua.c index 528830719a..cd6619b3b7 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -848,20 +848,41 @@ void hlua_unref(lua_State *L, int ref) luaL_unref(L, LUA_REGISTRYINDEX, ref); } -__LJMP const char *hlua_traceback(lua_State *L, const char* sep) +__LJMP static int _hlua_traceback(lua_State *L) +{ + lua_Debug *ar = lua_touserdata(L, 1); + + /* Fill fields: + * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what; + * 'l': fills in the field currentline; + * 'n': fills in the field name and namewhat; + * 't': fills in the field istailcall; + */ + return lua_getinfo(L, "Slnt", ar); +} + + +/* This function cannot fail (output will simply be truncated upon errors) */ +const char *hlua_traceback(lua_State *L, const char* sep) { lua_Debug ar; int level = 0; struct buffer *msg = get_trash_chunk(); while (lua_getstack(L, level++, &ar)) { - /* Fill fields: - * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what; - * 'l': fills in the field currentline; - * 'n': fills in the field name and namewhat; - * 't': fills in the field istailcall; - */ - lua_getinfo(L, "Slnt", &ar); + if (!lua_checkstack(L, 2)) + goto end; // abort + + lua_pushcfunction(L, _hlua_traceback); + lua_pushlightuserdata(L, &ar); + + /* safe getinfo */ + switch (lua_pcall(L, 1, 1, 0)) { + case LUA_OK: + break; + default: + goto end; // abort + } /* skip these empty entries, usually they come from deep C functions */ if (ar.currentline < 0 && *ar.what == 'C' && !*ar.namewhat && !ar.name) @@ -902,6 +923,7 @@ __LJMP const char *hlua_traceback(lua_State *L, const char* sep) chunk_appendf(msg, " ..."); } + end: return msg->area; }