untrusted comment: verify with openbsd-68-base.pub
RWQZj25CSG5R2h2AGMzW77ehLQAmUMuMfxwBbMALGW43S937DiqWV4YTWvqWEIHB7NmbHZDfjPpZCIVh4afuNvR+eCfUolvrEwc=

OpenBSD 6.8 errata 005, November 10, 2020:

unwind fails to process large DNS replies.

Apply by doing:
    signify -Vep /etc/signify/openbsd-68-base.pub -x 005_unwind.patch.sig \
        -m - | (cd /usr/src && patch -p0)

And then rebuild and install unwind:
    cd /usr/src/sbin/unwind
    make obj
    make
    make install

Index: sbin/unwind/frontend.c
===================================================================
RCS file: /cvs/src/sbin/unwind/frontend.c,v
retrieving revision 1.51
diff -u -p -r1.51 frontend.c
--- sbin/unwind/frontend.c	12 Sep 2020 17:01:03 -0000	1.51
+++ sbin/unwind/frontend.c	5 Nov 2020 10:39:09 -0000
@@ -420,12 +420,14 @@ frontend_dispatch_main(int fd, short eve
 void
 frontend_dispatch_resolver(int fd, short event, void *bula)
 {
-	static struct pending_query	*pq;
+	struct pending_query		*pq;
 	struct imsgev			*iev = bula;
 	struct imsgbuf			*ibuf = &iev->ibuf;
 	struct imsg			 imsg;
 	struct query_imsg		*query_imsg;
+	struct answer_imsg		*answer_imsg;
 	int				 n, shut = 0, chg;
+	uint8_t				*p;
 
 	if (event & EV_READ) {
 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
@@ -448,8 +450,6 @@ frontend_dispatch_resolver(int fd, short
 
 		switch (imsg.hdr.type) {
 		case IMSG_ANSWER_HEADER:
-			if (pq != NULL)
-				fatalx("expected IMSG_ANSWER but got HEADER");
 			if (IMSG_DATA_SIZE(imsg) != sizeof(*query_imsg))
 				fatalx("%s: IMSG_ANSWER_HEADER wrong length: "
 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
@@ -468,19 +468,35 @@ frontend_dispatch_resolver(int fd, short
 			pq->bogus = query_imsg->bogus;
 			break;
 		case IMSG_ANSWER:
-			if (pq == NULL)
-				fatalx("IMSG_ANSWER without HEADER");
-
-			if (pq->answer)
-				fatal("pq->answer");
-			if ((pq->answer = malloc(IMSG_DATA_SIZE(imsg))) !=
+			if (IMSG_DATA_SIZE(imsg) != sizeof(*answer_imsg))
+				fatalx("%s: IMSG_ANSWER wrong length: "
+				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
+			answer_imsg = (struct answer_imsg *)imsg.data;
+			if ((pq = find_pending_query(answer_imsg->id)) ==
 			    NULL) {
-				pq->answer_len = IMSG_DATA_SIZE(imsg);
-				memcpy(pq->answer, imsg.data, pq->answer_len);
-			} else
+				log_warnx("cannot find pending query %llu",
+				    answer_imsg->id);
+				break;
+			}
+
+			p = realloc(pq->answer, pq->answer_len +
+			    answer_imsg->len);
+
+			if (p != NULL) {
+				pq->answer = p;
+				memcpy(pq->answer + pq->answer_len,
+				    answer_imsg->answer, answer_imsg->len);
+				pq->answer_len += answer_imsg->len;
+			} else {
+				free(pq->answer);
+				pq->answer_len = 0;
+				pq->answer = NULL;
 				pq->rcode_override = LDNS_RCODE_SERVFAIL;
-			send_answer(pq);
-			pq = NULL;
+				send_answer(pq);
+				break;
+			}
+			if (!answer_imsg->truncated)
+				send_answer(pq);
 			break;
 		case IMSG_CTL_RESOLVER_INFO:
 		case IMSG_CTL_AUTOCONF_RESOLVER_INFO:
Index: sbin/unwind/resolver.c
===================================================================
RCS file: /cvs/src/sbin/unwind/resolver.c,v
retrieving revision 1.125
diff -u -p -r1.125 resolver.c
--- sbin/unwind/resolver.c	12 Sep 2020 17:01:03 -0000	1.125
+++ sbin/unwind/resolver.c	5 Nov 2020 10:39:09 -0000
@@ -884,6 +884,7 @@ resolve_done(struct uw_resolver *res, vo
 	sldns_buffer		*buf = NULL;
 	struct regional		*region = NULL;
 	struct query_imsg	*query_imsg;
+	struct answer_imsg	 answer_imsg;
 	struct running_query	*rq;
 	struct timespec		 tp, elapsed;
 	int64_t			 ms;
@@ -893,6 +894,7 @@ resolve_done(struct uw_resolver *res, vo
 	char			 rcode_buf[16];
 	char			 qclass_buf[16];
 	char			 qtype_buf[16];
+	uint8_t			*p;
 
 	clock_gettime(CLOCK_MONOTONIC, &tp);
 
@@ -1014,12 +1016,31 @@ resolve_done(struct uw_resolver *res, vo
 	} else
 		query_imsg->bogus = 0;
 
-	resolver_imsg_compose_frontend(IMSG_ANSWER_HEADER, 0, query_imsg,
-	    sizeof(*query_imsg));
-
-	/* XXX imsg overflow */
-	resolver_imsg_compose_frontend(IMSG_ANSWER, 0, answer_packet,
-	    answer_len);
+	if (resolver_imsg_compose_frontend(IMSG_ANSWER_HEADER, 0, query_imsg,
+	    sizeof(*query_imsg)) == -1)
+		fatalx("IMSG_ANSWER_HEADER failed for \"%s %s %s\"",
+		    query_imsg->qname, qclass_buf, qtype_buf);
+
+	answer_imsg.id = query_imsg->id;
+	p = answer_packet;
+	while ((size_t)answer_len > MAX_ANSWER_SIZE) {
+		answer_imsg.truncated = 1;
+		answer_imsg.len = MAX_ANSWER_SIZE;
+		memcpy(&answer_imsg.answer, p, MAX_ANSWER_SIZE);
+		if (resolver_imsg_compose_frontend(IMSG_ANSWER, 0, &answer_imsg,
+		    sizeof(answer_imsg)) == -1)
+			fatalx("IMSG_ANSWER failed for \"%s %s %s\"",
+			    query_imsg->qname, qclass_buf, qtype_buf);
+		p += MAX_ANSWER_SIZE;
+		answer_len -= MAX_ANSWER_SIZE;
+	}
+	answer_imsg.truncated = 0;
+	answer_imsg.len = answer_len;
+	memcpy(&answer_imsg.answer, p, answer_len);
+	if (resolver_imsg_compose_frontend(IMSG_ANSWER, 0, &answer_imsg,
+	    sizeof(answer_imsg)) == -1)
+		fatalx("IMSG_ANSWER failed for \"%s %s %s\"",
+		    query_imsg->qname, qclass_buf, qtype_buf);
 
 	TAILQ_REMOVE(&running_queries, rq, entry);
 	evtimer_del(&rq->timer_ev);
Index: sbin/unwind/unwind.c
===================================================================
RCS file: /cvs/src/sbin/unwind/unwind.c,v
retrieving revision 1.49
diff -u -p -r1.49 unwind.c
--- sbin/unwind/unwind.c	12 Sep 2020 17:01:03 -0000	1.49
+++ sbin/unwind/unwind.c	5 Nov 2020 10:39:09 -0000
@@ -726,7 +726,7 @@ void
 open_ports(void)
 {
 	struct addrinfo	 hints, *res0;
-	int		 udp4sock = -1, udp6sock = -1, error;
+	int		 udp4sock = -1, udp6sock = -1, error, bsize = 65535;
 	int		 opt = 1;
 
 	memset(&hints, 0, sizeof(hints));
@@ -741,6 +741,9 @@ open_ports(void)
 			if (setsockopt(udp4sock, SOL_SOCKET, SO_REUSEADDR,
 			    &opt, sizeof(opt)) == -1)
 				log_warn("setting SO_REUSEADDR on socket");
+			if (setsockopt(udp4sock, SOL_SOCKET, SO_SNDBUF, &bsize,
+			    sizeof(bsize)) == -1)
+				log_warn("setting SO_SNDBUF on socket");
 			if (bind(udp4sock, res0->ai_addr, res0->ai_addrlen)
 			    == -1) {
 				close(udp4sock);
@@ -759,6 +762,9 @@ open_ports(void)
 			if (setsockopt(udp6sock, SOL_SOCKET, SO_REUSEADDR,
 			    &opt, sizeof(opt)) == -1)
 				log_warn("setting SO_REUSEADDR on socket");
+			if (setsockopt(udp6sock, SOL_SOCKET, SO_SNDBUF, &bsize,
+			    sizeof(bsize)) == -1)
+				log_warn("setting SO_SNDBUF on socket");
 			if (bind(udp6sock, res0->ai_addr, res0->ai_addrlen)
 			    == -1) {
 				close(udp6sock);
Index: sbin/unwind/unwind.h
===================================================================
RCS file: /cvs/src/sbin/unwind/unwind.h,v
retrieving revision 1.47
diff -u -p -r1.47 unwind.h
--- sbin/unwind/unwind.h	18 Dec 2019 09:18:27 -0000	1.47
+++ sbin/unwind/unwind.h	5 Nov 2020 10:39:09 -0000
@@ -175,6 +175,15 @@ struct query_imsg {
 	struct timespec	 tp;
 };
 
+struct answer_imsg {
+#define	MAX_ANSWER_SIZE	MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof(uint64_t) - \
+			    2 * sizeof(int)
+	uint64_t	 id;
+	int		 truncated;
+	int		 len;
+	uint8_t		 answer[MAX_ANSWER_SIZE];
+};
+
 extern uint32_t	 cmd_opts;
 
 /* unwind.c */
