]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: lua: resume Channel:send() from the unsent part of the string
authorAurelien DARRAGON <adarragon@haproxy.com>
Thu, 6 Aug 2026 07:39:06 +0000 (09:39 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 10 Aug 2026 08:20:05 +0000 (10:20 +0200)
hlua_channel_send_yield() keeps in <l> the number of bytes already pushed
into the channel across yields, and correctly limits the amount it tries
to push next to the remaining "sz - l" bytes. But it always passed the
beginning of the string to _hlua_channel_insert(), so after a partial
write the same prefix was sent again instead of the remainder.

For a Lua script calling Channel:send() with more data than the channel
can currently hold, the peer therefore receives the beginning of the
buffer twice and never sees its tail. Any protocol framing carried over
that stream is silently desynchronized, and the script has no way to
notice since the returned count is correct.

Let's advance the source pointer by the number of bytes already sent, as
the applet send paths do.

This was introduced in 2.5 by commit a1ac5fb28 ("MEDIUM: filters/lua: Be
prepared to filter TCP payloads"). It must be backported to all stable
versions.

Reported-by: Claude (ANT-2026-GQE208VX)
src/hlua.c

index 1f62dc53e98727aefd0b39141683c10bc52b671d..1958da548d5e454c4f5e64eb3a1870b1e403f9bb 100644 (file)
@@ -4591,7 +4591,8 @@ __LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext
                len = sz - l;
        }
 
-       ret = _hlua_channel_insert(chn, L, ist2(str, len), offset);
+       /* <l> bytes were already sent by a previous pass, resume from there */
+       ret = _hlua_channel_insert(chn, L, ist2(str + l, len), offset);
        if (ret == -1) {
                lua_pop(L, 1);
                lua_pushinteger(L, -1);