]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: hlua: Be able to garbage collect uninitialized lua sockets
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 16 Feb 2024 14:00:54 +0000 (15:00 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 16 Feb 2024 14:48:08 +0000 (15:48 +0100)
It is poosible to create a lua socket without performing any connect. In
this case, the lua socket is released because of the garbage collector.
However, the garbarge collector does not release the applet, it wakes it
up. Since commit 751b59c40b ("BUG/MEDIUM: hlua: Initialize appctx used by a
lua socket on connect only"), the applet initialization is performed on
connect. So, here, it is possible to wake an uninitialized applet. It is an
unexpected case for the applet's I/O handler, leading to a segfault because
some resources are not initialized (the stream's target in this case).

So, now, in the lua socket GC function, we take care to immediately release
uninitialized applets. At worst, the release itself is delayed. But it is
safe because we are sure the applet's I/O handler will never be executed.

In addition, we take case to increment the GC counter when the lua socket is
created. The way, uninitialized lua socket are released more quickly.

This patch should fix the issue #2451. It must be backported as far as 2.6.

src/hlua.c

index fb04602b4effd425e8c236a236aa4735d5bbac4a..dcc8b6a81cfe1ea67f85feb7dc61dbdace465ba2 100644 (file)
@@ -2434,12 +2434,19 @@ __LJMP static int hlua_socket_gc(lua_State *L)
 
        ctx = container_of(peer, struct hlua_csk_ctx, xref);
 
-       /* Set the flag which destroy the session. */
-       ctx->die = 1;
-       appctx_wakeup(ctx->appctx);
-
        /* Remove all reference between the Lua stack and the coroutine stream. */
        xref_disconnect(&socket->xref, peer);
+
+       if (se_fl_test(ctx->appctx->sedesc, SE_FL_ORPHAN)) {
+               /* The applet was never initialized, just release it */
+               appctx_free(ctx->appctx);
+       }
+       else {
+               /* Otherwise, notify it that is must die and wake it up */
+               ctx->die = 1;
+               appctx_wakeup(ctx->appctx);
+       }
+
        return 0;
 }
 
@@ -3276,8 +3283,6 @@ __LJMP static int hlua_socket_connect(struct lua_State *L)
        applet_have_more_data(appctx);
        appctx_wakeup(appctx);
 
-       hlua->gc_count++;
-
        if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
                xref_unlock(&socket->xref, peer);
                WILL_LJMP(luaL_error(L, "out of memory"));
@@ -3388,6 +3393,12 @@ __LJMP static int hlua_socket_new(lua_State *L)
        struct hlua_socket *socket;
        struct hlua_csk_ctx *ctx;
        struct appctx *appctx;
+       struct hlua *hlua;
+
+       /* Get hlua struct, or NULL if we execute from main lua state */
+       hlua = hlua_gethlua(L);
+       if (!hlua)
+               return 0;
 
        /* Check stack size. */
        if (!lua_checkstack(L, 3)) {
@@ -3427,6 +3438,8 @@ __LJMP static int hlua_socket_new(lua_State *L)
        LIST_INIT(&ctx->wake_on_write);
        LIST_INIT(&ctx->wake_on_read);
 
+       hlua->gc_count++;
+
        /* Initialise cross reference between stream and Lua socket object. */
        xref_create(&socket->xref, &ctx->xref);
        return 1;