From c4dcedd2dc900b604c64475356ecf0ce37285a79 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Sat, 7 Nov 2020 20:48:37 +0100 Subject: [PATCH] netmgr: Don't crash if socket() returns an error in udpconnect MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit socket() call can return an error - e.g. EMFILE, so we need to handle this nicely and not crash. Additionally wrap the socket() call inside a platform independent helper function as the Socket data type on Windows is unsigned integer: > This means, for example, that checking for errors when the socket and > accept functions return should not be done by comparing the return > value with –1, or seeing if the value is negative (both common and > legal approaches in UNIX). Instead, an application should use the > manifest constant INVALID_SOCKET as defined in the Winsock2.h header > file. (cherry picked from commit 8af7f81d6c1f974ac3305186ae34b9ce423525d0) --- lib/isc/netmgr/netmgr-int.h | 6 ++++++ lib/isc/netmgr/netmgr.c | 36 ++++++++++++++++++++++++++++++++++++ lib/isc/netmgr/udp.c | 18 +++++++++++++----- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index d7bdecc633b..8efe84f30d4 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -952,6 +952,12 @@ isc__nm_decstats(isc_nm_t *mgr, isc_statscounter_t counterid); * Decrement socket-related statistics counters. */ +isc_result_t +isc__nm_socket(int domain, int type, int protocol, uv_os_sock_t *sockp); +/*%< + * Platform independent socket() version + */ + isc_result_t isc__nm_socket_freebind(uv_os_sock_t fd, sa_family_t sa_family); /*%< diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 42aeb12e323..5d9cb9992ef 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include @@ -1722,6 +1724,40 @@ isc__nm_decstats(isc_nm_t *mgr, isc_statscounter_t counterid) { } } +isc_result_t +isc__nm_socket(int domain, int type, int protocol, uv_os_sock_t *sockp) { +#ifdef WIN32 + SOCKET sock; + sock = socket(domain, type, protocol); + if (sock == INVALID_SOCKET) { + char strbuf[ISC_STRERRORSIZE]; + DWORD socket_errno = WSAGetLastError(); + switch (socket_errno) { + case WSAEMFILE: + case WSAENOBUFS: + return (ISC_R_NORESOURCES); + + case WSAEPROTONOSUPPORT: + case WSAEPFNOSUPPORT: + case WSAEAFNOSUPPORT: + return (ISC_R_FAMILYNOSUPPORT); + default: + strerror_r(socket_errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() failed: %s", strbuf); + return (ISC_R_UNEXPECTED); + } + } +#else + int sock = socket(domain, type, protocol); + if (sock < 0) { + return (isc_errno_toresult(errno)); + } +#endif + *sockp = (uv_os_sock_t)sock; + return (ISC_R_SUCCESS); +} + #define setsockopt_on(socket, level, name) \ setsockopt(socket, level, name, &(int){ 1 }, sizeof(int)) diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index 2c3b61965f5..0d085124f79 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -93,8 +93,8 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, INSIST(csock->recv_cb == NULL && csock->recv_cbarg == NULL); csock->recv_cb = cb; csock->recv_cbarg = cbarg; - csock->fd = socket(family, SOCK_DGRAM, 0); - RUNTIME_CHECK(csock->fd >= 0); + result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &csock->fd); + RUNTIME_CHECK(result == ISC_R_SUCCESS); result = isc__nm_socket_reuse(csock->fd); RUNTIME_CHECK(result == ISC_R_SUCCESS || @@ -770,6 +770,7 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc__netievent_udpconnect_t *event = NULL; isc__nm_uvreq_t *req = NULL; sa_family_t sa_family; + uv_os_sock_t fd; REQUIRE(VALID_NM(mgr)); REQUIRE(local != NULL); @@ -777,6 +778,15 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sa_family = peer->addr.type.sa.sa_family; + /* + * The socket() call can fail spuriously on FreeBSD 12, so we need to + * handle the failure early and gracefully. + */ + result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &fd); + if (result != ISC_R_SUCCESS) { + return (result); + } + sock = isc_mem_get(mgr->mctx, sizeof(isc_nmsocket_t)); isc__nmsocket_init(sock, mgr, isc_nm_udpsocket, local); @@ -786,11 +796,9 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sock->read_timeout = timeout; sock->extrahandlesize = extrahandlesize; sock->peer = peer->addr; + sock->fd = fd; atomic_init(&sock->client, true); - sock->fd = socket(sa_family, SOCK_DGRAM, 0); - RUNTIME_CHECK(sock->fd >= 0); - result = isc__nm_socket_reuse(sock->fd); RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_NOTIMPLEMENTED); -- 2.47.3