]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: stream: fix session leak on applet-initiated connections
authorWilly Tarreau <w@1wt.eu>
Wed, 29 Nov 2017 13:05:38 +0000 (14:05 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 29 Nov 2017 13:26:11 +0000 (14:26 +0100)
Commit 3e13cba ("MEDIUM: session: make use of the connection's destroy
callback") ensured that connections could be autonomous to destroy the
session they initiated, but it didn't take care of doing the same for
applets. Such applets are used for peers, Lua and SPOE outgoing
connections. In this case, once the stream ends, it closes everything
and nothing takes care of releasing the session. The problem is not
immediately obvious since the only visible effect is that older
processes will not quit on reload after having leaked one such session.

For now we check in stream_free() if the session's origin is the applet
we're releasing, and then free the session as well. Something more
uniform should probably be done once we manage to unify applets and
connections a bit more.

This fix needs to be backported to 1.8. Thanks to Emmanuel Hocdet for
reporting the problem.

src/stream.c

index 7d7910d9453ccf670eea59dc1be1c5f9d41b00cd..32da7c2e3527e14998cc2aa2a073b6033fe480e7 100644 (file)
@@ -297,6 +297,7 @@ static void stream_free(struct stream *s)
        struct proxy *fe = sess->fe;
        struct bref *bref, *back;
        struct conn_stream *cli_cs = objt_cs(s->si[0].end);
+       int must_free_sess;
        int i;
 
        if (s->pend_pos)
@@ -388,12 +389,15 @@ static void stream_free(struct stream *s)
        LIST_DEL(&s->list);
        HA_SPIN_UNLOCK(STRMS_LOCK, &streams_lock);
 
+       /* applets do not release session yet */
+       must_free_sess = objt_appctx(sess->origin) && sess->origin == s->si[0].end;
+
        si_release_endpoint(&s->si[1]);
        si_release_endpoint(&s->si[0]);
 
-       /* FIXME: for now we have a 1:1 relation between stream and session so
-        * the stream must free the session.
-        */
+       if (must_free_sess)
+               session_free(sess);
+
        pool_free(pool_head_stream, s);
 
        /* We may want to free the maximum amount of pools if the proxy is stopping */