diff options
author | Cy Schubert <cy@FreeBSD.org> | 2020-12-08 21:23:03 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2020-12-08 21:23:03 +0000 |
commit | c1dbcbf2d10cd99864ab0eb44358d9875ba0c0a5 (patch) | |
tree | 8cbca8d9dc814933d2bc59b6623b792b549aac6b /services/mesh.c | |
parent | 4cb89f2eee3bb358f0491932ab0498b5319f4229 (diff) | |
download | src-c1dbcbf2d10cd99864ab0eb44358d9875ba0c0a5.tar.gz src-c1dbcbf2d10cd99864ab0eb44358d9875ba0c0a5.zip |
Vendor import of Unbound 1.13.0.vendor/unbound/1.13.0
Security: CVE-2020-28935
Notes
Notes:
svn path=/vendor/unbound/dist/; revision=368464
svn path=/vendor/unbound/1.13.0/; revision=368465; tag=vendor/unbound/1.13.0
Diffstat (limited to 'services/mesh.c')
-rw-r--r-- | services/mesh.c | 59 |
1 files changed, 31 insertions, 28 deletions
diff --git a/services/mesh.c b/services/mesh.c index 52ff97e4a2e8..cd90509366f2 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -1196,6 +1196,12 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, /* Copy the client's EDNS for later restore, to make sure the edns * compare is with the correct edns options. */ struct edns_data edns_bak = r->edns; + /* briefly set the replylist to null in case the + * meshsendreply calls tcpreqinfo sendreply that + * comm_point_drops because of size, and then the + * null stops the mesh state remove and thus + * reply_list modification and accounting */ + struct mesh_reply* rlist = m->reply_list; /* examine security status */ if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) || m->s.env->cfg->ignore_cd) && rep && @@ -1218,15 +1224,21 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, r->h2_stream->mesh_state = NULL; } /* send the reply */ - /* We don't reuse the encoded answer if either the previous or current - * response has a local alias. We could compare the alias records - * and still reuse the previous answer if they are the same, but that - * would be complicated and error prone for the relatively minor case. - * So we err on the side of safety. */ - if(prev && prev_buffer && prev->qflags == r->qflags && + /* We don't reuse the encoded answer if: + * - either the previous or current response has a local alias. We could + * compare the alias records and still reuse the previous answer if they + * are the same, but that would be complicated and error prone for the + * relatively minor case. So we err on the side of safety. + * - there are registered callback functions for the given rcode, as these + * need to be called for each reply. */ + if(((rcode != LDNS_RCODE_SERVFAIL && + !m->s.env->inplace_cb_lists[inplace_cb_reply]) || + (rcode == LDNS_RCODE_SERVFAIL && + !m->s.env->inplace_cb_lists[inplace_cb_reply_servfail])) && + prev && prev_buffer && prev->qflags == r->qflags && !prev->local_alias && !r->local_alias && - prev->edns.edns_present == r->edns.edns_present && - prev->edns.bits == r->edns.bits && + prev->edns.edns_present == r->edns.edns_present && + prev->edns.bits == r->edns.bits && prev->edns.udp_size == r->edns.udp_size && edns_opt_list_compare(prev->edns.opt_list, r->edns.opt_list) == 0) { @@ -1236,22 +1248,26 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, sldns_buffer_write_at(r_buffer, 0, &r->qid, sizeof(uint16_t)); sldns_buffer_write_at(r_buffer, 12, r->qname, m->s.qinfo.qname_len); + m->reply_list = NULL; comm_point_send_reply(&r->query_reply); + m->reply_list = rlist; } else if(rcode) { m->s.qinfo.qname = r->qname; m->s.qinfo.local_alias = r->local_alias; if(rcode == LDNS_RCODE_SERVFAIL) { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, - rep, rcode, &r->edns, NULL, m->s.region)) + rep, rcode, &r->edns, &r->query_reply, m->s.region)) r->edns.opt_list = NULL; } else { if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, - &r->edns, NULL, m->s.region)) + &r->edns, &r->query_reply, m->s.region)) r->edns.opt_list = NULL; } error_encode(r_buffer, rcode, &m->s.qinfo, r->qid, r->qflags, &r->edns); + m->reply_list = NULL; comm_point_send_reply(&r->query_reply); + m->reply_list = rlist; } else { size_t udp_size = r->edns.udp_size; r->edns.edns_version = EDNS_ADVERTISED_VERSION; @@ -1261,7 +1277,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, m->s.qinfo.qname = r->qname; m->s.qinfo.local_alias = r->local_alias; if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, - LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region) || + LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region) || !apply_edns_options(&r->edns, &edns_bak, m->s.env->cfg, r->query_reply.c, m->s.region) || @@ -1271,13 +1287,15 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, secure)) { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, - rep, LDNS_RCODE_SERVFAIL, &r->edns, NULL, m->s.region)) + rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region)) r->edns.opt_list = NULL; error_encode(r_buffer, LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, r->qflags, &r->edns); } r->edns = edns_bak; + m->reply_list = NULL; comm_point_send_reply(&r->query_reply); + m->reply_list = rlist; } /* account */ log_assert(m->s.env->mesh->num_reply_addrs > 0); @@ -1365,20 +1383,12 @@ void mesh_query_done(struct mesh_state* mstate) mstate->reply_list = reply_list; } else { struct sldns_buffer* r_buffer = r->query_reply.c->buffer; - struct mesh_reply* rlist = mstate->reply_list; if(r->query_reply.c->tcp_req_info) { r_buffer = r->query_reply.c->tcp_req_info->spool_buffer; prev_buffer = NULL; } - /* briefly set the replylist to null in case the - * meshsendreply calls tcpreqinfo sendreply that - * comm_point_drops because of size, and then the - * null stops the mesh state remove and thus - * reply_list modification and accounting */ - mstate->reply_list = NULL; mesh_send_reply(mstate, mstate->s.return_rcode, rep, r, r_buffer, prev, prev_buffer); - mstate->reply_list = rlist; if(r->query_reply.c->tcp_req_info) { tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); r_buffer = NULL; @@ -1894,7 +1904,7 @@ mesh_serve_expired_callback(void* arg) { struct mesh_state* mstate = (struct mesh_state*) arg; struct module_qstate* qstate = &mstate->s; - struct mesh_reply* r, *rlist; + struct mesh_reply* r; struct mesh_area* mesh = qstate->env->mesh; struct dns_msg* msg; struct mesh_cb* c; @@ -1999,15 +2009,8 @@ mesh_serve_expired_callback(void* arg) r_buffer = r->query_reply.c->buffer; if(r->query_reply.c->tcp_req_info) r_buffer = r->query_reply.c->tcp_req_info->spool_buffer; - /* briefly set the replylist to null in case the meshsendreply - * calls tcpreqinfo sendreply that comm_point_drops because - * of size, and then the null stops the mesh state remove and - * thus reply_list modification and accounting */ - rlist = mstate->reply_list; - mstate->reply_list = NULL; mesh_send_reply(mstate, LDNS_RCODE_NOERROR, msg->rep, r, r_buffer, prev, prev_buffer); - mstate->reply_list = rlist; if(r->query_reply.c->tcp_req_info) tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); prev = r; |