BUG/MEDIUM: hlua: Never release a cosocket applet from the GC
The commit
38534d344b ("BUG/MEDIUM: hlua: Be able to garbage collect
uninitialized lua sockets") introduced a regression, leading to UAF
accesses.
Indeed, with a shared lua state, the garbage collector can be run on any
thread. So for a script using cosocket loaded via "lua-load" directive, the
lua socket garbage collector can run on any thread. So here there were two
problems:
* appctx_free() must only be called by the thread owning the applet. It
destroys the applet's task and releases the memory to the thread-local
pool cache. Here it was possible to call appctx_free() from any other
thread.
* All other accesses to the applet's context were performed after the xref
was disconnected. However, once disconnected, the applet is free to be
released at any instant by the thread owning it, because
hlua_socket_release() no longer finds any peer. Because the cosocket
context is part of the applet's context, this was a use-after-free.
So now, the GC only signals the applet it must die and wakes it up, exactly
like hlua_socket_close_helper() already does, and it does so before
disconnecting the xref. This way:
* The applet is always released by the thread owning it.
* Because the work is performed before the xref is disconnected, a
concurrent hlua_socket_release() is stalled on the xref lock and cannot
release the applet in our back.
Note this also fixes the same issue in hlua_socket_close_helper(), which
still wakes up a possibly uninitialized applet. Closing a lua socket that
was never connected ("core.tcp():close()") should be enough to trigger it.
Thank you to Red Hat and AISLE Research for reporting this.
This patch must be backported to all stable versions containing the commit
38534d344b, so as far as 2.6.