summaryrefslogtreecommitdiffstats
path: root/debian/patches/CVE-2019-19331.patch
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-07 05:28:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-07 05:28:39 +0000
commit4138bce0c92f9e5e7879983988f135c4509ff3bc (patch)
tree68fef474c8e4c37d355b92acbec8c5a731661fd8 /debian/patches/CVE-2019-19331.patch
parentReleasing progress-linux version 3.2.1-3+deb10u1progress5u1. (diff)
downloadknot-resolver-4138bce0c92f9e5e7879983988f135c4509ff3bc.tar.xz
knot-resolver-4138bce0c92f9e5e7879983988f135c4509ff3bc.zip
Merging debian version 3.2.1-3+deb10u2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'debian/patches/CVE-2019-19331.patch')
-rw-r--r--debian/patches/CVE-2019-19331.patch371
1 files changed, 371 insertions, 0 deletions
diff --git a/debian/patches/CVE-2019-19331.patch b/debian/patches/CVE-2019-19331.patch
new file mode 100644
index 0000000..67420ea
--- /dev/null
+++ b/debian/patches/CVE-2019-19331.patch
@@ -0,0 +1,371 @@
+From: Markus Koschany <apo@debian.org>
+Date: Mon, 11 Mar 2024 14:37:42 +0200
+Subject: CVE-2019-19331
+
+Bug-Debian: https://bugs.debian.org/946181
+Origin: https://gitlab.nic.cz/knot/knot-resolver/-/commit/782682db6d4b17d9d1559a1d13ae718a07eb260e
+---
+ daemon/lua/kres-gen.lua | 2 +
+ daemon/lua/kres-gen.sh | 1 +
+ lib/cache/api.c | 1 +
+ lib/dnssec.c | 1 +
+ lib/layer/iterate.c | 17 +++++-
+ lib/resolve.c | 1 +
+ lib/utils.c | 143 +++++++++++++++++++++++++++++++++++++++++++++---
+ lib/utils.h | 10 +++-
+ modules/dns64/dns64.lua | 1 +
+ 9 files changed, 167 insertions(+), 10 deletions(-)
+
+diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua
+index 9e9f586..a92288b 100644
+--- a/daemon/lua/kres-gen.lua
++++ b/daemon/lua/kres-gen.lua
+@@ -135,6 +135,7 @@ struct ranked_rr_array_entry {
+ _Bool yielded : 1;
+ _Bool to_wire : 1;
+ _Bool expiring : 1;
++ _Bool in_progress : 1;
+ knot_rrset_t *rr;
+ };
+ typedef struct ranked_rr_array_entry ranked_rr_array_entry_t;
+@@ -310,6 +311,7 @@ int kr_bitcmp(const char *, const char *, int);
+ int kr_family_len(int);
+ struct sockaddr *kr_straddr_socket(const char *, int);
+ int kr_ranked_rrarray_add(ranked_rr_array_t *, const knot_rrset_t *, uint8_t, _Bool, uint32_t, knot_mm_t *);
++int kr_ranked_rrarray_finalize(ranked_rr_array_t *, uint32_t, knot_mm_t *);
+ void kr_qflags_set(struct kr_qflags *, struct kr_qflags);
+ void kr_qflags_clear(struct kr_qflags *, struct kr_qflags);
+ int kr_zonecut_add(struct kr_zonecut *, const knot_dname_t *, const void *, int);
+diff --git a/daemon/lua/kres-gen.sh b/daemon/lua/kres-gen.sh
+index 538fe23..6c4aa64 100755
+--- a/daemon/lua/kres-gen.sh
++++ b/daemon/lua/kres-gen.sh
+@@ -163,6 +163,7 @@ EOF
+ kr_family_len
+ kr_straddr_socket
+ kr_ranked_rrarray_add
++ kr_ranked_rrarray_finalize
+ kr_qflags_set
+ kr_qflags_clear
+ kr_zonecut_add
+diff --git a/lib/cache/api.c b/lib/cache/api.c
+index 4c7f3d2..90aaf0b 100644
+--- a/lib/cache/api.c
++++ b/lib/cache/api.c
+@@ -605,6 +605,7 @@ static int stash_rrarray_entry(ranked_rr_array_t *arr, int arr_i,
+ /* TODO: ATM we assume that some properties are the same
+ * for all RRSIGs in the set (esp. label count). */
+ ranked_rr_array_entry_t *e = arr->at[j];
++ assert(!e->in_progress);
+ bool ok = e->qry_uid == qry->uid && !e->cached
+ && e->rr->type == KNOT_RRTYPE_RRSIG
+ && knot_rrsig_type_covered(e->rr->rrs.rdata) == rr->type
+diff --git a/lib/dnssec.c b/lib/dnssec.c
+index 4f8ad8a..9973656 100644
+--- a/lib/dnssec.c
++++ b/lib/dnssec.c
+@@ -447,6 +447,7 @@ int kr_dnssec_matches_name_and_type(const ranked_rr_array_t *rrs, uint32_t qry_u
+ int ret = kr_error(ENOENT);
+ for (size_t i = 0; i < rrs->len; ++i) {
+ const ranked_rr_array_entry_t *entry = rrs->at[i];
++ assert(!entry->in_progress);
+ const knot_rrset_t *nsec = entry->rr;
+ if (entry->qry_uid != qry_uid || entry->yielded) {
+ continue;
+diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c
+index feaadf0..0423a3d 100644
+--- a/lib/layer/iterate.c
++++ b/lib/layer/iterate.c
+@@ -1119,13 +1119,15 @@ static int resolve(kr_layer_t *ctx, knot_pkt_t *pkt)
+ return resolve_error(pkt, req);
+ }
+
++ int state;
+ /* Forwarding/stub mode is special. */
+ if (query->flags.STUB) {
+- return process_stub(pkt, req);
++ state = process_stub(pkt, req);
++ goto rrarray_finalize;
+ }
+
+ /* Resolve authority to see if it's referral or authoritative. */
+- int state = process_authority(pkt, req);
++ state = process_authority(pkt, req);
+ switch(state) {
+ case KR_STATE_CONSUME: /* Not referral, process answer. */
+ VERBOSE_MSG("<= rcode: %s\n", rcode ? rcode->name : "??");
+@@ -1139,6 +1141,17 @@ static int resolve(kr_layer_t *ctx, knot_pkt_t *pkt)
+ break;
+ }
+
++rrarray_finalize:
++ /* Finish construction of libknot-format RRsets. */
++ (void)0;
++ ranked_rr_array_t *selected[] = kr_request_selected(req);
++ for (knot_section_t i = KNOT_ANSWER; i <= KNOT_ADDITIONAL; ++i) {
++ int ret = kr_ranked_rrarray_finalize(selected[i], query->uid, &req->pool);
++ if (unlikely(ret)) {
++ return KR_STATE_FAIL;
++ }
++ }
++
+ return state;
+ }
+
+diff --git a/lib/resolve.c b/lib/resolve.c
+index b771cdc..65b167f 100644
+--- a/lib/resolve.c
++++ b/lib/resolve.c
+@@ -484,6 +484,7 @@ static int write_extra_ranked_records(const ranked_rr_array_t *arr, uint16_t reo
+
+ for (size_t i = 0; i < arr->len; ++i) {
+ ranked_rr_array_entry_t * entry = arr->at[i];
++ assert(!entry->in_progress);
+ if (!entry->to_wire) {
+ continue;
+ }
+diff --git a/lib/utils.c b/lib/utils.c
+index fe9ab03..2b093f6 100644
+--- a/lib/utils.c
++++ b/lib/utils.c
+@@ -677,6 +677,11 @@ static int to_wire_ensure_unique(ranked_rr_array_t *array, size_t index)
+ return kr_ok();
+ }
+
++/* Implementation overview of _add() and _finalize():
++ * - for rdata we just maintain a list of pointers (in knot_rrset_t::additional)
++ * - we only construct the final rdataset at the end (and thus more efficiently)
++ */
++typedef array_t(knot_rdata_t *) rdata_array_t;
+ int kr_ranked_rrarray_add(ranked_rr_array_t *array, const knot_rrset_t *rr,
+ uint8_t rank, bool to_wire, uint32_t qry_uid, knot_mm_t *pool)
+ {
+@@ -691,47 +696,93 @@ int kr_ranked_rrarray_add(ranked_rr_array_t *array, const knot_rrset_t *rr,
+ }
+ if (stashed->qry_uid != qry_uid) {
+ break;
++ /* We do not guarantee merging RRs "across" any point that switched
++ * to processing a different upstream packet (i.e. qry_uid).
++ * In particular, iterator never returns KR_STATE_YIELD. */
+ }
+ if (!rrsets_match(stashed->rr, rr)) {
+ continue;
+ }
+ /* Found the entry to merge with. Check consistency and merge. */
+- bool ok = stashed->rank == rank && !stashed->cached;
++ bool ok = stashed->rank == rank && !stashed->cached && stashed->in_progress;
+ if (!ok) {
+ assert(false);
+ return kr_error(EEXIST);
+ }
++ /* assert(rr->rrs.count == 1); */
++ /* ^^ shouldn't be a problem for this function, but it's probably a bug */
++
+ /* It may happen that an RRset is first considered useful
+ * (to_wire = false, e.g. due to being part of glue),
+ * and later we may find we also want it in the answer. */
+ stashed->to_wire = stashed->to_wire || to_wire;
+
+- return knot_rdataset_merge(&stashed->rr->rrs, &rr->rrs, pool);
++ /* We just add the reference into this in_progress RRset. */
++ rdata_array_t *ra = stashed->rr->additional;
++ if (ra == NULL) {
++ /* RRset not in array format yet -> convert it. */
++ ra = stashed->rr->additional = mm_alloc(pool, sizeof(*ra));
++ if (!ra) {
++ return kr_error(ENOMEM);
++ }
++ array_init(*ra);
++ int ret = array_reserve_mm(*ra, stashed->rr->rrs.count + rr->rrs.count,
++ kr_memreserve, pool);
++ if (ret) {
++ return kr_error(ret);
++ }
++ knot_rdata_t *r_it = stashed->rr->rrs.rdata;
++ for (int ri = 0; ri < stashed->rr->rrs.count;
++ ++ri, r_it = knot_rdataset_next(r_it)) {
++ if (array_push(*ra, r_it) < 0) {
++ abort();
++ }
++ }
++ } else {
++ int ret = array_reserve_mm(*ra, ra->len + rr->rrs.count,
++ kr_memreserve, pool);
++ if (ret) {
++ return kr_error(ret);
++ }
++ }
++ /* Append to the array. */
++ knot_rdata_t *r_it = rr->rrs.rdata;
++ for (int ri = 0; ri < rr->rrs.count;
++ ++ri, r_it = knot_rdataset_next(r_it)) {
++ if (array_push(*ra, r_it) < 0) {
++ abort();
++ }
++ }
++ return kr_ok();
+ }
+
+ /* No stashed rrset found, add */
+ int ret = array_reserve_mm(*array, array->len + 1, kr_memreserve, pool);
+- if (ret != 0) {
+- return kr_error(ENOMEM);
++ if (ret) {
++ return kr_error(ret);
+ }
+
+ ranked_rr_array_entry_t *entry = mm_alloc(pool, sizeof(ranked_rr_array_entry_t));
+ if (!entry) {
+ return kr_error(ENOMEM);
+ }
+- knot_rrset_t *copy = knot_rrset_copy(rr, pool);
+- if (!copy) {
++
++ knot_rrset_t *rr_new = knot_rrset_new(rr->owner, rr->type, rr->rclass, rr->ttl, pool);
++ if (!rr_new) {
+ mm_free(pool, entry);
+ return kr_error(ENOMEM);
+ }
++ rr_new->rrs = rr->rrs;
++ assert(rr_new->additional == NULL);
+
+ entry->qry_uid = qry_uid;
+- entry->rr = copy;
++ entry->rr = rr_new;
+ entry->rank = rank;
+ entry->revalidation_cnt = 0;
+ entry->cached = false;
+ entry->yielded = false;
+ entry->to_wire = to_wire;
++ entry->in_progress = true;
+ if (array_push(*array, entry) < 0) {
+ /* Silence coverity. It shouldn't be possible to happen,
+ * due to the array_reserve_mm call above. */
+@@ -742,6 +793,84 @@ int kr_ranked_rrarray_add(ranked_rr_array_t *array, const knot_rrset_t *rr,
+ return to_wire_ensure_unique(array, array->len - 1);
+ }
+
++/** Comparator for qsort() on an array of knot_data_t pointers. */
++static int rdata_p_cmp(const void *rp1, const void *rp2)
++{
++ /* Just correct types of the parameters and pass them dereferenced. */
++ const knot_rdata_t
++ *const *r1 = rp1,
++ *const *r2 = rp2;
++ return knot_rdata_cmp(*r1, *r2);
++}
++int kr_ranked_rrarray_finalize(ranked_rr_array_t *array, uint32_t qry_uid, knot_mm_t *pool)
++{
++ for (ssize_t array_i = array->len - 1; array_i >= 0; --array_i) {
++ ranked_rr_array_entry_t *stashed = array->at[array_i];
++ if (stashed->qry_uid != qry_uid) {
++ continue; /* We apparently can't always short-cut the cycle. */
++ }
++ if (!stashed->in_progress) {
++ continue;
++ }
++ rdata_array_t *ra = stashed->rr->additional;
++ if (!ra) {
++ /* No array, so we just need to copy the rdataset. */
++ knot_rdataset_t *rds = &stashed->rr->rrs;
++ knot_rdataset_t tmp = *rds;
++ int ret = knot_rdataset_copy(rds, &tmp, pool);
++ if (ret) {
++ return kr_error(ret);
++ }
++ } else {
++ /* Multiple RRs; first: sort the array. */
++ stashed->rr->additional = NULL;
++ qsort(ra->at, ra->len, sizeof(ra->at[0]), rdata_p_cmp);
++ /* Prune duplicates: NULL all except the last instance. */
++ int dup_count = 0;
++ for (int i = 0; i + 1 < ra->len; ++i) {
++ if (knot_rdata_cmp(ra->at[i], ra->at[i + 1]) == 0) {
++ ra->at[i] = NULL;
++ ++dup_count;
++ QRVERBOSE(NULL, "iter", "deleted duplicate RR\n");
++ }
++ }
++ /* Prepare rdataset, except rdata contents. */
++ int size_sum = 0;
++ for (int i = 0; i < ra->len; ++i) {
++ if (ra->at[i]) {
++ size_sum += knot_rdata_size(ra->at[i]->len);
++ }
++ }
++ knot_rdataset_t *rds = &stashed->rr->rrs;
++ rds->count = ra->len - dup_count;
++ #if KNOT_VERSION_HEX >= 0x020900
++ rds->size = size_sum;
++ #endif
++ if (size_sum) {
++ rds->rdata = mm_alloc(pool, size_sum);
++ if (!rds->rdata) {
++ return kr_error(ENOMEM);
++ }
++ } else {
++ rds->rdata = NULL;
++ }
++ /* Everything is ready; now just copy all the rdata. */
++ uint8_t *raw_it = (uint8_t *)rds->rdata;
++ for (int i = 0; i < ra->len; ++i) {
++ if (ra->at[i] && size_sum/*linters*/) {
++ const int size = knot_rdata_size(ra->at[i]->len);
++ memcpy(raw_it, ra->at[i], size);
++ raw_it += size;
++ }
++ }
++ assert(raw_it == (uint8_t *)rds->rdata + size_sum);
++ }
++ stashed->in_progress = false;
++ }
++ return kr_ok();
++}
++
++
+ int kr_ranked_rrarray_set_wire(ranked_rr_array_t *array, bool to_wire,
+ uint32_t qry_uid, bool check_dups,
+ bool (*extraCheck)(const ranked_rr_array_entry_t *))
+diff --git a/lib/utils.h b/lib/utils.h
+index 21eabac..3040e66 100644
+--- a/lib/utils.h
++++ b/lib/utils.h
+@@ -165,6 +165,7 @@ struct ranked_rr_array_entry {
+ bool yielded : 1;
+ bool to_wire : 1; /**< whether to be put into the answer */
+ bool expiring : 1; /**< low remaining TTL; see is_expiring; only used in cache ATM */
++ bool in_progress : 1; /**< build of RRset in progress, i.e. different format of RR data */
+ knot_rrset_t *rr;
+ };
+ typedef struct ranked_rr_array_entry ranked_rr_array_entry_t;
+@@ -351,10 +352,17 @@ KR_EXPORT
+ int kr_rrkey(char *key, uint16_t class, const knot_dname_t *owner,
+ uint16_t type, uint16_t additional);
+
+-/** @internal Add RRSet copy to ranked RR array. */
++/** Add RRSet copy to a ranked RR array.
++ *
++ * To convert to standard RRs inside, you need to call _finalize() afterwards,
++ * and the memory of rr->rrs.rdata has to remain until then.
++ */
+ KR_EXPORT
+ int kr_ranked_rrarray_add(ranked_rr_array_t *array, const knot_rrset_t *rr,
+ uint8_t rank, bool to_wire, uint32_t qry_uid, knot_mm_t *pool);
++/** Finalize in_progress sets - all with matching qry_uid. */
++KR_EXPORT
++int kr_ranked_rrarray_finalize(ranked_rr_array_t *array, uint32_t qry_uid, knot_mm_t *pool);
+
+ /** @internal Mark the RRSets from particular query as
+ * "have (not) to be recorded in the final answer".
+diff --git a/modules/dns64/dns64.lua b/modules/dns64/dns64.lua
+index 8e3eaa0..8700661 100644
+--- a/modules/dns64/dns64.lua
++++ b/modules/dns64/dns64.lua
+@@ -98,6 +98,7 @@ function M.layer.consume(state, req, pkt)
+ req.pool)
+ end
+ end
++ ffi.C.kr_ranked_rrarray_finalize(req.answ_selected, qry.uid, req.pool);
+ end
+
+ return M