On Thu, Feb 13, 2025 at 05:17:36PM +0100, Martijn van Duren wrote: > Hello ports@, > > Some time ago I hit an issue where my prosody server randomly started to > hang on the netio channel. After some debugging I found out that luasec > puts the underlying socket in blocking mode before calling SSL_shutdown. > This combined with a crappy client who is on the disconnect path can > result in the server not being able to send out the shutdown > notification, and waiting until the underlying TCP layer gives up. > > The diffs below is a backport from what is aleady accepted upstream by > prosody[0], and the luasec diff as forwarded to the luasec project via > prosody[1]. > > Since OpenBSD appears to be disproportionately affected by issue, from > what I've been told by the prosody people, it might be a good idea to > ship these changes as local patches until both upstreams makes the > new releases.
Well, if you want tests, get it in... > > martijn@ > > [0] https://hg.prosody.im/trunk/rev/a08065207ef0 > [1] https://github.com/lunarmodules/luasec/pull/203/files > > diff /usr/ports > path + /usr/ports > commit - bfce4c31b71ca3f1fbcd26b4c1c97d12bb453e72 > blob - 9c2b8e2f66fcd4d47cb882e8cc8f95fd5cc1a410 > file + net/prosody/Makefile > --- net/prosody/Makefile > +++ net/prosody/Makefile > @@ -1,5 +1,6 @@ > COMMENT = communications server for Jabber/XMPP written in Lua > DISTNAME = prosody-0.12.5 > +REVISION = 0 > CATEGORIES = net > HOMEPAGE = https://prosody.im/ > > commit - bfce4c31b71ca3f1fbcd26b4c1c97d12bb453e72 > blob - /dev/null > file + net/prosody/patches/patch-net_server_epoll_lua (mode 644) > --- /dev/null > +++ net/prosody/patches/patch-net_server_epoll_lua > @@ -0,0 +1,45 @@ > +Index: net/server_epoll.lua > +--- net/server_epoll.lua.orig > ++++ net/server_epoll.lua > +@@ -576,6 +576,7 @@ interface.send = interface.write; > + > + -- Close, possibly after writing is done > + function interface:close() > ++ local status, err; > + if self._connected and self.writebuffer and (self.writebuffer[1] or > type(self.writebuffer) == "string") then > + self._connected = false; > + self:set(false, true); -- Flush final buffer contents > +@@ -584,6 +585,24 @@ function interface:close() > + self.write, self.send = noop, noop; -- No more writing > + self:debug("Close after writing remaining buffered data"); > + self.ondrain = interface.close; > ++ elseif self.conn.shutdown and self._tls then > ++ status, err = self.conn:shutdown(); > ++ self.onreadable = interface.close; > ++ self.onwritable = interface.close; > ++ if err == nil then > ++ if status == true then > ++ self._tls = false; > ++ end > ++ return self:close(); > ++ elseif err == "wantread" then > ++ self:set(true, nil); > ++ self:setreadtimeout(); > ++ elseif err == "wantwrite" then > ++ self:set(nil, true); > ++ self:setwritetimeout(); > ++ else > ++ self._tls = false; > ++ end > + else > + self:debug("Closing now"); > + self.write, self.send = noop, noop; > +@@ -594,6 +613,8 @@ function interface:close() > + end > + > + function interface:destroy() > ++ -- make sure tls sockets aren't put in blocking mode > ++ if self.conn.shutdown and self._tls then self.conn:shutdown(); end > + self:del(); > + self:setwritetimeout(false); > + self:setreadtimeout(false); > commit - bfce4c31b71ca3f1fbcd26b4c1c97d12bb453e72 > blob - 98f317ac9f1568932b9ce2de581924d3e193c310 > file + security/luasec/Makefile > --- security/luasec/Makefile > +++ security/luasec/Makefile > @@ -3,6 +3,7 @@ COMMENT= lua binding to OpenSSL to provide TLS/SSL com > GH_ACCOUNT= brunoos > GH_PROJECT= luasec > GH_TAGNAME= v1.2.0 > +REVISION= 0 > > CATEGORIES= security > > commit - bfce4c31b71ca3f1fbcd26b4c1c97d12bb453e72 > blob - /dev/null > file + security/luasec/patches/patch-src_luasocket_usocket_c (mode 644) > --- /dev/null > +++ security/luasec/patches/patch-src_luasocket_usocket_c > @@ -0,0 +1,11 @@ > +Index: src/luasocket/usocket.c > +--- src/luasocket/usocket.c.orig > ++++ src/luasocket/usocket.c > +@@ -82,7 +82,6 @@ int socket_close(void) { > + > \*-------------------------------------------------------------------------*/ > + void socket_destroy(p_socket ps) { > + if (*ps != SOCKET_INVALID) { > +- socket_setblocking(ps); > + close(*ps); > + *ps = SOCKET_INVALID; > + } > commit - bfce4c31b71ca3f1fbcd26b4c1c97d12bb453e72 > blob - /dev/null > file + security/luasec/patches/patch-src_ssl_c (mode 644) > --- /dev/null > +++ security/luasec/patches/patch-src_ssl_c > @@ -0,0 +1,86 @@ > +Index: src/ssl.c > +--- src/ssl.c.orig > ++++ src/ssl.c > +@@ -87,7 +87,8 @@ static int meth_destroy(lua_State *L) > + { > + p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); > + if (ssl->state == LSEC_STATE_CONNECTED) { > +- socket_setblocking(&ssl->sock); > ++ if (!ssl->shutdown) > ++ socket_setblocking(&ssl->sock); > + SSL_shutdown(ssl->ssl); > + } > + if (ssl->sock != SOCKET_INVALID) { > +@@ -305,6 +306,7 @@ static int meth_create(lua_State *L) > + return luaL_argerror(L, 1, "invalid context"); > + } > + ssl->state = LSEC_STATE_NEW; > ++ ssl->shutdown = 0; > + SSL_set_fd(ssl->ssl, (int)SOCKET_INVALID); > + SSL_set_mode(ssl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | > + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); > +@@ -341,6 +343,56 @@ static int meth_receive(lua_State *L) { > + } > + > + /** > ++ * SSL shutdown function > ++ */ > ++static int meth_shutdown(lua_State *L) { > ++ p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); > ++ int err; > ++ p_timeout tm = timeout_markstart(&ssl->tm); > ++ > ++ ssl->shutdown = 1; > ++ if (ssl->state == LSEC_STATE_CLOSED) { > ++ lua_pushboolean(L, 1); > ++ return 1; > ++ } > ++ > ++ err = SSL_shutdown(ssl->ssl); > ++ switch (err) { > ++ case 0: > ++ lua_pushboolean(L, 0); > ++ lua_pushnil(L); > ++ return 2; > ++ case 1: > ++ lua_pushboolean(L, 1); > ++ lua_pushnil(L); > ++ ssl->state = LSEC_STATE_CLOSED; > ++ return 2; > ++ case -1: > ++ lua_pushboolean(L, 0); > ++ ssl->error = SSL_get_error(ssl->ssl, err); > ++ switch (ssl->error) { > ++ case SSL_ERROR_WANT_READ: > ++ err = socket_waitfd(&ssl->sock, WAITFD_R, tm); > ++ lua_pushstring(L, ssl_ioerror((void *)ssl, err == IO_TIMEOUT ? > LSEC_IO_SSL : err)); > ++ break; > ++ case SSL_ERROR_WANT_WRITE: > ++ err = socket_waitfd(&ssl->sock, WAITFD_W, tm); > ++ lua_pushstring(L, ssl_ioerror((void *)ssl, err == IO_TIMEOUT ? > LSEC_IO_SSL : err)); > ++ break; > ++ case SSL_ERROR_SYSCALL: > ++ if (ERR_peek_error()) > ++ ssl->error = SSL_ERROR_SSL; > ++ lua_pushstring(L, ssl_ioerror((void *)ssl, LSEC_IO_SSL)); > ++ break; > ++ default: > ++ lua_pushstring(L, ssl_ioerror((void *)ssl, LSEC_IO_SSL)); > ++ break; > ++ } > ++ return 2; > ++ } > ++} > ++ > ++/** > + * Get the buffer's statistics. > + */ > + static int meth_getstats(lua_State *L) { > +@@ -904,6 +956,7 @@ static int meth_tlsa(lua_State *L) > + */ > + static luaL_Reg methods[] = { > + {"close", meth_close}, > ++ {"shutdown", meth_shutdown}, > + {"getalpn", meth_getalpn}, > + {"getfd", meth_getfd}, > + {"getfinished", meth_getfinished}, > commit - bfce4c31b71ca3f1fbcd26b4c1c97d12bb453e72 > blob - /dev/null > file + security/luasec/patches/patch-src_ssl_h (mode 644) > --- /dev/null > +++ security/luasec/patches/patch-src_ssl_h > @@ -0,0 +1,11 @@ > +Index: src/ssl.h > +--- src/ssl.h.orig > ++++ src/ssl.h > +@@ -32,6 +32,7 @@ typedef struct t_ssl_ { > + t_timeout tm; > + SSL *ssl; > + int state; > ++ int shutdown; > + int error; > + } t_ssl; > + typedef t_ssl* p_ssl; >