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

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