[ntp/f20] validate lengths of values in extension fields (CVE-2014-9297)
Miroslav Lichvar
mlichvar at fedoraproject.org
Thu Feb 5 14:52:39 UTC 2015
commit 5f1c8505ee34165a9f76a6985d25607aadb55d6c
Author: Miroslav Lichvar <mlichvar at redhat.com>
Date: Thu Feb 5 15:30:25 2015 +0100
validate lengths of values in extension fields (CVE-2014-9297)
ntp-4.2.6p5-cve-2014-9297.patch | 375 +++++++++++++++++++++++++++++++++++++++
ntp.spec | 3 +
2 files changed, 378 insertions(+), 0 deletions(-)
---
diff --git a/ntp-4.2.6p5-cve-2014-9297.patch b/ntp-4.2.6p5-cve-2014-9297.patch
new file mode 100644
index 0000000..1364e8c
--- /dev/null
+++ b/ntp-4.2.6p5-cve-2014-9297.patch
@@ -0,0 +1,375 @@
+http://bk.ntp.org/ntp-stable/?PAGE=patch&REV=54abb266In81wLNAqIaovtP8f2UmUw
+http://bk.ntp.org/ntp-stable/?PAGE=patch&REV=54a7c595jlwS3KmAxBML75HFGLR_pQ
+http://bk.ntp.org/ntp-stable/?PAGE=patch&REV=5492d353ncauuWt_PONxaDhC5Qv_SA
+
+diff -up ntp-4.2.6p5/ntpd/ntp_crypto.c.cve-2014-9297 ntp-4.2.6p5/ntpd/ntp_crypto.c
+--- ntp-4.2.6p5/ntpd/ntp_crypto.c.cve-2014-9297 2015-02-04 11:37:44.488673076 +0100
++++ ntp-4.2.6p5/ntpd/ntp_crypto.c 2015-02-04 11:37:44.491673082 +0100
+@@ -109,6 +109,7 @@
+ #define TAI_1972 10 /* initial TAI offset (s) */
+ #define MAX_LEAP 100 /* max UTC leapseconds (s) */
+ #define VALUE_LEN (6 * 4) /* min response field length */
++#define MAX_VALLEN (65535 - VALUE_LEN)
+ #define YEAR (60 * 60 * 24 * 365) /* seconds in year */
+
+ /*
+@@ -147,8 +148,8 @@ static char *rand_file = NULL; /* random
+ */
+ static int crypto_verify (struct exten *, struct value *,
+ struct peer *);
+-static int crypto_encrypt (struct exten *, struct value *,
+- keyid_t *);
++static int crypto_encrypt (const u_char *, u_int, keyid_t *,
++ struct value *);
+ static int crypto_alice (struct peer *, struct value *);
+ static int crypto_alice2 (struct peer *, struct value *);
+ static int crypto_alice3 (struct peer *, struct value *);
+@@ -444,6 +445,12 @@ crypto_recv(
+ tstamp = ntohl(ep->tstamp);
+ fstamp = ntohl(ep->fstamp);
+ vallen = ntohl(ep->vallen);
++ /*
++ * Bug 2761: I hope this isn't too early...
++ */
++ if ( vallen == 0
++ || len - VALUE_LEN < vallen)
++ return XEVNT_LEN;
+ }
+ switch (code) {
+
+@@ -494,8 +501,9 @@ crypto_recv(
+ rval = XEVNT_ERR;
+ break;
+ }
++ INSIST(len >= VALUE_LEN);
+ if (vallen == 0 || vallen > MAXHOSTNAME ||
+- len < VALUE_LEN + vallen) {
++ len - VALUE_LEN < vallen) {
+ rval = XEVNT_LEN;
+ break;
+ }
+@@ -1162,11 +1170,11 @@ crypto_xmit(
+ * choice.
+ */
+ case CRYPTO_CERT | CRYPTO_RESP:
+- vallen = ntohl(ep->vallen);
+- if (vallen == 0 || vallen > MAXHOSTNAME) {
++ vallen = ntohl(ep->vallen); /* Must be <64k */
++ if (vallen == 0 || vallen > MAXHOSTNAME ||
++ len - VALUE_LEN < vallen) {
+ rval = XEVNT_LEN;
+ break;
+-
+ } else {
+ memcpy(certname, ep->pkt, vallen);
+ certname[vallen] = '\0';
+@@ -1315,7 +1323,10 @@ crypto_xmit(
+ * anything goes wrong.
+ */
+ case CRYPTO_COOK | CRYPTO_RESP:
+- if ((opcode & 0xffff) < VALUE_LEN) {
++ vallen = ntohl(ep->vallen); /* Must be <64k */
++ if ( vallen == 0
++ || (vallen >= MAX_VALLEN)
++ || (opcode & 0x0000ffff) < VALUE_LEN + vallen) {
+ rval = XEVNT_LEN;
+ break;
+ }
+@@ -1323,8 +1334,8 @@ crypto_xmit(
+ tcookie = cookie;
+ else
+ tcookie = peer->hcookie;
+- if ((rval = crypto_encrypt(ep, &vtemp, &tcookie)) ==
+- XEVNT_OK) {
++ if ((rval = crypto_encrypt((const u_char *)ep->pkt, vallen, &tcookie, &vtemp))
++ == XEVNT_OK) {
+ len = crypto_send(fp, &vtemp, start);
+ value_free(&vtemp);
+ }
+@@ -1464,13 +1475,16 @@ crypto_verify(
+ * up to the next word (4 octets).
+ */
+ vallen = ntohl(ep->vallen);
+- if (vallen == 0)
++ if ( vallen == 0
++ || vallen > MAX_VALLEN)
+ return (XEVNT_LEN);
+
+ i = (vallen + 3) / 4;
+ siglen = ntohl(ep->pkt[i++]);
+- if (len < VALUE_LEN + ((vallen + 3) / 4) * 4 + ((siglen + 3) /
+- 4) * 4)
++ if ( siglen > MAX_VALLEN
++ || len - VALUE_LEN < ((vallen + 3) / 4) * 4
++ || len - VALUE_LEN - ((vallen + 3) / 4) * 4
++ < ((siglen + 3) / 4) * 4)
+ return (XEVNT_LEN);
+
+ /*
+@@ -1528,6 +1542,7 @@ crypto_verify(
+ * proventic bit. What a relief.
+ */
+ EVP_VerifyInit(&ctx, peer->digest);
++ /* XXX: the "+ 12" needs to be at least documented... */
+ EVP_VerifyUpdate(&ctx, (u_char *)&ep->tstamp, vallen + 12);
+ if (EVP_VerifyFinal(&ctx, (u_char *)&ep->pkt[i], siglen,
+ pkey) <= 0)
+@@ -1540,34 +1555,32 @@ crypto_verify(
+
+
+ /*
+- * crypto_encrypt - construct encrypted cookie and signature from
+- * extension field and cookie
++ * crypto_encrypt - construct vp (encrypted cookie and signature) from
++ * the public key and cookie.
+ *
+- * Returns
++ * Returns:
+ * XEVNT_OK success
+ * XEVNT_CKY bad or missing cookie
+ * XEVNT_PUB bad or missing public key
+ */
+ static int
+ crypto_encrypt(
+- struct exten *ep, /* extension pointer */
+- struct value *vp, /* value pointer */
+- keyid_t *cookie /* server cookie */
++ const u_char *ptr, /* Public Key */
++ u_int vallen, /* Length of Public Key */
++ keyid_t *cookie, /* server cookie */
++ struct value *vp /* value pointer */
+ )
+ {
+ EVP_PKEY *pkey; /* public key */
+ EVP_MD_CTX ctx; /* signature context */
+ tstamp_t tstamp; /* NTP timestamp */
+ u_int32 temp32;
+- u_int len;
+- u_char *ptr;
++ u_char *puch;
+
+ /*
+ * Extract the public key from the request.
+ */
+- len = ntohl(ep->vallen);
+- ptr = (u_char *)ep->pkt;
+- pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, len);
++ pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, vallen);
+ if (pkey == NULL) {
+ msyslog(LOG_ERR, "crypto_encrypt: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+@@ -1581,12 +1594,12 @@ crypto_encrypt(
+ tstamp = crypto_time();
+ vp->tstamp = htonl(tstamp);
+ vp->fstamp = hostval.tstamp;
+- len = EVP_PKEY_size(pkey);
+- vp->vallen = htonl(len);
+- vp->ptr = emalloc(len);
+- ptr = vp->ptr;
++ vallen = EVP_PKEY_size(pkey);
++ vp->vallen = htonl(vallen);
++ vp->ptr = emalloc(vallen);
++ puch = vp->ptr;
+ temp32 = htonl(*cookie);
+- if (RSA_public_encrypt(4, (u_char *)&temp32, ptr,
++ if (RSA_public_encrypt(4, (u_char *)&temp32, puch,
+ pkey->pkey.rsa, RSA_PKCS1_OAEP_PADDING) <= 0) {
+ msyslog(LOG_ERR, "crypto_encrypt: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+@@ -1601,8 +1614,8 @@ crypto_encrypt(
+ vp->sig = emalloc(sign_siglen);
+ EVP_SignInit(&ctx, sign_digest);
+ EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
+- EVP_SignUpdate(&ctx, vp->ptr, len);
+- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
++ EVP_SignUpdate(&ctx, vp->ptr, vallen);
++ if (EVP_SignFinal(&ctx, vp->sig, &vallen, sign_pkey))
+ vp->siglen = htonl(sign_siglen);
+ return (XEVNT_OK);
+ }
+@@ -1673,6 +1686,9 @@ crypto_ident(
+ * call in the protocol module.
+ *
+ * Returns extension field pointer (no errors)
++ *
++ * XXX: opcode and len should really be 32-bit quantities and
++ * we should make sure that str is not too big.
+ */
+ struct exten *
+ crypto_args(
+@@ -1685,24 +1701,31 @@ crypto_args(
+ tstamp_t tstamp; /* NTP timestamp */
+ struct exten *ep; /* extension field pointer */
+ u_int len; /* extension field length */
++ size_t slen;
+
+ tstamp = crypto_time();
+ len = sizeof(struct exten);
+- if (str != NULL)
+- len += strlen(str);
++ if (str != NULL) {
++ slen = strlen(str);
++ INSIST(slen < MAX_VALLEN);
++ len += slen;
++ }
+ ep = emalloc(len);
+ memset(ep, 0, len);
+ if (opcode == 0)
+ return (ep);
+
++ REQUIRE(0 == (len & ~0x0000ffff));
++ REQUIRE(0 == (opcode & ~0xffff0000));
++
+ ep->opcode = htonl(opcode + len);
+ ep->associd = htonl(associd);
+ ep->tstamp = htonl(tstamp);
+ ep->fstamp = hostval.tstamp;
+ ep->vallen = 0;
+ if (str != NULL) {
+- ep->vallen = htonl(strlen(str));
+- memcpy((char *)ep->pkt, str, strlen(str));
++ ep->vallen = htonl(slen);
++ memcpy((char *)ep->pkt, str, slen);
+ }
+ return (ep);
+ }
+@@ -1715,6 +1738,8 @@ crypto_args(
+ * Note: it is not polite to send a nonempty signature with zero
+ * timestamp or a nonzero timestamp with an empty signature, but those
+ * rules are not enforced here.
++ *
++ * XXX This code won't work on a box with 16-bit ints.
+ */
+ int
+ crypto_send(
+@@ -1730,8 +1755,9 @@ crypto_send(
+ * Calculate extension field length and check for buffer
+ * overflow. Leave room for the MAC.
+ */
+- len = 16;
++ len = 16; /* XXX Document! */
+ vallen = ntohl(vp->vallen);
++ INSIST(vallen <= MAX_VALLEN);
+ len += ((vallen + 3) / 4 + 1) * 4;
+ siglen = ntohl(vp->siglen);
+ len += ((siglen + 3) / 4 + 1) * 4;
+@@ -1772,6 +1798,7 @@ crypto_send(
+ }
+ opcode = ntohl(ep->opcode);
+ ep->opcode = htonl((opcode & 0xffff0000) | len);
++ ENSURE(len <= MAX_VALLEN);
+ return (len);
+ }
+
+@@ -1807,7 +1834,6 @@ crypto_update(void)
+ if (hostval.tstamp == 0)
+ return;
+
+-
+ /*
+ * Sign public key and timestamps. The filestamp is derived from
+ * the host key file extension from wherever the file was
+@@ -2108,7 +2134,8 @@ crypto_bob(
+ tstamp_t tstamp; /* NTP timestamp */
+ BIGNUM *bn, *bk, *r;
+ u_char *ptr;
+- u_int len;
++ u_int len; /* extension field length */
++ u_int vallen = 0; /* value length */
+
+ /*
+ * If the IFF parameters are not valid, something awful
+@@ -2123,8 +2150,11 @@ crypto_bob(
+ /*
+ * Extract r from the challenge.
+ */
+- len = ntohl(ep->vallen);
+- if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
++ vallen = ntohl(ep->vallen);
++ len = ntohl(ep->opcode) & 0x0000ffff;
++ if (vallen == 0 || len < VALUE_LEN || len - VALUE_LEN < vallen)
++ return XEVNT_LEN;
++ if ((r = BN_bin2bn((u_char *)ep->pkt, vallen, NULL)) == NULL) {
+ msyslog(LOG_ERR, "crypto_bob: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return (XEVNT_ERR);
+@@ -2136,7 +2166,7 @@ crypto_bob(
+ */
+ bctx = BN_CTX_new(); bk = BN_new(); bn = BN_new();
+ sdsa = DSA_SIG_new();
+- BN_rand(bk, len * 8, -1, 1); /* k */
++ BN_rand(bk, vallen * 8, -1, 1); /* k */
+ BN_mod_mul(bn, dsa->priv_key, r, dsa->q, bctx); /* b r mod q */
+ BN_add(bn, bn, bk);
+ BN_mod(bn, bn, dsa->q, bctx); /* k + b r mod q */
+@@ -2155,30 +2185,37 @@ crypto_bob(
+ * Encode the values in ASN.1 and sign. The filestamp is from
+ * the local file.
+ */
+- len = i2d_DSA_SIG(sdsa, NULL);
+- if (len == 0) {
++ vallen = i2d_DSA_SIG(sdsa, NULL);
++ if (vallen == 0) {
+ msyslog(LOG_ERR, "crypto_bob: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ DSA_SIG_free(sdsa);
+ return (XEVNT_ERR);
+ }
++ if (vallen > MAX_VALLEN) {
++ msyslog(LOG_ERR, "crypto_bob: signature is too big: %d",
++ vallen);
++ DSA_SIG_free(sdsa);
++ return (XEVNT_LEN);
++ }
+ memset(vp, 0, sizeof(struct value));
+ tstamp = crypto_time();
+ vp->tstamp = htonl(tstamp);
+ vp->fstamp = htonl(iffkey_info->fstamp);
+- vp->vallen = htonl(len);
+- ptr = emalloc(len);
++ vp->vallen = htonl(vallen);
++ ptr = emalloc(vallen);
+ vp->ptr = ptr;
+ i2d_DSA_SIG(sdsa, &ptr);
+ DSA_SIG_free(sdsa);
+ if (tstamp == 0)
+ return (XEVNT_OK);
+
++ /* XXX: more validation to make sure the sign fits... */
+ vp->sig = emalloc(sign_siglen);
+ EVP_SignInit(&ctx, sign_digest);
+ EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
+- EVP_SignUpdate(&ctx, vp->ptr, len);
+- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
++ EVP_SignUpdate(&ctx, vp->ptr, vallen);
++ if (EVP_SignFinal(&ctx, vp->sig, &vallen, sign_pkey))
+ vp->siglen = htonl(sign_siglen);
+ return (XEVNT_OK);
+ }
+diff -up ntp-4.2.6p5/ntpd/ntp_proto.c.cve-2014-9297 ntp-4.2.6p5/ntpd/ntp_proto.c
+--- ntp-4.2.6p5/ntpd/ntp_proto.c.cve-2014-9297 2015-02-04 11:37:44.490673080 +0100
++++ ntp-4.2.6p5/ntpd/ntp_proto.c 2015-02-04 11:47:42.653868627 +0100
+@@ -431,7 +431,7 @@ receive(
+ */
+ authlen = LEN_PKT_NOMAC;
+ has_mac = rbufp->recv_length - authlen;
+- while (has_mac != 0) {
++ while (has_mac > 0) {
+ u_int32 len;
+
+ if (has_mac % 4 != 0 || has_mac < MIN_MAC_LEN) {
+@@ -456,6 +456,14 @@ receive(
+ }
+
+ /*
++ * If has_mac is < 0 we had a malformed packet.
++ */
++ if (has_mac < 0) {
++ sys_badlength++;
++ return; /* bad length */
++ }
++
++ /*
+ * If authentication required, a MAC must be present.
+ */
+ if (restrict_mask & RES_DONTTRUST && has_mac == 0) {
diff --git a/ntp.spec b/ntp.spec
index 57ad0da..2096554 100644
--- a/ntp.spec
+++ b/ntp.spec
@@ -97,6 +97,8 @@ Patch25: ntp-4.2.6p5-cve-2014-9293.patch
Patch26: ntp-4.2.6p5-cve-2014-9295.patch
# ntpbz #2670
Patch27: ntp-4.2.6p5-cve-2014-9296.patch
+# ntpbz #2671
+Patch28: ntp-4.2.6p5-cve-2014-9297.patch
# handle unknown clock types
Patch50: ntpstat-0.2-clksrc.patch
@@ -209,6 +211,7 @@ This package contains NTP documentation in HTML format.
%patch25 -p1 -b .cve-2014-9293
%patch26 -p1 -b .cve-2014-9295
%patch27 -p1 -b .cve-2014-9296
+%patch28 -p1 -b .cve-2014-9297
# ntpstat patches
%patch50 -p1 -b .clksrc
More information about the scm-commits
mailing list