untrusted comment: verify with openbsd-67-base.pub RWRmkIA877Io3jHYVdx0zu2ZtYLZADjt01Bt5MVE9/td0uyjMozPQlit7cOeKzEzkBu7PtefF4nraF9pCyGCNjHqevkP3Wrkvgc= OpenBSD 6.7 errata 028, November 10, 2020: unwind fails to process large DNS replies. Apply by doing: signify -Vep /etc/signify/openbsd-67-base.pub -x 028_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.50 diff -u -p -r1.50 frontend.c --- sbin/unwind/frontend.c 28 Jan 2020 15:44:13 -0000 1.50 +++ sbin/unwind/frontend.c 5 Nov 2020 09:43:34 -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.123 diff -u -p -r1.123 resolver.c --- sbin/unwind/resolver.c 19 Mar 2020 19:27:21 -0000 1.123 +++ sbin/unwind/resolver.c 5 Nov 2020 09:43:34 -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.46 diff -u -p -r1.46 unwind.c --- sbin/unwind/unwind.c 20 Dec 2019 08:30:27 -0000 1.46 +++ sbin/unwind/unwind.c 5 Nov 2020 09:44:19 -0000 @@ -727,7 +727,7 @@ void open_ports(void) { struct addrinfo hints, *res0; - int udp4sock = -1, udp6sock = -1, error; + int udp4sock = -1, udp6sock = -1, error, bsize = 65535; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; @@ -738,6 +738,9 @@ open_ports(void) if (!error && res0) { if ((udp4sock = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol)) != -1) { + 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); @@ -753,6 +756,9 @@ open_ports(void) if (!error && res0) { if ((udp6sock = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol)) != -1) { + 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 09:43:34 -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 */