diff options
Diffstat (limited to '')
-rw-r--r-- | debian/patches/CVE-2019-10191.patch | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/debian/patches/CVE-2019-10191.patch b/debian/patches/CVE-2019-10191.patch new file mode 100644 index 0000000..1d4a4b5 --- /dev/null +++ b/debian/patches/CVE-2019-10191.patch @@ -0,0 +1,158 @@ +From: Markus Koschany <apo@debian.org> +Date: Mon, 11 Mar 2024 14:24:02 +0100 +Subject: CVE-2019-10191 + +Bug-Debian: https://bugs.debian.org/932048 +Origin: https://gitlab.labs.nic.cz/knot/knot-resolver/merge_requests/839 +--- + daemon/lua/kres-gen.lua | 1 + + daemon/worker.c | 5 ++++- + lib/cache/api.c | 4 +++- + lib/cache/impl.h | 3 ++- + lib/layer.h | 7 ++++++- + lib/layer/iterate.c | 11 ++++++++++- + lib/resolve.c | 2 ++ + lib/rplan.h | 2 ++ + 8 files changed, 30 insertions(+), 5 deletions(-) + +diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua +index eeb8ff7..9e9f586 100644 +--- a/daemon/lua/kres-gen.lua ++++ b/daemon/lua/kres-gen.lua +@@ -120,6 +120,7 @@ struct kr_qflags { + _Bool DNS64_MARK : 1; + _Bool CACHE_TRIED : 1; + _Bool NO_NS_FOUND : 1; ++ _Bool PKT_IS_SANE : 1; + }; + typedef struct { + knot_rrset_t **at; +diff --git a/daemon/worker.c b/daemon/worker.c +index 117cc91..1235979 100644 +--- a/daemon/worker.c ++++ b/daemon/worker.c +@@ -1611,8 +1611,11 @@ int worker_submit(struct session *session, knot_pkt_t *query) + return kr_error(ENOMEM); + } + } else if (query) { /* response from upstream */ +- task = session_tasklist_del_msgid(session, knot_wire_get_id(query->wire)); ++ const uint16_t id = knot_wire_get_id(query->wire); ++ task = session_tasklist_del_msgid(session, id); + if (task == NULL) { ++ VERBOSE_MSG(NULL, "=> ignoring packet with mismatching ID %d\n", ++ (int)id); + return kr_error(ENOENT); + } + assert(!session_flags(session)->closing); +diff --git a/lib/cache/api.c b/lib/cache/api.c +index c0591d6..4c7f3d2 100644 +--- a/lib/cache/api.c ++++ b/lib/cache/api.c +@@ -408,7 +408,9 @@ int cache_stash(kr_layer_t *ctx, knot_pkt_t *pkt) + /* LATER(optim.): typically we also have corresponding NS record in the list, + * so we might save a cache operation. */ + +- stash_pkt(pkt, qry, req, has_optout); ++ if (qry->flags.PKT_IS_SANE && check_dname_for_lf(knot_pkt_qname(pkt), qry)) { ++ stash_pkt(pkt, qry, req, has_optout); ++ } + + finally: + if (unauth_cnt) { +diff --git a/lib/cache/impl.h b/lib/cache/impl.h +index a08f355..ffb5e67 100644 +--- a/lib/cache/impl.h ++++ b/lib/cache/impl.h +@@ -253,7 +253,8 @@ void entry_list_memcpy(struct entry_apex *ea, entry_list_t list); + /* Packet caching; implementation in ./entry_pkt.c */ + + /** Stash the packet into cache (if suitable, etc.) +- * \param has_optout whether the packet contains an opt-out NSEC3 */ ++ * \param has_optout whether the packet contains an opt-out NSEC3 ++ * It assumes check_dname_for_lf(). */ + void stash_pkt(const knot_pkt_t *pkt, const struct kr_query *qry, + const struct kr_request *req, bool has_optout); + +diff --git a/lib/layer.h b/lib/layer.h +index 0909cb7..011d279 100644 +--- a/lib/layer.h ++++ b/lib/layer.h +@@ -48,7 +48,12 @@ + enum kr_layer_state { + KR_STATE_CONSUME = 1 << 0, /*!< Consume data. */ + KR_STATE_PRODUCE = 1 << 1, /*!< Produce data. */ +- KR_STATE_DONE = 1 << 2, /*!< Finished successfully. */ ++ ++ /*! Finished successfully or a special case: in CONSUME phase this can ++ * be used (by iterator) to do a transition to PRODUCE phase again, ++ * in which case the packet wasn't accepted for some reason. */ ++ KR_STATE_DONE = 1 << 2, ++ + KR_STATE_FAIL = 1 << 3, /*!< Error. */ + KR_STATE_YIELD = 1 << 4, /*!< Paused, waiting for a sub-query. */ + }; +diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c +index ee2607e..feaadf0 100644 +--- a/lib/layer/iterate.c ++++ b/lib/layer/iterate.c +@@ -81,10 +81,14 @@ static bool is_paired_to_query(const knot_pkt_t *answer, struct kr_query *query) + uint16_t qtype = query->stype; + const knot_dname_t *qname = minimized_qname(query, &qtype); + ++ /* ID should already match, thanks to session_tasklist_del_msgid() ++ * in worker_submit(), but it won't hurt to check again. */ + return query->id == knot_wire_get_id(answer->wire) && +- knot_wire_get_qdcount(answer->wire) > 0 && ++ knot_wire_get_qdcount(answer->wire) == 1 && + query->sclass == knot_pkt_qclass(answer) && + qtype == knot_pkt_qtype(answer) && ++ /* qry->secret had been xor-applied to answer already, ++ * so this also checks for correctness of case randomization */ + knot_dname_is_equal(qname, knot_pkt_qname(answer)); + } + +@@ -1029,6 +1033,7 @@ static int resolve(kr_layer_t *ctx, knot_pkt_t *pkt) + if (!query) { + return ctx->state; + } ++ query->flags.PKT_IS_SANE = false; + + WITH_VERBOSE(query) { + if (query->flags.TRACE) { +@@ -1072,6 +1077,10 @@ static int resolve(kr_layer_t *ctx, knot_pkt_t *pkt) + return KR_STATE_CONSUME; + } + ++ /* If exiting above here, there's no sense to put it into packet cache. ++ * The most important part is to check for spoofing: is_paired_to_query() */ ++ query->flags.PKT_IS_SANE = true; ++ + #ifndef NOVERBOSELOG + const knot_lookup_t *rcode = knot_lookup_by_id(knot_rcode_names, knot_wire_get_rcode(pkt->wire)); + #endif +diff --git a/lib/resolve.c b/lib/resolve.c +index b4b3657..b771cdc 100644 +--- a/lib/resolve.c ++++ b/lib/resolve.c +@@ -150,6 +150,8 @@ static void randomized_qname_case(knot_dname_t * restrict qname, uint32_t secret + assert(qname); + const int len = knot_dname_size(qname) - 2; /* Skip first, last label. */ + for (int i = 0; i < len; ++i) { ++ /* Note: this relies on the fact that correct label lengths ++ * can't pass the isletter() test (by "luck"). */ + if (isletter(*++qname)) { + *qname ^= ((secret >> (i & 31)) & 1) * 0x20; + } +diff --git a/lib/rplan.h b/lib/rplan.h +index 21b0b0b..7e82b03 100644 +--- a/lib/rplan.h ++++ b/lib/rplan.h +@@ -64,6 +64,8 @@ struct kr_qflags { + bool DNS64_MARK : 1; /**< Internal mark for dns64 module. */ + bool CACHE_TRIED : 1; /**< Internal to cache module. */ + bool NO_NS_FOUND : 1; /**< No valid NS found during last PRODUCE stage. */ ++ bool PKT_IS_SANE : 1; /**< Set by iterator in consume phase to indicate whether ++ * some basic aspects of the packet are OK, e.g. QNAME. */ + }; + + /** Combine flags together. This means set union for simple flags. */ |