]> git.kaiwu.me - haproxy.git/commit
BUG/MEDIUM: sink: do not hold the sft lock around ring_dispatch_messages()
authorWilly Tarreau <w@1wt.eu>
Tue, 25 Aug 2026 15:53:45 +0000 (17:53 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 25 Aug 2026 16:40:15 +0000 (18:40 +0200)
commitd7ad27e4e48e4b28b06e415f12e5330fd12b720d
tree93ab37a33b4056d30b81ce970172f648f4a3fd58
parentfaabedec2330e5307dccadf02d2b4a8b73e8a645
BUG/MEDIUM: sink: do not hold the sft lock around ring_dispatch_messages()

Attaching a reader to a ring is done under thread_isolate(), which was
added by commit 31b93b40b ("MEDIUM: ring: protect the initialization of
the initial reader offset"). But _sink_forward_io_handler() calls
ring_dispatch_messages() with the sft lock held, where on the very first
call for a given sft, a thread isolates itself while holding that lock!
Needles to say that if a second thread tries to emit a lock during that
tiny time frame, it's a guaranted deadlock!

The lock is not needed around that call: sft->ofs and sft->e_processed
are only ever accessed from this applet, which is bound to a single
thread, and both lists involved are mt_lists that protect themselves.
What the lock really protects is sft->appctx, whose publication by
process_sink_forward() is asynchronous, and that is already dealt with
by sink_forward_session_init(), which runs before the first call to the
I/O handler. So let's simply take the lock after the dispatch. In fact
that lock is a leftover from 2.2's commit 494c505703 ("MEDIUM: ring:
add server statement to forward messages from a ring") which duplicated
the dispatching code inside the function's body, so when this was cleaned
up in 3.0 with commit c262442b1a ("MEDIUM: sink: move the generic ring
forwarder code use ring_dispatch_messages()"), it was not noticed that
this lock could now cause harm.

This should be backported to 3.0.
src/sink.c