In commit
b5ee8bebfc ("MINOR: server: always call ssl->destroy_srv when
available"), we made it so srv_drop() doesn't depend on proxy to perform
server cleanup.
It turns out this is now mandatory, because during deinit, free_proxy()
can occur before the final srv_drop(). This is the case when using Lua
scripts for instance.
In
2a9436f96 ("MINOR: lbprm: Add method to deinit server and proxy") we
added a freeing check under srv_drop() that depends on the proxy.
Because of that UAF may occur during deinit when using a Lua script that
manipulate server objects.
To fix the issue, let's perform the lbprm server deinit logic under
free_proxy() directly, where the DEINIT server hooks are evaluated.
Also, to prevent similar bugs in the future, let's explicitly document
in srv_drop() that server cleanups should assume that the proxy may
already be freed.
No backport needed unless
2a9436f96 is.
while (s) {
list_for_each_entry(srvdf, &server_deinit_list, list)
srvdf->fct(s);
+
+ if (p->lbprm.server_deinit)
+ p->lbprm.server_deinit(s);
+
s = srv_drop(s);
}/* end while(s) */
* dynamic servers, its refcount is decremented first. The free operations are
* conducted only if the refcount is nul.
*
+ * A general rule is to assume that proxy may already be freed, so cleanup checks
+ * must not depend on the proxy
+ *
* As a convenience, <srv.next> is returned if srv is not NULL. It may be useful
* when calling srv_drop on the list of servers.
*/
EXTRA_COUNTERS_FREE(srv->extra_counters);
- if (srv->proxy->lbprm.server_deinit)
- srv->proxy->lbprm.server_deinit(srv);
-
ha_free(&srv);
end: