summaryrefslogtreecommitdiffstats
path: root/debian/patches/0010-mitigate-KeyTrap-DoS-CVE-2023-50387.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/0010-mitigate-KeyTrap-DoS-CVE-2023-50387.patch')
-rw-r--r--debian/patches/0010-mitigate-KeyTrap-DoS-CVE-2023-50387.patch233
1 files changed, 233 insertions, 0 deletions
diff --git a/debian/patches/0010-mitigate-KeyTrap-DoS-CVE-2023-50387.patch b/debian/patches/0010-mitigate-KeyTrap-DoS-CVE-2023-50387.patch
new file mode 100644
index 0000000..d6109e0
--- /dev/null
+++ b/debian/patches/0010-mitigate-KeyTrap-DoS-CVE-2023-50387.patch
@@ -0,0 +1,233 @@
+From: =?utf-8?b?VmxhZGltw61yIMSMdW7DoXQ=?= <vladimir.cunat@nic.cz>
+Date: Mon, 1 Jan 2024 16:21:10 +0100
+Subject: mitigate KeyTrap DoS = CVE-2023-50387
+
+---
+ daemon/engine.c | 1 +
+ daemon/lua/kres-gen-30.lua | 3 +++
+ daemon/lua/kres-gen-31.lua | 3 +++
+ daemon/lua/kres-gen-32.lua | 3 +++
+ lib/defines.h | 2 ++
+ lib/dnssec.c | 28 ++++++++++++++++++++++++++++
+ lib/dnssec.h | 1 +
+ lib/layer/validate.c | 7 +++++++
+ lib/resolve.h | 3 +++
+ lib/rplan.h | 6 ++++++
+ 10 files changed, 57 insertions(+)
+
+diff --git a/daemon/engine.c b/daemon/engine.c
+index 26c225f..a3f439f 100644
+--- a/daemon/engine.c
++++ b/daemon/engine.c
+@@ -492,6 +492,7 @@ static int init_resolver(struct engine *engine)
+ /* Open resolution context */
+ ctx->trust_anchors = trie_create(NULL);
+ ctx->negative_anchors = trie_create(NULL);
++ ctx->vld_limit_crypto = KR_VLD_LIMIT_CRYPTO_DEFAULT;
+ ctx->pool = engine->pool;
+ ctx->modules = &engine->modules;
+ ctx->cache_rtt_tout_retry_interval = KR_NS_TIMEOUT_RETRY_INTERVAL;
+diff --git a/daemon/lua/kres-gen-30.lua b/daemon/lua/kres-gen-30.lua
+index 4353c5c..01ae6ac 100644
+--- a/daemon/lua/kres-gen-30.lua
++++ b/daemon/lua/kres-gen-30.lua
+@@ -336,6 +336,8 @@ struct kr_query {
+ struct kr_qflags forward_flags;
+ uint32_t secret;
+ uint32_t uid;
++ int32_t vld_limit_crypto_remains;
++ uint32_t vld_limit_uid;
+ uint64_t creation_time_mono;
+ uint64_t timestamp_mono;
+ struct timeval timestamp;
+@@ -353,6 +355,7 @@ struct kr_context {
+ knot_rrset_t *upstream_opt_rr;
+ trie_t *trust_anchors;
+ trie_t *negative_anchors;
++ int32_t vld_limit_crypto;
+ struct kr_zonecut root_hints;
+ struct kr_cache cache;
+ unsigned int cache_rtt_tout_retry_interval;
+diff --git a/daemon/lua/kres-gen-31.lua b/daemon/lua/kres-gen-31.lua
+index a68dd65..c3845ec 100644
+--- a/daemon/lua/kres-gen-31.lua
++++ b/daemon/lua/kres-gen-31.lua
+@@ -336,6 +336,8 @@ struct kr_query {
+ struct kr_qflags forward_flags;
+ uint32_t secret;
+ uint32_t uid;
++ int32_t vld_limit_crypto_remains;
++ uint32_t vld_limit_uid;
+ uint64_t creation_time_mono;
+ uint64_t timestamp_mono;
+ struct timeval timestamp;
+@@ -353,6 +355,7 @@ struct kr_context {
+ knot_rrset_t *upstream_opt_rr;
+ trie_t *trust_anchors;
+ trie_t *negative_anchors;
++ int32_t vld_limit_crypto;
+ struct kr_zonecut root_hints;
+ struct kr_cache cache;
+ unsigned int cache_rtt_tout_retry_interval;
+diff --git a/daemon/lua/kres-gen-32.lua b/daemon/lua/kres-gen-32.lua
+index 222891e..2c407d4 100644
+--- a/daemon/lua/kres-gen-32.lua
++++ b/daemon/lua/kres-gen-32.lua
+@@ -337,6 +337,8 @@ struct kr_query {
+ struct kr_qflags forward_flags;
+ uint32_t secret;
+ uint32_t uid;
++ int32_t vld_limit_crypto_remains;
++ uint32_t vld_limit_uid;
+ uint64_t creation_time_mono;
+ uint64_t timestamp_mono;
+ struct timeval timestamp;
+@@ -354,6 +356,7 @@ struct kr_context {
+ knot_rrset_t *upstream_opt_rr;
+ trie_t *trust_anchors;
+ trie_t *negative_anchors;
++ int32_t vld_limit_crypto;
+ struct kr_zonecut root_hints;
+ struct kr_cache cache;
+ unsigned int cache_rtt_tout_retry_interval;
+diff --git a/lib/defines.h b/lib/defines.h
+index 6b6dac5..e832892 100644
+--- a/lib/defines.h
++++ b/lib/defines.h
+@@ -57,6 +57,8 @@ static inline int KR_COLD kr_error(int x) {
+ #define KR_COUNT_NO_NSADDR_LIMIT 5
+ #define KR_CONSUME_FAIL_ROW_LIMIT 3 /* Maximum number of KR_STATE_FAIL in a row. */
+
++#define KR_VLD_LIMIT_CRYPTO_DEFAULT 32 /**< default for struct kr_query::vld_limit_crypto */
++
+ /*
+ * Defines.
+ */
+diff --git a/lib/dnssec.c b/lib/dnssec.c
+index c536357..1e6eb58 100644
+--- a/lib/dnssec.c
++++ b/lib/dnssec.c
+@@ -240,6 +240,29 @@ fail:
+ return NULL;
+ }
+
++/// Return if we want to afford yet another crypto-validation (and account it).
++static bool check_crypto_limit(const kr_rrset_validation_ctx_t *vctx)
++{
++ if (vctx->limit_crypto_remains == NULL)
++ return true; // no limiting
++ if (*vctx->limit_crypto_remains > 0) {
++ --*vctx->limit_crypto_remains;
++ return true;
++ }
++ // We got over limit. There are optional actions to do.
++ if (vctx->log_qry && kr_log_is_debug_qry(VALIDATOR, vctx->log_qry)) {
++ auto_free char *name_str = kr_dname_text(vctx->zone_name);
++ kr_log_q(vctx->log_qry, VALIDATOR,
++ "expensive crypto limited, mitigating CVE-2023-50387, current zone: %s\n",
++ name_str);
++ }
++ if (vctx->log_qry && vctx->log_qry->request) {
++ kr_request_set_extended_error(vctx->log_qry->request, KNOT_EDNS_EDE_BOGUS,
++ "EAIE: expensive crypto limited, mitigating CVE-2023-50387");
++ }
++ return false;
++}
++
+ static int kr_svldr_rrset_with_key(knot_rrset_t *rrs, const knot_rdataset_t *rrsigs,
+ kr_rrset_validation_ctx_t *vctx, const kr_svldr_key_t *key)
+ {
+@@ -258,6 +281,8 @@ static int kr_svldr_rrset_with_key(knot_rrset_t *rrs, const knot_rdataset_t *rrs
+ } else if (retv != 0) {
+ continue;
+ }
++ if (!check_crypto_limit(vctx))
++ return vctx->result = kr_error(E2BIG);
+ // We only expect non-expanded wildcard records in input;
+ // that also means we don't need to perform non-existence proofs.
+ const int trim_labels = (val_flgs & FLG_WILDCARD_EXPANSION) ? 1 : 0;
+@@ -367,6 +392,9 @@ static int kr_rrset_validate_with_key(kr_rrset_validation_ctx_t *vctx,
+ break;
+ }
+ }
++ if (!check_crypto_limit(vctx)) {
++ goto finish;
++ }
+ if (kr_check_signature(rdata_j, key, covered, trim_labels) != 0) {
+ vctx->rrs_counters.crypto_invalid++;
+ continue;
+diff --git a/lib/dnssec.h b/lib/dnssec.h
+index 0fbd47c..ca737cf 100644
+--- a/lib/dnssec.h
++++ b/lib/dnssec.h
+@@ -44,6 +44,7 @@ struct kr_rrset_validation_ctx {
+ uint32_t flags; /*!< Output - Flags. */
+ uint32_t err_cnt; /*!< Output - Number of validation failures. */
+ uint32_t cname_norrsig_cnt; /*!< Output - Number of CNAMEs missing RRSIGs. */
++ int32_t *limit_crypto_remains; /*!< Optional pointer to struct kr_query::vld_limit_crypto_remains */
+
+ /** Validation result: kr_error() code.
+ *
+diff --git a/lib/layer/validate.c b/lib/layer/validate.c
+index 6c0d7ad..4882da8 100644
+--- a/lib/layer/validate.c
++++ b/lib/layer/validate.c
+@@ -276,6 +276,7 @@ static int validate_records(struct kr_request *req, knot_pkt_t *answer, knot_mm_
+ .err_cnt = 0,
+ .cname_norrsig_cnt = 0,
+ .result = 0,
++ .limit_crypto_remains = &qry->vld_limit_crypto_remains,
+ .log_qry = qry,
+ };
+
+@@ -384,6 +385,7 @@ static int validate_keyset(struct kr_request *req, knot_pkt_t *answer, bool has_
+ .has_nsec3 = has_nsec3,
+ .flags = 0,
+ .result = 0,
++ .limit_crypto_remains = &qry->vld_limit_crypto_remains,
+ .log_qry = qry,
+ };
+ int ret = kr_dnskeys_trusted(&vctx, sig_rds, qry->zone_cut.trust_anchor);
+@@ -1030,6 +1032,11 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
+
++ if (qry->vld_limit_uid != qry->uid) {
++ qry->vld_limit_uid = qry->uid;
++ qry->vld_limit_crypto_remains = req->ctx->vld_limit_crypto;
++ }
++
+ /* Ignore faulty or unprocessed responses. */
+ if (ctx->state & (KR_STATE_FAIL|KR_STATE_CONSUME)) {
+ return ctx->state;
+diff --git a/lib/resolve.h b/lib/resolve.h
+index 97ba07b..a2d5ec9 100644
+--- a/lib/resolve.h
++++ b/lib/resolve.h
+@@ -162,6 +162,9 @@ struct kr_context
+
+ trie_t *trust_anchors;
+ trie_t *negative_anchors;
++ /** Validator's limit on the number of cryptographic steps for a single upstream packet. */
++ int32_t vld_limit_crypto;
++
+ struct kr_zonecut root_hints;
+ struct kr_cache cache;
+ unsigned cache_rtt_tout_retry_interval;
+diff --git a/lib/rplan.h b/lib/rplan.h
+index 891781f..68174af 100644
+--- a/lib/rplan.h
++++ b/lib/rplan.h
+@@ -87,6 +87,12 @@ struct kr_query {
+ struct kr_qflags forward_flags;
+ uint32_t secret;
+ uint32_t uid; /**< Query iteration number, unique within the kr_rplan. */
++
++ /** Remaining limit; see kr_query::vld_limit_crypto docs */
++ int32_t vld_limit_crypto_remains;
++ /** ::uid value to which this remaining limit applies. */
++ uint32_t vld_limit_uid;
++
+ uint64_t creation_time_mono; /* The time of query's creation (milliseconds).
+ * Or time of creation of an oldest
+ * ancestor if it is a subquery. */