Description: Backports of bind9 upstream patches. This includes three upstream commits that refactors cmsgbufs from being dynamically handled to static buffers. The commits in question are: 2fca8cbd memset the remainder of sendcmsgbuf to 0 d79be7dd Fix socket cmsg buffer usage 49f90025 Use completely static-sized buffers Origin: upstream Bug: https://gitlab.isc.org/isc-projects/bind9/issues/180 Bug-Ubuntu: https://bugs.launchpad.net/bind/+bug/1804542 Acked-by: Bryce Harrington Last-Update: 2019-06-07 Applied-Upstream: 49f90025a07be39d1236504d46db3ce73f1578ee diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index a5187511..0f03036e 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -317,6 +317,35 @@ typedef isc_event_t intev_t; #define RCVBUFSIZE (32*1024) #endif /* TUNE_LARGE */ +/*% + * Instead of calculating the cmsgbuf lengths every time we take + * a rule of thumb approach - sizes are taken from x86_64 linux, + * multiplied by 2, everything should fit. Those sizes are not + * large enough to cause any concern. + */ +#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO) +#define CMSG_SP_IN6PKT 40 +#else +#define CMSG_SP_IN6PKT 0 +#endif + +#if defined(USE_CMSG) && defined(SO_TIMESTAMP) +#define CMSG_SP_TIMESTAMP 32 +#else +#define CMSG_SP_TIMESTAMP 0 +#endif + +#if defined(USE_CMSG) && (defined(IPV6_TCLASS) || defined(IP_TOS)) +#define CMSG_SP_TCTOS 24 +#else +#define CMSG_SP_TCTOS 0 +#endif + +#define CMSG_SP_INT 24 + +#define RECVCMSGBUFLEN (2*(CMSG_SP_IN6PKT + CMSG_SP_TIMESTAMP + CMSG_SP_TCTOS)+1) +#define SENDCMSGBUFLEN (2*(CMSG_SP_IN6PKT + CMSG_SP_INT + CMSG_SP_TCTOS)+1) + /*% * The number of times a send operation is repeated if the result is EINTR. */ @@ -373,11 +402,6 @@ struct isc__socket { unsigned char overflow; /* used for MSG_TRUNC fake */ #endif - char *recvcmsgbuf; - ISC_SOCKADDR_LEN_T recvcmsgbuflen; - char *sendcmsgbuf; - ISC_SOCKADDR_LEN_T sendcmsgbuflen; - void *fdwatcharg; isc_sockfdwatch_t fdwatchcb; int fdwatchflags; @@ -485,9 +509,9 @@ static void internal_send(isc_task_t *, isc_event_t *); static void internal_fdwatch_write(isc_task_t *, isc_event_t *); static void internal_fdwatch_read(isc_task_t *, isc_event_t *); static void process_cmsg(isc__socket_t *, struct msghdr *, isc_socketevent_t *); -static void build_msghdr_send(isc__socket_t *, isc_socketevent_t *, +static void build_msghdr_send(isc__socket_t *, char *, isc_socketevent_t *, struct msghdr *, struct iovec *, size_t *); -static void build_msghdr_recv(isc__socket_t *, isc_socketevent_t *, +static void build_msghdr_recv(isc__socket_t *, char *, isc_socketevent_t *, struct msghdr *, struct iovec *, size_t *); #ifdef USE_WATCHER_THREAD static isc_boolean_t process_ctlfd(isc__socketmgr_t *manager); @@ -1436,7 +1460,7 @@ process_cmsg(isc__socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) { * this transaction can send. */ static void -build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, +build_msghdr_send(isc__socket_t *sock, char* cmsgbuf, isc_socketevent_t *dev, struct msghdr *msg, struct iovec *iov, size_t *write_countp) { unsigned int iovcount; @@ -1449,9 +1473,6 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, #endif memset(msg, 0, sizeof(*msg)); - if (sock->sendcmsgbuflen != 0U) { - memset(sock->sendcmsgbuf, 0, sock->sendcmsgbuflen); - } if (!sock->connected) { msg->msg_name = (void *)&dev->address.type.sa; @@ -1529,11 +1550,11 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, "sendto pktinfo data, ifindex %u", dev->pktinfo.ipi6_ifindex); + msg->msg_control = (void *)cmsgbuf; msg->msg_controllen = cmsg_space(sizeof(struct in6_pktinfo)); - INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); - msg->msg_control = (void *)sock->sendcmsgbuf; + INSIST(msg->msg_controllen <= SENDCMSGBUFLEN); - cmsgp = (struct cmsghdr *)sock->sendcmsgbuf; + cmsgp = (struct cmsghdr *)cmsgbuf; cmsgp->cmsg_level = IPPROTO_IPV6; cmsgp->cmsg_type = IPV6_PKTINFO; cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo)); @@ -1548,10 +1569,11 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, { int use_min_mtu = 1; /* -1, 0, 1 */ - cmsgp = (struct cmsghdr *)(sock->sendcmsgbuf + + cmsgp = (struct cmsghdr *)(cmsgbuf + msg->msg_controllen); + msg->msg_control = (void *)cmsgbuf; msg->msg_controllen += cmsg_space(sizeof(use_min_mtu)); - INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); + INSIST(msg->msg_controllen <= SENDCMSGBUFLEN); cmsgp->cmsg_level = IPPROTO_IPV6; cmsgp->cmsg_type = IPV6_USE_MIN_MTU; @@ -1576,11 +1598,11 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, #ifdef IP_TOS if (sock->pf == AF_INET && sock->pktdscp) { - cmsgp = (struct cmsghdr *)(sock->sendcmsgbuf + + cmsgp = (struct cmsghdr *)(cmsgbuf + msg->msg_controllen); - msg->msg_control = (void *)sock->sendcmsgbuf; + msg->msg_control = (void *)cmsgbuf; msg->msg_controllen += cmsg_space(sizeof(dscp)); - INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); + INSIST(msg->msg_controllen <= SENDCMSGBUFLEN); cmsgp->cmsg_level = IPPROTO_IP; cmsgp->cmsg_type = IP_TOS; @@ -1607,11 +1629,11 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, #endif #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) if (sock->pf == AF_INET6 && sock->pktdscp) { - cmsgp = (struct cmsghdr *)(sock->sendcmsgbuf + + cmsgp = (struct cmsghdr *)(cmsgbuf + msg->msg_controllen); - msg->msg_control = (void *)sock->sendcmsgbuf; + msg->msg_control = (void *)cmsgbuf; msg->msg_controllen += cmsg_space(sizeof(dscp)); - INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); + INSIST(msg->msg_controllen <= SENDCMSGBUFLEN); cmsgp->cmsg_level = IPPROTO_IPV6; cmsgp->cmsg_type = IPV6_TCLASS; @@ -1635,6 +1657,12 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, sock->dscp = dscp; } #endif + if (msg->msg_controllen != 0 && + msg->msg_controllen < SENDCMSGBUFLEN) + { + memset(cmsgbuf + msg->msg_controllen, 0, + SENDCMSGBUFLEN - msg->msg_controllen); + } } #endif /* USE_CMSG */ #else /* ISC_NET_BSD44MSGHDR */ @@ -1659,7 +1687,7 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, * this transaction can receive. */ static void -build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev, +build_msghdr_recv(isc__socket_t *sock, char *cmsgbuf, isc_socketevent_t *dev, struct msghdr *msg, struct iovec *iov, size_t *read_countp) { unsigned int iovcount; @@ -1762,8 +1790,8 @@ build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev, #ifdef ISC_NET_BSD44MSGHDR #if defined(USE_CMSG) - msg->msg_control = sock->recvcmsgbuf; - msg->msg_controllen = sock->recvcmsgbuflen; + msg->msg_control = cmsgbuf; + msg->msg_controllen = RECVCMSGBUFLEN; #else msg->msg_control = NULL; msg->msg_controllen = 0; @@ -1866,8 +1894,9 @@ doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) { isc_buffer_t *buffer; int recv_errno; char strbuf[ISC_STRERRORSIZE]; + char cmsgbuf[RECVCMSGBUFLEN] = {0}; - build_msghdr_recv(sock, dev, &msghdr, iov, &read_count); + build_msghdr_recv(sock, cmsgbuf, dev, &msghdr, iov, &read_count); #if defined(ISC_SOCKET_DEBUG) dump_msg(&msghdr); @@ -2061,8 +2090,9 @@ doio_send(isc__socket_t *sock, isc_socketevent_t *dev) { int attempts = 0; int send_errno; char strbuf[ISC_STRERRORSIZE]; + char cmsgbuf[SENDCMSGBUFLEN] = {0}; - build_msghdr_send(sock, dev, &msghdr, iov, &write_count); + build_msghdr_send(sock, cmsgbuf, dev, &msghdr, iov, &write_count); resend: if (sock->type == isc_sockettype_udp && @@ -2280,7 +2310,6 @@ allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type, { isc__socket_t *sock; isc_result_t result; - ISC_SOCKADDR_LEN_T cmsgbuflen; sock = isc_mem_get(manager->mctx, sizeof(*sock)); @@ -2301,53 +2330,6 @@ allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type, ISC_LINK_INIT(sock, link); - sock->recvcmsgbuf = NULL; - sock->sendcmsgbuf = NULL; - - /* - * Set up cmsg buffers. - */ - cmsgbuflen = 0; -#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO) - cmsgbuflen += cmsg_space(sizeof(struct in6_pktinfo)); -#endif -#if defined(USE_CMSG) && defined(SO_TIMESTAMP) - cmsgbuflen += cmsg_space(sizeof(struct timeval)); -#endif -#if defined(USE_CMSG) && (defined(IPV6_TCLASS) || defined(IP_TOS)) - cmsgbuflen += cmsg_space(sizeof(int)); -#endif - sock->recvcmsgbuflen = cmsgbuflen; - if (sock->recvcmsgbuflen != 0U) { - sock->recvcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen); - if (sock->recvcmsgbuf == NULL) { - result = ISC_R_NOMEMORY; - goto error; - } - } - - cmsgbuflen = 0; -#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO) - cmsgbuflen += cmsg_space(sizeof(struct in6_pktinfo)); -#if defined(IPV6_USE_MIN_MTU) - /* - * Provide space for working around FreeBSD's broken IPV6_USE_MIN_MTU - * support. - */ - cmsgbuflen += cmsg_space(sizeof(int)); -#endif -#endif -#if defined(USE_CMSG) && (defined(IP_TOS) || defined(IPV6_TCLASS)) - cmsgbuflen += cmsg_space(sizeof(int)); -#endif - sock->sendcmsgbuflen = cmsgbuflen; - if (sock->sendcmsgbuflen != 0U) { - sock->sendcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen); - if (sock->sendcmsgbuf == NULL) { - result = ISC_R_NOMEMORY; - goto error; - } - } memset(sock->name, 0, sizeof(sock->name)); sock->tag = NULL; @@ -2395,12 +2377,6 @@ allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type, return (ISC_R_SUCCESS); error: - if (sock->recvcmsgbuf != NULL) - isc_mem_put(manager->mctx, sock->recvcmsgbuf, - sock->recvcmsgbuflen); - if (sock->sendcmsgbuf != NULL) - isc_mem_put(manager->mctx, sock->sendcmsgbuf, - sock->sendcmsgbuflen); isc_mem_put(manager->mctx, sock, sizeof(*sock)); return (result); @@ -2429,13 +2405,6 @@ free_socket(isc__socket_t **socketp) { INSIST(ISC_LIST_EMPTY(sock->connect_list)); INSIST(!ISC_LINK_LINKED(sock, link)); - if (sock->recvcmsgbuf != NULL) - isc_mem_put(sock->manager->mctx, sock->recvcmsgbuf, - sock->recvcmsgbuflen); - if (sock->sendcmsgbuf != NULL) - isc_mem_put(sock->manager->mctx, sock->sendcmsgbuf, - sock->sendcmsgbuflen); - sock->common.magic = 0; sock->common.impmagic = 0; @@ -2806,15 +2775,6 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, #endif /* SO_TIMESTAMP */ #if defined(ISC_PLATFORM_HAVEIPV6) - if (sock->pf == AF_INET6 && sock->recvcmsgbuflen == 0U) { - /* - * Warn explicitly because this anomaly can be hidden - * in usual operation (and unexpectedly appear later). - */ - UNEXPECTED_ERROR(__FILE__, __LINE__, - "No buffer available to receive " - "IPv6 destination"); - } #ifdef ISC_PLATFORM_HAVEIN6PKTINFO #ifdef IPV6_RECVPKTINFO /* RFC 3542 */