From 7d392a592d5341df43086a2a48f34658b0ba432f Mon Sep 17 00:00:00 2001 From: Emeric Brun Date: Fri, 1 Jul 2022 17:36:50 +0200 Subject: [PATCH] BUG/MEDIUM: ssl/fd: unexpected fd close using async engine Before 2.3, after an async crypto processing or on session close, the engine async file's descriptors were removed from the fdtab but not closed because it is the engine which has created the file descriptor, and it is responsible for closing it. In 2.3 the fd_remove() call was replaced by fd_stop_both() which stops the polling but does not remove the fd from the fdtab and the fd remains indefinitively in the fdtab. A simple replacement by fd_delete() is not a valid fix because fd_delete() removes the fd from the fdtab but also closes the fd. And the fd will be closed twice: by the haproxy's core and by the engine itself. Instead, let's set FD_DISOWN on the FD before calling fd_delete() which will take care of not closing it. This patch must be backported on branches >= 2.3, and it relies on this previous patch: MINOR: fd: add a new FD_DISOWN flag to prevent from closing a deleted FD As mentioned in the patch above, a different flag will be needed in 2.3. --- src/ssl_sock.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/ssl_sock.c b/src/ssl_sock.c index e955a46cd..3c89aaa8d 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -776,8 +776,14 @@ void ssl_async_fd_free(int fd) } SSL_get_all_async_fds(ssl, all_fd, &num_all_fds); - for (i=0 ; i < num_all_fds ; i++) - fd_stop_both(all_fd[i]); + for (i=0 ; i < num_all_fds ; i++) { + /* We want to remove the fd from the fdtab + * but we flag it to disown because the + * close is performed by the engine itself + */ + fdtab[all_fd[i]].state |= FD_DISOWN; + fd_delete(all_fd[i]); + } /* Now we can safely call SSL_free, no more pending job in engines */ SSL_free(ssl); @@ -807,8 +813,14 @@ static inline void ssl_async_process_fds(struct ssl_sock_ctx *ctx) SSL_get_changed_async_fds(ssl, add_fd, &num_add_fds, del_fd, &num_del_fds); /* We remove unused fds from the fdtab */ - for (i=0 ; i < num_del_fds ; i++) - fd_stop_both(del_fd[i]); + for (i=0 ; i < num_del_fds ; i++) { + /* We want to remove the fd from the fdtab + * but we flag it to disown because the + * close is performed by the engine itself + */ + fdtab[del_fd[i]].state |= FD_DISOWN; + fd_delete(del_fd[i]); + } /* We add new fds to the fdtab */ for (i=0 ; i < num_add_fds ; i++) { @@ -6796,8 +6808,14 @@ void ssl_sock_close(struct connection *conn, void *xprt_ctx) { * because the fd is owned by the engine. * the engine is responsible to close */ - for (i=0 ; i < num_all_fds ; i++) - fd_stop_both(all_fd[i]); + for (i=0 ; i < num_all_fds ; i++) { + /* We want to remove the fd from the fdtab + * but we flag it to disown because the + * close is performed by the engine itself + */ + fdtab[all_fd[i]].state |= FD_DISOWN; + fd_delete(all_fd[i]); + } } #endif SSL_free(ctx->ssl);