]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: hlua: prevent LJMP in hlua_traceback()
authorAurelien DARRAGON <adarragon@haproxy.com>
Tue, 4 Jun 2024 08:41:32 +0000 (10:41 +0200)
committerAurelien DARRAGON <adarragon@haproxy.com>
Tue, 4 Jun 2024 14:31:15 +0000 (16:31 +0200)
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.

src/hlua.c

index 528830719acedbd5f985b4d977d0d5275c8bd975..cd6619b3b7520e8dfd350bb18fa7fea0787f1fe2 100644 (file)
@@ -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;
 }