]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
ISC_SOCKEVENTATTR_TRUNC was not be set
authorMark Andrews <marka@isc.org>
Tue, 1 May 2018 06:52:01 +0000 (16:52 +1000)
committerMark Andrews <marka@isc.org>
Fri, 18 May 2018 06:19:19 +0000 (16:19 +1000)
(cherry picked from commit 6bff1768cfeb156f05a3a6078d79afa9c98b29b3)

CHANGES
lib/isc/tests/socket_test.c
lib/isc/unix/socket.c

diff --git a/CHANGES b/CHANGES
index 9f399d8589f25b3a668509578f7c200f7f59a9c6..5ee8fd4ee35b96902ddd55f94e6451969df82212 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+4950.  [bug]           ISC_SOCKEVENTATTR_TRUNC was not be set. [GL #238]
+
 4949.  [bug]           lib/isc/print.c failed to handle floating point
                        output correctly. [GL #261]
 
index d0e5b003982c136d76bddc795be05752f7740035..51724b7e0ed95d11aad7ef4b06c1211b799bdbc2 100644 (file)
@@ -29,6 +29,8 @@
 #include "../task_p.h"
 #include "isctest.h"
 
+static isc_boolean_t recv_trunc;
+
 /*
  * Helper functions
  */
@@ -52,6 +54,7 @@ event_done(isc_task_t *task, isc_event_t *event) {
        dev = (isc_socketevent_t *) event;
        completion->result = dev->result;
        completion->done = ISC_TRUE;
+       recv_trunc = ISC_TF((dev->attributes & ISC_SOCKEVENTATTR_TRUNC) != 0);
        isc_event_free(&event);
 }
 
@@ -70,6 +73,45 @@ waitfor(completion_t *completion) {
        return (ISC_R_FAILURE);
 }
 
+/*
+ * Backport from 9.10 lib/isc/unix/socket.c.
+ */
+static void
+destroy_socketevent(isc_event_t *event) {
+       isc_socketevent_t *ev = (isc_socketevent_t *)event;
+
+       INSIST(ISC_LIST_EMPTY(ev->bufferlist));
+
+       (ev->destroy)(event);
+}
+
+static isc_socketevent_t *
+isc_socket_socketevent(isc_mem_t *mem, void *sender,
+                      isc_eventtype_t eventtype, isc_taskaction_t action,
+                      void *arg)
+{
+       isc_socketevent_t *ev;
+
+       ev = (isc_socketevent_t *)isc_event_allocate(mem, sender,
+                                                    eventtype, action, arg,
+                                                    sizeof(*ev));
+
+       if (ev == NULL)
+               return (NULL);
+
+       ev->result = ISC_R_UNSET;
+       ISC_LINK_INIT(ev, ev_link);
+       ISC_LIST_INIT(ev->bufferlist);
+       ev->region.base = NULL;
+       ev->n = 0;
+       ev->offset = 0;
+       ev->attributes = 0;
+       ev->destroy = ev->ev_destroy;
+       ev->ev_destroy = destroy_socketevent;
+
+       return (ev);
+}
+
 /*
  * Individual unit tests
  */
@@ -242,12 +284,138 @@ ATF_TC_BODY(udp_dup, tc) {
        isc_test_end();
 }
 
+/* Test UDP truncation detection */
+ATF_TC(udp_trunc);
+ATF_TC_HEAD(udp_trunc, tc) {
+       atf_tc_set_md_var(tc, "descr", "UDP Truncation detection");
+}
+ATF_TC_BODY(udp_trunc, tc) {
+       isc_result_t result;
+       isc_sockaddr_t addr1, addr2;
+       struct in_addr in;
+       isc_socket_t *s1 = NULL, *s2 = NULL;
+       isc_task_t *task = NULL;
+       char sendbuf[BUFSIZ*2], recvbuf[BUFSIZ];
+       completion_t completion;
+       isc_region_t r;
+       isc_socketevent_t *socketevent;
+
+       UNUSED(tc);
+
+       result = isc_test_begin(NULL, ISC_TRUE, 0);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       in.s_addr = inet_addr("127.0.0.1");
+       isc_sockaddr_fromin(&addr1, &in, 0);
+       isc_sockaddr_fromin(&addr2, &in, 0);
+
+       result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1);
+       ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                          isc_result_totext(result));
+       result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS);
+       ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                          isc_result_totext(result));
+       result = isc_socket_getsockname(s1, &addr1);
+       ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                        isc_result_totext(result));
+       ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0);
+
+       result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2);
+       ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                          isc_result_totext(result));
+       result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS);
+       ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                          isc_result_totext(result));
+       result = isc_socket_getsockname(s2, &addr2);
+       ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                        isc_result_totext(result));
+       ATF_REQUIRE(isc_sockaddr_getport(&addr2) != 0);
+
+       result = isc_task_create(taskmgr, 0, &task);
+       ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                          isc_result_totext(result));
+
+       /*
+        * Send a message that will not be truncated.
+        */
+       memset(sendbuf, 0xff, sizeof(sendbuf));
+       snprintf(sendbuf, sizeof(sendbuf), "Hello");
+       r.base = (void *) sendbuf;
+       r.length = strlen(sendbuf) + 1;
+
+       completion_init(&completion);
+
+       socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE,
+                                            event_done, &completion);
+       ATF_REQUIRE(socketevent != NULL);
+
+       result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0);
+       ATF_REQUIRE_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                          isc_result_totext(result));
+       waitfor(&completion);
+       ATF_CHECK(completion.done);
+       ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+       r.base = (void *) recvbuf;
+       r.length = BUFSIZ;
+       completion_init(&completion);
+       recv_trunc = ISC_FALSE;
+       result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       waitfor(&completion);
+       ATF_CHECK(completion.done);
+       ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+       ATF_CHECK_STREQ(recvbuf, "Hello");
+       ATF_CHECK_EQ(recv_trunc, ISC_FALSE);
+
+       /*
+        * Send a message that will be truncated.
+        */
+       memset(sendbuf, 0xff, sizeof(sendbuf));
+       snprintf(sendbuf, sizeof(sendbuf), "Hello");
+       r.base = (void *) sendbuf;
+       r.length = sizeof(sendbuf);
+
+       completion_init(&completion);
+
+       socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE,
+                                            event_done, &completion);
+       ATF_REQUIRE(socketevent != NULL);
+
+       result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0);
+       ATF_REQUIRE_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                          isc_result_totext(result));
+       waitfor(&completion);
+       ATF_CHECK(completion.done);
+       ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+       r.base = (void *) recvbuf;
+       r.length = BUFSIZ;
+       completion_init(&completion);
+       recv_trunc = ISC_FALSE;
+       result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       waitfor(&completion);
+       ATF_CHECK(completion.done);
+       ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+       ATF_CHECK_STREQ(recvbuf, "Hello");
+       ATF_CHECK_EQ(recv_trunc, ISC_TRUE);
+
+       isc_task_detach(&task);
+
+       isc_socket_detach(&s1);
+       isc_socket_detach(&s2);
+
+       isc_test_end();
+}
+
 /*
  * Main
  */
 ATF_TP_ADD_TCS(tp) {
        ATF_TP_ADD_TC(tp, udp_sendto);
        ATF_TP_ADD_TC(tp, udp_dup);
+       ATF_TP_ADD_TC(tp, udp_trunc);
 
        return (atf_no_error());
 }
index 8458cf472139f26eb0bf3cd7f5861f511d372d17..1c67b8f3ee71ae0bc2090b5cebf6b6e5fbc11136 100644 (file)
@@ -341,7 +341,7 @@ struct isc__socket {
                                bound : 1, /* bound to local addr */
                                dupped : 1;
 
-#ifdef ISC_NET_RECVOVERFLOW
+#ifdef ISC_PLATFORM_RECVOVERFLOW
        unsigned char           overflow; /* used for MSG_TRUNC fake */
 #endif
 
@@ -432,7 +432,7 @@ static isc__socketmgr_t *socketmgr = NULL;
  * send() and recv() iovec counts
  */
 #define MAXSCATTERGATHER_SEND  (ISC_SOCKET_MAXSCATTERGATHER)
-#ifdef ISC_NET_RECVOVERFLOW
+#ifdef ISC_PLATFORM_RECVOVERFLOW
 # define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER + 1)
 #else
 # define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
@@ -1517,10 +1517,6 @@ build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev,
 #else
                msg->msg_name = (void *)&dev->address.type.sa;
                msg->msg_namelen = sizeof(dev->address.type);
-#endif
-#ifdef ISC_NET_RECVOVERFLOW
-               /* If needed, steal one iovec for overflow detection. */
-               maxiov--;
 #endif
        } else { /* TCP */
                msg->msg_name = NULL;
@@ -1572,12 +1568,11 @@ build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev,
  config:
 
        /*
-        * If needed, set up to receive that one extra byte.  Note that
-        * we know there is at least one iov left, since we stole it
-        * at the top of this function.
+        * If needed, set up to receive that one extra byte.
         */
-#ifdef ISC_NET_RECVOVERFLOW
+#ifdef ISC_PLATFORM_RECVOVERFLOW
        if (sock->type == isc_sockettype_udp) {
+               INSIST(iovcount < MAXSCATTERGATHER_RECV);
                iov[iovcount].iov_base = (void *)(&sock->overflow);
                iov[iovcount].iov_len = 1;
                iovcount++;
@@ -1817,7 +1812,7 @@ doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) {
         * this indicates an overflow situation.  Set the flag in the
         * dev entry and adjust how much we read by one.
         */
-#ifdef ISC_NET_RECVOVERFLOW
+#ifdef ISC_PLATFORM_RECVOVERFLOW
        if ((sock->type == isc_sockettype_udp) && ((size_t)cc > read_count)) {
                dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
                cc--;