summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordormando <dormando@rydia.net>2022-12-01 22:03:11 -0800
committerdormando <dormando@rydia.net>2022-12-01 22:03:11 -0800
commit683bb98a55ba19f69c4e2a60b9104ed2edc971c3 (patch)
treef5795b64e0433b8ccd21d56f5005af0bf66219d3
parent5468b726004aa9651ad77ec3db2dbb9859137b53 (diff)
downloadmemcached-683bb98a55ba19f69c4e2a60b9104ed2edc971c3.tar.gz
proxy: lua registry corruption on data chunk error
This was a nightmare to debug; I need some better tools here. 1) There's a helper routine that ensures the lua coroutine is cleared up if an error happens while handling the network/etc. 2) On reading the value data from a set request, there's one last error that can happen before the coroutine ownership is taken from the connection object. 3) The bug was the set read completion code was unreferencing the coroutine, but could still throw an error if the set data was malformed. 4) Thus it would double free the reference. 5) Then really weird things wout happen to the registry: the same reference ID would get handed out twice. 6) This blows up code later on as it gets data it doesn't expect, and some referenced objects get clobbered. 7) This was triggered in combination of an earlier bug that would cause bad data chunks on short writes in certain situations. Took a long time to get a repro case outside of a benchmark; was looking in the wrong place.
-rw-r--r--proto_proxy.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/proto_proxy.c b/proto_proxy.c
index 95c9de1..5a40c7d 100644
--- a/proto_proxy.c
+++ b/proto_proxy.c
@@ -419,8 +419,9 @@ void complete_nread_proxy(conn *c) {
conn_set_state(c, conn_new_cmd);
// Grab our coroutine.
+ // Leave the reference alone in case we error out, so the conn cleanup
+ // routine can handle it properly.
lua_rawgeti(L, LUA_REGISTRYINDEX, c->proxy_coro_ref);
- luaL_unref(L, LUA_REGISTRYINDEX, c->proxy_coro_ref);
lua_State *Lc = lua_tothread(L, -1);
mcp_request_t *rq = luaL_checkudata(Lc, -1, "mcp.request");
@@ -439,6 +440,7 @@ void complete_nread_proxy(conn *c) {
rq->pr.vbuf = c->item;
c->item = NULL;
c->item_malloced = false;
+ luaL_unref(L, LUA_REGISTRYINDEX, c->proxy_coro_ref);
c->proxy_coro_ref = 0;
proxy_run_coroutine(Lc, c->resp, NULL, c);