112 lines
4.2 KiB
Diff
112 lines
4.2 KiB
Diff
From b4c3ce6fb9b2aebbbe7d802ce48c691a9cabcf4f Mon Sep 17 00:00:00 2001
|
|
From: Nicolas Williams <nico@twosigma.com>
|
|
Date: Wed, 10 Mar 2021 16:49:04 -0600
|
|
Subject: [PATCH 1/2] CVE-2022-44640 HEIMDAL: asn1: Invalid free in ASN.1 codec
|
|
|
|
This is a 10.0 on the Common Vulnerability Scoring System (CVSS) v3.
|
|
|
|
Heimdal's ASN.1 compiler generates code that allows specially
|
|
crafted DER encodings of CHOICEs to invoke the wrong free function
|
|
on the decoded structure upon decode error. This is known to impact
|
|
the Heimdal KDC, leading to an invalid free() of an address partly
|
|
or wholly under the control of the attacker, in turn leading to a
|
|
potential remote code execution (RCE) vulnerability.
|
|
|
|
This error affects the DER codec for all CHOICE types used in
|
|
Heimdal, though not all cases will be exploitable. We have not
|
|
completed a thorough analysis of all the Heimdal components
|
|
affected, thus the Kerberos client, the X.509 library, and other
|
|
parts, may be affected as well.
|
|
|
|
This bug has been in Heimdal since 2005. It was first reported by
|
|
Douglas Bagnall, though it had been found independently by the
|
|
Heimdal maintainers via fuzzing a few weeks earlier.
|
|
|
|
While no zero-day exploit is known, such an exploit will likely be
|
|
available soon after public disclosure.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14929
|
|
|
|
[abartlet@samba.org Adapted from Heimdal commit
|
|
ea5ec8f174920cb80ce2b168b49195378420449e for older Heimdal in Samba 4.15
|
|
by dropping fuzz-inputs file and EXPORTS entry for fuzzing]
|
|
|
|
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
Reviewed-by: Stefan Metzmacher <metze@samba.org>
|
|
|
|
Conflict: NA
|
|
Reference: https://attachments.samba.org/attachment.cgi?id=17679
|
|
---
|
|
source4/heimdal/lib/asn1/gen_decode.c | 12 ++++++------
|
|
source4/heimdal/lib/asn1/gen_free.c | 7 +++++++
|
|
2 files changed, 13 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/source4/heimdal/lib/asn1/gen_decode.c b/source4/heimdal/lib/asn1/gen_decode.c
|
|
index 9d816d5400d7..bf2d93b806df 100644
|
|
--- a/source4/heimdal/lib/asn1/gen_decode.c
|
|
+++ b/source4/heimdal/lib/asn1/gen_decode.c
|
|
@@ -584,14 +584,14 @@ decode_type (const char *name, const Type *t, int optional,
|
|
classname(cl),
|
|
ty ? "CONS" : "PRIM",
|
|
valuename(cl, tag));
|
|
+ fprintf(codefile,
|
|
+ "(%s)->element = %s;\n",
|
|
+ name, m->label);
|
|
if (asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&",
|
|
name, m->gen_name) < 0 || s == NULL)
|
|
errx(1, "malloc");
|
|
decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL,
|
|
depth + 1);
|
|
- fprintf(codefile,
|
|
- "(%s)->element = %s;\n",
|
|
- name, m->label);
|
|
free(s);
|
|
fprintf(codefile,
|
|
"}\n");
|
|
@@ -600,23 +600,23 @@ decode_type (const char *name, const Type *t, int optional,
|
|
if (have_ellipsis) {
|
|
fprintf(codefile,
|
|
"else {\n"
|
|
+ "(%s)->element = %s;\n"
|
|
"(%s)->u.%s.data = calloc(1, len);\n"
|
|
"if ((%s)->u.%s.data == NULL) {\n"
|
|
"e = ENOMEM; %s;\n"
|
|
"}\n"
|
|
"(%s)->u.%s.length = len;\n"
|
|
"memcpy((%s)->u.%s.data, p, len);\n"
|
|
- "(%s)->element = %s;\n"
|
|
"p += len;\n"
|
|
"ret += len;\n"
|
|
"len = 0;\n"
|
|
"}\n",
|
|
+ name, have_ellipsis->label,
|
|
name, have_ellipsis->gen_name,
|
|
name, have_ellipsis->gen_name,
|
|
forwstr,
|
|
name, have_ellipsis->gen_name,
|
|
- name, have_ellipsis->gen_name,
|
|
- name, have_ellipsis->label);
|
|
+ name, have_ellipsis->gen_name);
|
|
} else {
|
|
fprintf(codefile,
|
|
"else {\n"
|
|
diff --git a/source4/heimdal/lib/asn1/gen_free.c b/source4/heimdal/lib/asn1/gen_free.c
|
|
index b9cae7533b17..74449fe6ca82 100644
|
|
--- a/source4/heimdal/lib/asn1/gen_free.c
|
|
+++ b/source4/heimdal/lib/asn1/gen_free.c
|
|
@@ -61,6 +61,13 @@ free_type (const char *name, const Type *t, int preserve)
|
|
case TNull:
|
|
case TGeneralizedTime:
|
|
case TUTCTime:
|
|
+ /*
|
|
+ * This doesn't do much, but it leaves zeros where garbage might
|
|
+ * otherwise have been found. Gets us closer to having the equivalent
|
|
+ * of a memset()-to-zero data structure after calling the free
|
|
+ * functions.
|
|
+ */
|
|
+ fprintf(codefile, "*%s = 0;\n", name);
|
|
break;
|
|
case TBitString:
|
|
if (ASN1_TAILQ_EMPTY(t->members))
|
|
--
|
|
2.34.1
|