Blame SOURCES/ntp-4.2.6p5-cve-2015-7691_7692_7702.patch

063937
diff -up ntp-4.2.6p5/ntpd/ntp_crypto.c.cve-2015-7691_7692_7702 ntp-4.2.6p5/ntpd/ntp_crypto.c
063937
--- ntp-4.2.6p5/ntpd/ntp_crypto.c.cve-2015-7691_7692_7702	2015-10-22 13:05:34.696482937 +0200
063937
+++ ntp-4.2.6p5/ntpd/ntp_crypto.c	2015-10-22 13:14:12.473848919 +0200
063937
@@ -170,6 +170,7 @@ static	void	cert_free	(struct cert_info
063937
 static	struct pkey_info *crypto_key (char *, char *, sockaddr_u *);
063937
 static	void	bighash		(BIGNUM *, BIGNUM *);
063937
 static	struct cert_info *crypto_cert (char *);
063937
+static	u_int	exten_payload_size(const struct exten *);
063937
 
063937
 #ifdef SYS_WINNT
063937
 int
063937
@@ -389,7 +390,7 @@ crypto_recv(
063937
 	struct autokey *ap, *bp; /* autokey pointer */
063937
 	struct exten *ep, *fp;	/* extension pointers */
063937
 	struct cert_info *xinfo; /* certificate info pointer */
063937
-	int	has_mac;	/* length of MAC field */
063937
+	int	macbytes;	/* length of MAC field, signed by intention */
063937
 	int	authlen;	/* offset of MAC field */
063937
 	associd_t associd;	/* association ID */
063937
 	tstamp_t tstamp = 0;	/* timestamp */
063937
@@ -417,7 +418,11 @@ crypto_recv(
063937
 	 */
063937
 	authlen = LEN_PKT_NOMAC;
063937
 	hismode = (int)PKT_MODE((&rbufp->recv_pkt)->li_vn_mode);
063937
-	while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) {
063937
+	while ((macbytes = rbufp->recv_length - authlen) > (int)MAX_MAC_LEN) {
063937
+		/* We can be reasonably sure that we can read at least
063937
+		 * the opcode and the size field here. More stringent
063937
+		 * checks follow up shortly.
063937
+		 */
063937
 		pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4;
063937
 		ep = (struct exten *)pkt;
063937
 		code = ntohl(ep->opcode) & 0xffff0000;
063937
@@ -441,6 +446,18 @@ crypto_recv(
063937
 			code |= CRYPTO_ERROR;
063937
 		}
063937
 
063937
+		/* Check if the declared size fits into the remaining
063937
+		 * buffer.
063937
+		 */
063937
+		if (len > macbytes) {
063937
+			DPRINTF(1, ("crypto_recv: possible attack detected, associd %d\n",
063937
+				    associd));
063937
+			return XEVNT_LEN;
063937
+		}
063937
+
063937
+		/* Check if the paylod of the extension fits into the
063937
+		 * declared frame.
063937
+		 */
063937
 		if (len >= VALUE_LEN) {
063937
 			tstamp = ntohl(ep->tstamp);
063937
 			fstamp = ntohl(ep->fstamp);
063937
@@ -1170,9 +1187,8 @@ crypto_xmit(
063937
 	 * choice. 
063937
 	 */
063937
 	case CRYPTO_CERT | CRYPTO_RESP:
063937
-		vallen = ntohl(ep->vallen);	/* Must be <64k */
063937
-		if (vallen == 0 || vallen > MAXHOSTNAME ||
063937
-		    len - VALUE_LEN < vallen) {
063937
+		vallen = exten_payload_size(ep); /* Must be <64k */
063937
+		if (vallen == 0 || vallen >= sizeof(certname) ) {
063937
 			rval = XEVNT_LEN;
063937
 			break;
063937
 		} else {
063937
@@ -2134,8 +2150,7 @@ crypto_bob(
063937
 	tstamp_t tstamp;	/* NTP timestamp */
063937
 	BIGNUM	*bn, *bk, *r;
063937
 	u_char	*ptr;
063937
-	u_int	len;		/* extension field length */
063937
-	u_int	vallen = 0;	/* value length */
063937
+	u_int	len;		/* extension field value length */
063937
 
063937
 	/*
063937
 	 * If the IFF parameters are not valid, something awful
063937
@@ -2150,11 +2165,10 @@ crypto_bob(
063937
 	/*
063937
 	 * Extract r from the challenge.
063937
 	 */
063937
-	vallen = ntohl(ep->vallen);
063937
-	len = ntohl(ep->opcode) & 0x0000ffff;
063937
-	if (vallen == 0 || len < VALUE_LEN || len - VALUE_LEN < vallen)
063937
-		return XEVNT_LEN;
063937
-	if ((r = BN_bin2bn((u_char *)ep->pkt, vallen, NULL)) == NULL) {
063937
+	len = exten_payload_size(ep);
063937
+	if (len == 0 || len > MAX_VALLEN)
063937
+		return (XEVNT_LEN);
063937
+	if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
063937
 		msyslog(LOG_ERR, "crypto_bob: %s",
063937
 		    ERR_error_string(ERR_get_error(), NULL));
063937
 		return (XEVNT_ERR);
063937
@@ -2166,7 +2180,7 @@ crypto_bob(
063937
 	 */
063937
 	bctx = BN_CTX_new(); bk = BN_new(); bn = BN_new();
063937
 	sdsa = DSA_SIG_new();
063937
-	BN_rand(bk, vallen * 8, -1, 1);		/* k */
063937
+	BN_rand(bk, len * 8, -1, 1);		/* k */
063937
 	BN_mod_mul(bn, dsa->priv_key, r, dsa->q, bctx); /* b r mod q */
063937
 	BN_add(bn, bn, bk);
063937
 	BN_mod(bn, bn, dsa->q, bctx);		/* k + b r mod q */
063937
@@ -2185,16 +2199,16 @@ crypto_bob(
063937
 	 * Encode the values in ASN.1 and sign. The filestamp is from
063937
 	 * the local file.
063937
 	 */
063937
-	vallen = i2d_DSA_SIG(sdsa, NULL);
063937
-	if (vallen == 0) {
063937
+	len = i2d_DSA_SIG(sdsa, NULL);
063937
+	if (len == 0) {
063937
 		msyslog(LOG_ERR, "crypto_bob: %s",
063937
 		    ERR_error_string(ERR_get_error(), NULL));
063937
 		DSA_SIG_free(sdsa);
063937
 		return (XEVNT_ERR);
063937
 	}
063937
-	if (vallen > MAX_VALLEN) {
063937
-		msyslog(LOG_ERR, "crypto_bob: signature is too big: %d",
063937
-		    vallen);
063937
+	if (len > MAX_VALLEN) {
063937
+		msyslog(LOG_ERR, "crypto_bob: signature is too big: %u",
063937
+		    len);
063937
 		DSA_SIG_free(sdsa);
063937
 		return (XEVNT_LEN);
063937
 	}
063937
@@ -2202,8 +2216,8 @@ crypto_bob(
063937
 	tstamp = crypto_time();
063937
 	vp->tstamp = htonl(tstamp);
063937
 	vp->fstamp = htonl(iffkey_info->fstamp);
063937
-	vp->vallen = htonl(vallen);
063937
-	ptr = emalloc(vallen);
063937
+	vp->vallen = htonl(len);
063937
+	ptr = emalloc(len);
063937
 	vp->ptr = ptr;
063937
 	i2d_DSA_SIG(sdsa, &ptr);
063937
 	DSA_SIG_free(sdsa);
063937
@@ -2214,9 +2228,9 @@ crypto_bob(
063937
 	vp->sig = emalloc(sign_siglen);
063937
 	EVP_SignInit(&ctx, sign_digest);
063937
 	EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
063937
-	EVP_SignUpdate(&ctx, vp->ptr, vallen);
063937
-	if (EVP_SignFinal(&ctx, vp->sig, &vallen, sign_pkey))
063937
-		vp->siglen = htonl(sign_siglen);
063937
+	EVP_SignUpdate(&ctx, vp->ptr, len);
063937
+	if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
063937
+		vp->siglen = htonl(len);
063937
 	return (XEVNT_OK);
063937
 }
063937
 
063937
@@ -2462,7 +2476,9 @@ crypto_bob2(
063937
 	/*
063937
 	 * Extract r from the challenge.
063937
 	 */
063937
-	len = ntohl(ep->vallen);
063937
+	len = exten_payload_size(ep);
063937
+	if (len == 0 || len > MAX_VALLEN)
063937
+		return (XEVNT_LEN);
063937
 	if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
063937
 		msyslog(LOG_ERR, "crypto_bob2: %s",
063937
 		    ERR_error_string(ERR_get_error(), NULL));
063937
@@ -2787,7 +2803,9 @@ crypto_bob3(
063937
 	/*
063937
 	 * Extract r from the challenge.
063937
 	 */
063937
-	len = ntohl(ep->vallen);
063937
+	len = exten_payload_size(ep);
063937
+	if (len == 0 || len > MAX_VALLEN)
063937
+		return (XEVNT_LEN);
063937
 	if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
063937
 		msyslog(LOG_ERR, "crypto_bob3: %s",
063937
 		    ERR_error_string(ERR_get_error(), NULL));
063937
@@ -3002,8 +3020,11 @@ cert_sign(
063937
 	if (tstamp == 0)
063937
 		return (XEVNT_TSP);
063937
 
063937
+	len = exten_payload_size(ep);
063937
+	if (len == 0 || len > MAX_VALLEN)
063937
+		return (XEVNT_LEN);
063937
 	ptr = (u_char *)ep->pkt;
063937
-	if ((req = d2i_X509(NULL, &ptr, ntohl(ep->vallen))) == NULL) {
063937
+	if ((req = d2i_X509(NULL, &ptr, len)) == NULL) {
063937
 		msyslog(LOG_ERR, "cert_sign: %s",
063937
 		    ERR_error_string(ERR_get_error(), NULL));
063937
 		return (XEVNT_CRT);
063937
@@ -3968,6 +3989,36 @@ crypto_config(
063937
 		break;
063937
 	}
063937
 }
063937
+
063937
+/*
063937
+ * Get payload size (internal value length) of an extension packet. If
063937
+ * the inner value length does not match the outer packet length (that
063937
+ * is, the value would end behind the frame given by the opcode/size
063937
+ * field) the function will efectively return UINT_MAX. If the frame is
063937
+ * too short to holda variable-sized value, the return value is zero.
063937
+ */
063937
+static u_int
063937
+exten_payload_size(
063937
+	const struct exten * ep)
063937
+{
063937
+	typedef const u_char *BPTR;
063937
+	
063937
+	size_t extn_size;
063937
+	size_t data_size;
063937
+	size_t head_size;
063937
+
063937
+	data_size = 0;
063937
+	if (NULL != ep) {
063937
+		head_size = (BPTR)(&ep->vallen + 1) - (BPTR)ep;
063937
+		extn_size = (uint16_t)(ntohl(ep->opcode) & 0x0000ffff);
063937
+		if (extn_size >= head_size) {
063937
+			data_size = (uint32_t)ntohl(ep->vallen);
063937
+			if (data_size > extn_size - head_size)
063937
+				data_size = ~(size_t)0u;
063937
+		}
063937
+	}
063937
+	return (u_int)data_size;
063937
+}
063937
 # else
063937
 int ntp_crypto_bs_pubkey;
063937
 # endif /* OPENSSL */