aboutsummaryrefslogtreecommitdiff
path: root/services/mesh.c
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2020-12-08 21:23:03 +0000
committerCy Schubert <cy@FreeBSD.org>2020-12-08 21:23:03 +0000
commitc1dbcbf2d10cd99864ab0eb44358d9875ba0c0a5 (patch)
tree8cbca8d9dc814933d2bc59b6623b792b549aac6b /services/mesh.c
parent4cb89f2eee3bb358f0491932ab0498b5319f4229 (diff)
downloadsrc-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.c59
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;