diff options
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.patch | 233 |
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. */ |