From: Willy Tarreau Date: Mon, 21 Aug 2023 09:17:10 +0000 (+0200) Subject: DOC: ssl: add some comments about the non-obvious session allocation stuff X-Git-Tag: v2.9-dev5~94 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bc31ef08964dad1a1de0d7c2c283861dcfdc167b;p=thirdparty%2Fhaproxy.git DOC: ssl: add some comments about the non-obvious session allocation stuff The SSL session allocation/reuse part is far from being trivial, and there are some necessary tricks such as allocating then immediately freeing that are required by the API due to internal refcount. All of this is particularly hard to grasp, even with the scarce man pages. Let's document a little bit what's granted and expected along this path to help the reader later. --- diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 5c4f584ba1..141d8c9735 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -4273,6 +4273,7 @@ static int ssl_sess_new_srv_cb(SSL *ssl, SSL_SESSION *sess) unsigned char *ptr; const char *sni; + /* determine the required len to store this new session */ len = i2d_SSL_SESSION(sess, NULL); sni = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.lock); @@ -4286,9 +4287,13 @@ static int ssl_sess_new_srv_cb(SSL *ssl, SSL_SESSION *sess) s->ssl_ctx.reused_sess[tid].ptr = ptr; s->ssl_ctx.reused_sess[tid].allocated_size = len; } + if (s->ssl_ctx.reused_sess[tid].ptr) { - s->ssl_ctx.reused_sess[tid].size = i2d_SSL_SESSION(sess, - &ptr); + /* store the new session into ptr and advance it; save the + * resulting size. It's guaranteed to be equal to the returned + * len above, and the pointer to be advanced by as much. + */ + s->ssl_ctx.reused_sess[tid].size = i2d_SSL_SESSION(sess, &ptr); } if (s->ssl_ctx.reused_sess[tid].sni) { @@ -5703,12 +5708,19 @@ static int ssl_sock_init(struct connection *conn, void **xprt_ctx) SSL_set_connect_state(ctx->ssl); HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &(__objt_server(conn->target)->ssl_ctx.lock)); if (__objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr) { + /* let's recreate a session from (ptr,size) and assign + * it to ctx->ssl. Its refcount will be updated by the + * creation and by the assignment, so after assigning + * it or failing to, we must always free it to decrement + * the refcount. + */ const unsigned char *ptr = __objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr; SSL_SESSION *sess = d2i_SSL_SESSION(NULL, &ptr, __objt_server(conn->target)->ssl_ctx.reused_sess[tid].size); if (sess && !SSL_set_session(ctx->ssl, sess)) { SSL_SESSION_free(sess); ha_free(&__objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr); } else if (sess) { + /* already assigned, not needed anymore */ SSL_SESSION_free(sess); } }