BUG/MEDIUM: spoe: Let an agent outlive its applets during a backend deletion
The deletion of a backend holding a SPOE filter destroys the SPOE agent with
the filter deinitialization. But the agent owns an internal frontend proxy,
with its streams and the SPOE applets processing its frames, which are not
attached to the filtered backend: they may outlive the last stream of this
backend, so the agent may be freed while its applets, and the streams of its
applets, still reference it. This is a use-after-free, reachable with the
"del backend" CLI command: no server is required on the filtered backend and
the SPOE streams are attached to the internal frontend of the agent, so an
unpublished backend without attached stream can be deleted while its agent
is still processing frames.
Add a reference count on the SPOE agent: the filter configuration owns one
reference, dropped during its deinitialization, and each applet holds one,
taken when it is created and dropped when its applet context is destroyed,
with the new applet destroy callback. The agent is released when its last
reference is dropped. A backend holding a SPOE filter can now be deleted at
any time: its agents stay alive as long as their filter configuration and
their applets reference them.
The applet reference cannot be dropped with the applet release callback: it
may run during the processing of the applet stream, which may then be
requeued for a last run, for instance while the connection to the agent is
being closed, and dereference the agent internal frontend again, for the log
message of its close for instance. The applet destroy callback is used
instead: it runs during the teardown of the applet stream, from sc_destroy()
inside stream_free(). So the applet stream is guaranteed to never run again.
The internal frontend of the agent, previously embedded in the agent
structure and initialized with setup_new_proxy(), is now allocated with
alloc_new_proxy(), like any other internal proxy, and released with
proxy_drop(), when the agent is released. It may then survive its agent,
which is released during the teardown of the streams of its last applets:
the streams attached to the frontend hold a reference on it during their own
teardown. So the frontend is released after the teardown of its last stream
completed.
This will also be needed for the dynamically created backends, which will be
able to inherit an active SPOE filter instance from their defaults section
and are meant to be deleted at any time.
This patch relies on:
* MINOR: applet: Add a destroy callback to the applets
* MEDIUM: stream: Hold a reference on the frontend during stream_free()
This patch should be backported as far as 3.3 with commits above but only
after a period of observation.